From 5d2bddcd0654b9f1ad548799e6828780a30b506c Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Mon, 22 May 2006 11:43:45 -0500 Subject: [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 --- src/H5Edefin.h | 8 +- src/H5Einit.h | 24 +- src/H5Epubgen.h | 12 +- src/H5Eterm.h | 8 +- src/H5FS.c | 1031 +++++++++++++++++++++++++++++++---------- src/H5FSprivate.h | 41 +- src/H5Fprivate.h | 4 + src/H5HF.c | 68 ++- src/H5HFcache.c | 3 +- src/H5HFdbg.c | 2 +- src/H5HFdblock.c | 75 ++- src/H5HFhdr.c | 51 +- src/H5HFiblock.c | 164 ++----- src/H5HFint.c | 141 +++++- src/H5HFiter.c | 2 +- src/H5HFpkg.h | 50 +- src/H5HFprivate.h | 1 + src/H5HFsection.c | 717 ++++++++++++++++++++++++---- src/H5HFspace.c | 55 ++- src/H5HFtest.c | 95 +++- src/H5err.txt | 9 +- test/fheap.c | 1333 +++++++++++++++++++++++++++++++++++++++++++++++------ 22 files changed, 3220 insertions(+), 674 deletions(-) diff --git a/src/H5Edefin.h b/src/H5Edefin.h index f5bcbcf..d10ec5f 100644 --- a/src/H5Edefin.h +++ b/src/H5Edefin.h @@ -46,7 +46,7 @@ hid_t H5E_TST_g = FAIL; /* Ternary Search Trees */ hid_t H5E_ARGS_g = FAIL; /* Invalid arguments to routine */ hid_t H5E_ERROR_g = FAIL; /* Error API */ hid_t H5E_PLINE_g = FAIL; /* Data filters */ -hid_t H5E_FSPACE_g = FAIL; /* File Free Space */ +hid_t H5E_FSPACE_g = FAIL; /* Free Space Manager */ hid_t H5E_CACHE_g = FAIL; /* Object cache */ /* Minor error IDs */ @@ -85,6 +85,11 @@ hid_t H5E_CANTGET_g = FAIL; /* Can't get value */ hid_t H5E_CANTSET_g = FAIL; /* Can't set value */ hid_t H5E_DUPCLASS_g = FAIL; /* Duplicate class name in parent class */ +/* Free space errors */ +hid_t H5E_CANTMERGE_g = FAIL; /* Can't merge objects */ +hid_t H5E_CANTREVIVE_g = FAIL; /* Can't revive object */ +hid_t H5E_CANTSHRINK_g = FAIL; /* Can't shrink container */ + /* Object header related errors */ hid_t H5E_LINKCOUNT_g = FAIL; /* Bad object header link count */ hid_t H5E_VERSION_g = FAIL; /* Wrong version number */ @@ -174,6 +179,7 @@ hid_t H5E_CANTSWAP_g = FAIL; /* Unable to swap records */ hid_t H5E_CANTINSERT_g = FAIL; /* Unable to insert object */ hid_t H5E_CANTLIST_g = FAIL; /* Unable to list node */ hid_t H5E_CANTMODIFY_g = FAIL; /* Unable to modify record */ +hid_t H5E_CANTREMOVE_g = FAIL; /* Unable to remove object */ /* Argument errors */ hid_t H5E_UNINITIALIZED_g = FAIL; /* Information is uinitialized */ diff --git a/src/H5Einit.h b/src/H5Einit.h index 72d581c..c6909d2 100644 --- a/src/H5Einit.h +++ b/src/H5Einit.h @@ -154,7 +154,7 @@ if((msg = H5E_create_msg(cls, H5E_MAJOR, "Data filters"))==NULL) if((H5E_PLINE_g = H5I_register(H5I_ERROR_MSG, msg))<0) HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") assert(H5E_FSPACE_g==(-1)); -if((msg = H5E_create_msg(cls, H5E_MAJOR, "File Free Space"))==NULL) +if((msg = H5E_create_msg(cls, H5E_MAJOR, "Free Space Manager"))==NULL) HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") if((H5E_FSPACE_g = H5I_register(H5I_ERROR_MSG, msg))<0) HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") @@ -299,6 +299,23 @@ if((msg = H5E_create_msg(cls, H5E_MINOR, "Duplicate class name in parent class") if((H5E_DUPCLASS_g = H5I_register(H5I_ERROR_MSG, msg))<0) HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +/* Free space errors */ +assert(H5E_CANTMERGE_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't merge objects"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_CANTMERGE_g = H5I_register(H5I_ERROR_MSG, msg))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +assert(H5E_CANTREVIVE_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't revive object"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_CANTREVIVE_g = H5I_register(H5I_ERROR_MSG, msg))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +assert(H5E_CANTSHRINK_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't shrink container"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_CANTSHRINK_g = H5I_register(H5I_ERROR_MSG, msg))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") + /* Object header related errors */ assert(H5E_LINKCOUNT_g==(-1)); if((msg = H5E_create_msg(cls, H5E_MINOR, "Bad object header link count"))==NULL) @@ -660,6 +677,11 @@ if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to modify record"))==NULL) HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") if((H5E_CANTMODIFY_g = H5I_register(H5I_ERROR_MSG, msg))<0) HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +assert(H5E_CANTREMOVE_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to remove object"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_CANTREMOVE_g = H5I_register(H5I_ERROR_MSG, msg))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") /* Argument errors */ assert(H5E_UNINITIALIZED_g==(-1)); diff --git a/src/H5Epubgen.h b/src/H5Epubgen.h index 001346f..01ed436 100644 --- a/src/H5Epubgen.h +++ b/src/H5Epubgen.h @@ -77,7 +77,7 @@ H5_DLLVAR hid_t H5E_TST_g; /* Ternary Search Trees */ H5_DLLVAR hid_t H5E_ARGS_g; /* Invalid arguments to routine */ H5_DLLVAR hid_t H5E_ERROR_g; /* Error API */ H5_DLLVAR hid_t H5E_PLINE_g; /* Data filters */ -H5_DLLVAR hid_t H5E_FSPACE_g; /* File Free Space */ +H5_DLLVAR hid_t H5E_FSPACE_g; /* Free Space Manager */ H5_DLLVAR hid_t H5E_CACHE_g; /* Object cache */ /*********************/ @@ -142,6 +142,14 @@ H5_DLLVAR hid_t H5E_CANTGET_g; /* Can't get value */ H5_DLLVAR hid_t H5E_CANTSET_g; /* Can't set value */ H5_DLLVAR hid_t H5E_DUPCLASS_g; /* Duplicate class name in parent class */ +/* Free space errors */ +#define H5E_CANTMERGE (H5OPEN H5E_CANTMERGE_g) +#define H5E_CANTREVIVE (H5OPEN H5E_CANTREVIVE_g) +#define H5E_CANTSHRINK (H5OPEN H5E_CANTSHRINK_g) +H5_DLLVAR hid_t H5E_CANTMERGE_g; /* Can't merge objects */ +H5_DLLVAR hid_t H5E_CANTREVIVE_g; /* Can't revive object */ +H5_DLLVAR hid_t H5E_CANTSHRINK_g; /* Can't shrink container */ + /* Object header related errors */ #define H5E_LINKCOUNT (H5OPEN H5E_LINKCOUNT_g) #define H5E_VERSION (H5OPEN H5E_VERSION_g) @@ -289,6 +297,7 @@ H5_DLLVAR hid_t H5E_CANTCOMPARE_g; /* Can't compare objects */ #define H5E_CANTINSERT (H5OPEN H5E_CANTINSERT_g) #define H5E_CANTLIST (H5OPEN H5E_CANTLIST_g) #define H5E_CANTMODIFY (H5OPEN H5E_CANTMODIFY_g) +#define H5E_CANTREMOVE (H5OPEN H5E_CANTREMOVE_g) H5_DLLVAR hid_t H5E_NOTFOUND_g; /* Object not found */ H5_DLLVAR hid_t H5E_EXISTS_g; /* Object already exists */ H5_DLLVAR hid_t H5E_CANTENCODE_g; /* Unable to encode value */ @@ -299,6 +308,7 @@ H5_DLLVAR hid_t H5E_CANTSWAP_g; /* Unable to swap records */ H5_DLLVAR hid_t H5E_CANTINSERT_g; /* Unable to insert object */ H5_DLLVAR hid_t H5E_CANTLIST_g; /* Unable to list node */ H5_DLLVAR hid_t H5E_CANTMODIFY_g; /* Unable to modify record */ +H5_DLLVAR hid_t H5E_CANTREMOVE_g; /* Unable to remove object */ /* Argument errors */ #define H5E_UNINITIALIZED (H5OPEN H5E_UNINITIALIZED_g) diff --git a/src/H5Eterm.h b/src/H5Eterm.h index 1b28d16..1643db9 100644 --- a/src/H5Eterm.h +++ b/src/H5Eterm.h @@ -87,6 +87,11 @@ H5E_CANTGET_g= H5E_CANTSET_g= H5E_DUPCLASS_g= +/* Free space errors */ +H5E_CANTMERGE_g= +H5E_CANTREVIVE_g= +H5E_CANTSHRINK_g= + /* Object header related errors */ H5E_LINKCOUNT_g= H5E_VERSION_g= @@ -175,7 +180,8 @@ H5E_CANTREDISTRIBUTE_g= H5E_CANTSWAP_g= H5E_CANTINSERT_g= H5E_CANTLIST_g= -H5E_CANTMODIFY_g= +H5E_CANTMODIFY_g= +H5E_CANTREMOVE_g= /* Argument errors */ H5E_UNINITIALIZED_g= diff --git a/src/H5FS.c b/src/H5FS.c index ba8e025..aaa11ee 100644 --- a/src/H5FS.c +++ b/src/H5FS.c @@ -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") diff --git a/src/H5FSprivate.h b/src/H5FSprivate.h index e6d669c..3b9311b 100644 --- a/src/H5FSprivate.h +++ b/src/H5FSprivate.h @@ -38,6 +38,17 @@ /* Library Private Macros */ /**************************/ +/* Flags for H5FS_add() */ +#define H5FS_ADD_DESERIALIZING 0x01 /* Free space is being deserialized + * (for package use only) + */ +#define H5FS_ADD_RETURNED_SPACE 0x02 /* Section was previously allocated + * and is being returned to the + * free space manager (usually + * as a result of freeing an + * object) + */ + /****************************/ /* Library Private Typedefs */ @@ -51,12 +62,23 @@ typedef struct H5FS_section_info_t H5FS_section_info_t; /* Free space section class info */ typedef struct H5FS_section_class_t { - unsigned type; /* Type of free space section */ + /* Class variables */ + const unsigned type; /* Type of free space section */ size_t serial_size; /* Size of serialized form of section */ - herr_t (*init)(struct H5FS_section_class_t *, const void *); /* Routine to initialize class-specific settings */ - herr_t (*serialize)(const H5FS_section_info_t *, uint8_t *); /* Routine to serialize a "live" section into a buffer */ + + /* Class methods */ + herr_t (*init_cls)(struct H5FS_section_class_t *, const void *); /* Routine to initialize class-specific settings */ + + /* Object methods */ + herr_t (*serialize)(const H5FS_section_info_t *, uint8_t *); /* Routine to serialize a "live" section into a buffer */ herr_t (*deserialize)(struct H5FS_section_class_t *cls, const uint8_t *, haddr_t, hsize_t, H5FS_section_info_t **); /* Routine to deserialize a buffer into a "live" section */ + htri_t (*can_merge)(const H5FS_section_info_t *, const H5FS_section_info_t *, + void *); /* Routine to determine if two nodes are mergable */ + herr_t (*merge)(H5FS_section_info_t *, H5FS_section_info_t *, void *); /* Routine to merge two nodes */ + htri_t (*can_shrink)(H5FS_section_info_t *, void *); /* Routine to determine if node can shrink container */ + herr_t (*shrink)(H5FS_section_info_t **, void *); /* Routine to shrink container */ + herr_t (*free)(H5FS_section_info_t *); /* Routine to free node */ herr_t (*debug)(const H5FS_section_info_t *, FILE *, int , int ); /* Routine to dump debugging information about a section */ } H5FS_section_class_t; @@ -105,13 +127,14 @@ H5FL_SEQ_EXTERN(H5FS_section_class_t); /* Library-private Function Prototypes */ /***************************************/ H5_DLL 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); -H5_DLL H5FS_t *H5FS_open(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr, - H5SL_operator_t node_free_op, size_t nclasses, + const H5FS_create_t *fs_create, size_t nclasses, H5FS_section_class_t *classes, const void *cls_init_udata); -H5_DLL herr_t H5FS_add(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *node); -H5_DLL htri_t H5FS_find(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, hsize_t request, H5FS_section_info_t **node); +H5_DLL H5FS_t *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); +H5_DLL herr_t H5FS_add(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, + H5FS_section_info_t *node, unsigned flags, void *op_data); +H5_DLL htri_t H5FS_find(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, + hsize_t request, H5FS_section_info_t **node); H5_DLL herr_t H5FS_iterate(H5FS_t *fspace, H5FS_operator_t op, void *op_data); H5_DLL herr_t H5FS_flush(H5F_t *f, hid_t dxpl_id, unsigned flags); H5_DLL herr_t H5FS_close(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace); diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index bc50cfd..14f43bd 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -90,6 +90,7 @@ typedef struct H5F_t H5F_t; int64_t _n = (n); \ size_t _i; \ uint8_t *_p = (uint8_t*)(p); \ + \ for (_i = 0; _i < sizeof(int64_t); _i++, _n >>= 8) \ *_p++ = (uint8_t)(_n & 0xff); \ for (/*void*/; _i < 8; _i++) \ @@ -101,6 +102,7 @@ typedef struct H5F_t H5F_t; uint64_t _n = (n); \ size_t _i; \ uint8_t *_p = (uint8_t*)(p); \ + \ for (_i = 0; _i < sizeof(uint64_t); _i++, _n >>= 8) \ *_p++ = (uint8_t)(_n & 0xff); \ for (/*void*/; _i < 8; _i++) \ @@ -172,6 +174,7 @@ typedef struct H5F_t H5F_t; # define INT64DECODE(p, n) { \ /* WE DON'T CHECK FOR OVERFLOW! */ \ size_t _i; \ + \ n = 0; \ (p) += 8; \ for (_i = 0; _i < sizeof(int64_t); _i++) \ @@ -182,6 +185,7 @@ typedef struct H5F_t H5F_t; # define UINT64DECODE(p, n) { \ /* WE DON'T CHECK FOR OVERFLOW! */ \ size_t _i; \ + \ n = 0; \ (p) += 8; \ for (_i = 0; _i < sizeof(uint64_t); _i++) \ diff --git a/src/H5HF.c b/src/H5HF.c index ec9ca8a..fcbb9cc 100644 --- a/src/H5HF.c +++ b/src/H5HF.c @@ -376,6 +376,9 @@ HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "'write once' managed blocks not su } /* end else */ done: +#ifdef QAK +HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value); +#endif /* QAK */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF_insert() */ @@ -411,7 +414,7 @@ H5HF_get_obj_len(H5HF_t *fh, const void *_id, size_t *obj_len_p) id += fh->hdr->heap_off_size; /* Retrieve the entry length */ - UINT64DECODE_VAR(id, *obj_len_p, fh->hdr->id_len); + UINT64DECODE_VAR(id, *obj_len_p, fh->hdr->heap_len_size); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5HF_get_obj_len() */ @@ -452,8 +455,7 @@ H5HF_read(H5HF_t *fh, hid_t dxpl_id, const void *_id, void *obj/*out*/) hdr = fh->hdr; /* Decode the object offset within the heap & it's length */ - UINT64DECODE_VAR(id, obj_off, hdr->heap_off_size); - UINT64DECODE_VAR(id, obj_len, hdr->id_len); + H5HF_ID_DECODE(id, hdr, obj_off, obj_len); #ifdef QAK HDfprintf(stderr, "%s: obj_off = %Hu, obj_len = %Zu\n", FUNC, obj_off, obj_len); #endif /* QAK */ @@ -465,7 +467,7 @@ HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "standalone blocks not supported ye else { /* Read object from managed heap blocks */ if(H5HF_man_read(hdr, dxpl_id, obj_off, obj_len, obj) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't read object from fractal heap") + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read object from fractal heap") } /* end else */ done: @@ -474,6 +476,64 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_remove + * + * Purpose: Remove an object from a fractal heap + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 15 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_remove(H5HF_t *fh, hid_t dxpl_id, const void *_id) +{ + const uint8_t *id = (const uint8_t *)_id; /* Object ID */ + hsize_t obj_off; /* Object's offset in heap */ + size_t obj_len; /* Object's length in heap */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5HF_remove, FAIL) + + /* + * Check arguments. + */ + HDassert(fh); + HDassert(fh->hdr); + HDassert(id); + + /* Decode the object offset within the heap & it's length */ +#ifdef QAK +HDfprintf(stderr, "%s: fh->hdr->heap_off_size = %u, fh->hdr->heap_len_size = %u\n", FUNC, (unsigned)fh->hdr->heap_off_size, (unsigned)fh->hdr->heap_len_size); +#endif /* QAK */ + H5HF_ID_DECODE(id, fh->hdr, obj_off, obj_len); +#ifdef QAK +HDfprintf(stderr, "%s: obj_off = %Hu, obj_len = %Zu\n", FUNC, obj_off, obj_len); +#endif /* QAK */ + + /* Sanity check parameters */ + HDassert(obj_off); + HDassert(obj_len); + + /* Check for standalone object */ + if(obj_off & 0) { +HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "standalone blocks not supported yet") + } /* end if */ + else { + /* Remove object from managed heap blocks */ + if(H5HF_man_remove(fh->hdr, dxpl_id, obj_off, obj_len) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove object from fractal heap") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_remove() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_close * * Purpose: Close a fractal heap wrapper diff --git a/src/H5HFcache.c b/src/H5HFcache.c index 1e6c1ed..8b59876 100644 --- a/src/H5HFcache.c +++ b/src/H5HFcache.c @@ -698,12 +698,13 @@ H5HF_cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, HDassert(dblock); if(dblock->cache_info.is_dirty) { - H5HF_hdr_t *hdr; /* Shared fractal heap information */ + H5HF_hdr_t *hdr; /* Shared fractal heap information */ uint8_t *p; /* Pointer into raw data buffer */ /* Get the pointer to the shared heap header */ hdr = dblock->hdr; + HDassert(dblock->blk); p = dblock->blk; /* Magic number */ diff --git a/src/H5HFdbg.c b/src/H5HFdbg.c index 3135590..9748964 100644 --- a/src/H5HFdbg.c +++ b/src/H5HFdbg.c @@ -311,7 +311,7 @@ H5HF_dblock_debug_cb(const H5FS_section_info_t *_sect, void *_udata) /* Calculate the length */ len = end - start; - sprintf(temp_str, "Section #%u:", udata->sect_count); + sprintf(temp_str, "Section #%u:", (unsigned)udata->sect_count); HDfprintf(udata->stream, "%*s%-*s %8Zu, %8Zu\n", udata->indent + 3, "", MAX(0, udata->fwidth - 9), temp_str, start, len); diff --git a/src/H5HFdblock.c b/src/H5HFdblock.c index 8e37137..88c4e90 100644 --- a/src/H5HFdblock.c +++ b/src/H5HFdblock.c @@ -95,7 +95,7 @@ H5HF_man_dblock_create(hid_t dxpl_id, H5HF_hdr_t *hdr, H5HF_indirect_t *par_iblo unsigned par_entry, size_t block_size, hsize_t block_off, haddr_t *addr_p, H5HF_free_section_t **ret_sec_node) { - H5HF_free_section_t *sec_node; /* Pointer to free list section for block */ + H5HF_free_section_t *sec_node; /* Pointer to free space section for block */ H5HF_direct_t *dblock = NULL; /* Pointer to direct block */ size_t free_space; /* Free space in new block */ herr_t ret_value = SUCCEED; /* Return value */ @@ -173,7 +173,7 @@ HDmemset(dblock->blk, 0, dblock->size); /* Pass back the pointer to the section instead of adding it to the free list */ *ret_sec_node = sec_node; else { - /* Add new free space to the global list of space */ + /* Add new free space to the heap's list of space */ if(H5HF_space_add(hdr, dxpl_id, sec_node) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add direct block free space to global list") } /* end else */ @@ -192,6 +192,77 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_man_dblock_destroy + * + * Purpose: Destroy a managed direct block + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 17 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_man_dblock_destroy(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_direct_t *dblock, + haddr_t dblock_addr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_man_dblock_destroy) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(dblock); + + /* Check for root direct block */ + if(hdr->man_dtable.curr_root_rows == 0) { +#ifdef QAK +HDfprintf(stderr, "%s: root direct block\n", FUNC); +#endif /* QAK */ + /* Sanity check */ + HDassert(hdr->man_dtable.table_addr == dblock_addr); + HDassert(hdr->man_dtable.cparam.start_block_size == dblock->size); + + /* Sanity check block iterator */ + HDassert(!H5HF_man_iter_ready(&hdr->next_block)); + + /* Reset header information back to "empty heap" state */ + if(H5HF_hdr_empty(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't make heap empty") + } /* end if */ + else { +#ifdef QAK +HDfprintf(stderr, "%s: root indirect block\n", FUNC); +#endif /* QAK */ + +/* Remove from parent indirect block */ + +/* If this is the last block in the heap, move block iterator backwards */ + +/* Detect the last direct block (of the starting block size) and make it the root direct block */ + +HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "destroying non-root direct block not supported yet") + } /* end else */ + + /* Release direct block's disk space */ + if(H5MF_xfree(hdr->f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, dblock_addr, (hsize_t)dblock->size)<0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") + + /* Remove direct block from metadata cache */ + if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__DELETED_FLAG) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block") + dblock = NULL; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_man_dblock_destroy() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_man_dblock_new * * Purpose: Create a direct block large enough to hold an object of diff --git a/src/H5HFhdr.c b/src/H5HFhdr.c index 664a7e7..a25a11b 100644 --- a/src/H5HFhdr.c +++ b/src/H5HFhdr.c @@ -216,8 +216,9 @@ H5HF_hdr_finish_init(H5HF_hdr_t *hdr) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize doubling table info") /* Set the size of heap IDs */ - hdr->id_len = hdr->heap_off_size + MIN(hdr->man_dtable.max_dir_blk_off_size, - ((H5V_log2_gen((hsize_t)hdr->standalone_size) + 7) / 8)); + hdr->heap_len_size = MIN(hdr->man_dtable.max_dir_blk_off_size, + ((H5V_log2_gen((hsize_t)hdr->standalone_size) + 7) / 8)); + hdr->id_len = hdr->heap_off_size + hdr->heap_len_size; /* Set the free space in direct blocks */ for(u = 0; u < hdr->man_dtable.max_root_rows; u++) { @@ -555,3 +556,49 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF_hdr_inc_alloc() */ + +/*------------------------------------------------------------------------- + * Function: H5HF_hdr_empty + * + * Purpose: Reset heap header to 'empty heap' state + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 17 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_hdr_empty(H5HF_hdr_t *hdr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_hdr_empty) +#ifdef QAK +HDfprintf(stderr, "%s: Reseting heap header to empty\n", FUNC); +#endif /* QAK */ + + /* Sanity check */ + HDassert(hdr); + + /* Reset root pointer information */ + hdr->man_dtable.curr_root_rows = 0; + hdr->man_dtable.table_addr = HADDR_UNDEF; + + /* Shrink heap size */ + hdr->total_size = hdr->std_size; + hdr->man_size = 0; + + /* Reset the free space in direct blocks */ + hdr->total_man_free = 0; + + /* Mark heap header as modified */ + if(H5HF_hdr_dirty(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark header as dirty") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_hdr_empty() */ + diff --git a/src/H5HFiblock.c b/src/H5HFiblock.c index cdffa80..d9462c8 100644 --- a/src/H5HFiblock.c +++ b/src/H5HFiblock.c @@ -444,6 +444,9 @@ HDfprintf(stderr, "%s: acc_row_dblock_free_space = %Zu\n", FUNC, acc_row_dblock_ /* Advance outer loop index */ u += row_entries; } /* end for */ +#ifdef QAK +HDfprintf(stderr, "%s: sect_off = %Zu\n", FUNC, sect_off); +#endif /* QAK */ /* Advance the allocated heap size/new block iterator */ if(H5HF_hdr_inc_alloc(hdr, sect_off, nentries) < 0) @@ -658,7 +661,7 @@ HDfprintf(stderr, "%s: Extending root indirect block\n", FUNC); #ifdef QAK HDfprintf(stderr, "%s: min_nrows = %u, new_nrows = %u\n", FUNC, min_nrows, new_nrows); HDfprintf(stderr, "%s: iblock->nrows = %u\n", FUNC, iblock->nrows); -HDfprintf(stderr, "%s: old_next_entry = %u, iblock->next_entry = %u\n", FUNC, old_next_entry, iblock->next_entry); +HDfprintf(stderr, "%s: new_next_entry = %u\n", FUNC, new_next_entry); #endif /* QAK */ /* Currently, the old block data is "thrown away" after the space is reallocated, @@ -672,7 +675,7 @@ HDfprintf(stderr, "%s: old_next_entry = %u, iblock->next_entry = %u\n", FUNC, ol */ /* Free previous indirect block disk space */ if(H5MF_xfree(hdr->f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, iblock->addr, (hsize_t)iblock->size)<0) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block") + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block") /* Compute size of buffer needed for new indirect block */ iblock->nrows = new_nrows; @@ -680,7 +683,7 @@ HDfprintf(stderr, "%s: old_next_entry = %u, iblock->next_entry = %u\n", FUNC, ol /* Allocate space for the new indirect block on disk */ if(HADDR_UNDEF == (new_addr = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, (hsize_t)iblock->size))) - HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block") + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block") #ifdef QAK HDfprintf(stderr, "%s: new_addr = %a\n", FUNC, new_addr); #endif /* QAK */ @@ -710,9 +713,10 @@ HDfprintf(stderr, "%s: new_addr = %a\n", FUNC, new_addr); if(H5HF_iblock_dirty(iblock) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty") - /* Move object in cache */ - if(H5AC_rename(hdr->f, H5AC_FHEAP_IBLOCK, iblock->addr, new_addr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTSPLIT, FAIL, "unable to move fractal heap root indirect block") + /* Move object in cache, if it actually was relocated */ + if(H5F_addr_ne(iblock->addr, new_addr)) + if(H5AC_rename(hdr->f, H5AC_FHEAP_IBLOCK, iblock->addr, new_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSPLIT, FAIL, "unable to move fractal heap root indirect block") /* Update other shared header info */ hdr->man_dtable.curr_root_rows = new_nrows; @@ -731,11 +735,22 @@ HDfprintf(stderr, "%s: acc_dblock_free = %Hu\n", FUNC, acc_dblock_free); if(H5HF_hdr_dirty(hdr) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark header as dirty") +/* XXX: Sanity check until can rename pinned entry in metadata cache */ +#ifndef NDEBUG +{ +H5HF_indirect_t *old_root_iblock = iblock; +#endif /* NDEBUG */ + /* Lock root indirect block (again) */ if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, new_addr, hdr->man_dtable.curr_root_rows, NULL, 0, H5AC_WRITE))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") iblock->addr = new_addr; +#ifndef NDEBUG + HDassert(old_root_iblock == iblock); +} +#endif /* NDEBUG */ + /* Update the indirect block pointer in iterator */ /* (pins the indirect block after it's in the new location) */ if(H5HF_man_iter_update_iblock(&hdr->next_block, iblock) < 0) @@ -830,7 +845,7 @@ HDfprintf(stderr, "%s: next_row = %u\n", FUNC, next_row); HDfprintf(stderr, "%s: next_entry = %u\n", FUNC, next_entry); #endif /* QAK */ /* Check for skipping over blocks in the current block */ - if(min_dblock_row > next_row) { + if(min_dblock_row > next_row && next_row < iblock->nrows) { unsigned min_entry; /* Min entry for direct block requested */ unsigned skip_entries; /* Number of entries to skip in the current block */ @@ -853,6 +868,11 @@ HDfprintf(stderr, "%s: min_entry = %u, skip_entries = %u\n", FUNC, min_entry, sk &next_entry, &iblock) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, NULL, "unable to retrieve current block iterator location") } /* end if */ + + do { + /* Reset conditions for leaving loop */ + walked_up = walked_down = FALSE; + #ifdef QAK HDfprintf(stderr, "%s: Check 2.0\n", FUNC); HDfprintf(stderr, "%s: iblock = %p\n", FUNC, iblock); @@ -861,10 +881,6 @@ HDfprintf(stderr, "%s: next_row = %u\n", FUNC, next_row); HDfprintf(stderr, "%s: next_entry = %u\n", FUNC, next_entry); #endif /* QAK */ - do { - /* Reset conditions for leaving loop */ - walked_up = walked_down = FALSE; - /* Check for walking off end of indirect block */ /* (walk up iterator) */ while(next_row >= iblock->nrows) { @@ -899,7 +915,7 @@ HDfprintf(stderr, "%s: Walking up a level\n", FUNC); /* Indicate that we walked up */ walked_up = TRUE; - } /* end if */ + } /* end while */ #ifdef QAK HDfprintf(stderr, "%s: Check 3.0\n", FUNC); HDfprintf(stderr, "%s: iblock = %p\n", FUNC, iblock); @@ -946,6 +962,8 @@ HDfprintf(stderr, "%s: Skipping indirect block row that is too small\n", FUNC); child_rows_needed = (H5V_log2_of2(min_dblock_size) - H5V_log2_of2(hdr->man_dtable.cparam.start_block_size)) + 2; HDassert(child_rows_needed > child_nrows); child_entry = (next_row + (child_rows_needed - child_nrows)) * hdr->man_dtable.cparam.width; + if(child_entry > (iblock->nrows * hdr->man_dtable.cparam.width)) + child_entry = iblock->nrows * hdr->man_dtable.cparam.width; #ifdef QAK HDfprintf(stderr, "%s: child_rows_needed = %u\n", FUNC, child_rows_needed); HDfprintf(stderr, "%s: child_entry = %u\n", FUNC, child_entry); @@ -1035,7 +1053,7 @@ HDfprintf(stderr, "%s: Skipping rows in new child indirect block - new_entry = % /* Indicate that we walked down */ walked_down = TRUE; - } /* end while */ + } /* end if */ } while(walked_down || walked_up); } /* end else */ @@ -1074,78 +1092,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5HF_man_iblock_alloc_single - * - * Purpose: Update the memory information for a 'single' free section - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * May 8 2006 - * - *------------------------------------------------------------------------- - */ -herr_t -H5HF_man_iblock_alloc_single(H5HF_hdr_t *hdr, hid_t dxpl_id, - H5HF_free_section_t *sec_node) -{ - H5HF_indirect_t *sec_iblock; /* Pointer to section indirect block */ - unsigned sec_entry; /* Entry within section indirect block */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5HF_man_iblock_alloc_single) - - /* - * Check arguments. - */ - HDassert(hdr); - HDassert(sec_node); - HDassert(sec_node->sect_info.state == H5FS_SECT_SERIALIZED); - - /* Check for root direct block */ - if(hdr->man_dtable.curr_root_rows == 0) { - /* Set the information for the section */ - sec_node->u.single.parent = NULL; - sec_node->u.single.par_entry = 0; - - /* Set direct block info */ - HDassert(H5F_addr_defined(hdr->man_dtable.table_addr)); - sec_node->u.single.dblock_addr = hdr->man_dtable.table_addr; - sec_node->u.single.dblock_size = hdr->man_dtable.cparam.start_block_size; - } /* end if */ - else { - /* Look up indirect block containing direct blocks for range */ - if(H5HF_man_locate_block(hdr, dxpl_id, sec_node->sect_info.addr, FALSE, &sec_iblock, &sec_entry, H5AC_READ) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") - - /* Increment reference count on indirect block that free section is in */ - if(H5HF_iblock_incr(sec_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") - - /* Set the information for the section */ - sec_node->u.single.parent = sec_iblock; - sec_node->u.single.par_entry = sec_entry; - - /* Set direct block info */ - sec_node->u.single.dblock_addr = sec_iblock->ents[sec_entry].addr; - sec_node->u.single.dblock_size = hdr->man_dtable.row_block_size[sec_entry / hdr->man_dtable.cparam.width]; - - /* Unlock indirect block */ - if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, sec_iblock->addr, sec_iblock, H5AC__NO_FLAGS_SET) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") - sec_iblock = NULL; - } /* end else */ - - /* Section is "live" now */ - sec_node->sect_info.state = H5FS_SECT_LIVE; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_man_iblock_alloc_single() */ - - -/*------------------------------------------------------------------------- * Function: H5HF_man_iblock_alloc_range * * Purpose: Allocate a "single" section for an object, out of a "range" @@ -1182,27 +1128,9 @@ H5HF_man_iblock_alloc_range(H5HF_hdr_t *hdr, hid_t dxpl_id, /* Check for serialized section */ if(old_sec_node->sect_info.state == H5FS_SECT_SERIALIZED) { - H5HF_indirect_t *sec_iblock; /* Pointer to section indirect block */ - unsigned sec_entry; /* Entry within section indirect block */ - - /* Look up indirect block containing direct blocks for range */ - if(H5HF_man_locate_block(hdr, dxpl_id, old_sec_node->sect_info.addr, FALSE, &sec_iblock, &sec_entry, H5AC_READ) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") - - /* Increment reference count on indirect block that free section is in */ - if(H5HF_iblock_incr(sec_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") - - /* Set the pointer to the section's indirect block */ - old_sec_node->u.range.iblock = sec_iblock; - - /* Unlock indirect block */ - if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, sec_iblock->addr, sec_iblock, H5AC__NO_FLAGS_SET) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") - sec_iblock = NULL; - - /* Section is "live" now */ - old_sec_node->sect_info.state = H5FS_SECT_LIVE; + /* Revive range section */ + if(H5HF_sect_range_revive(hdr, dxpl_id, old_sec_node) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTREVIVE, FAIL, "can't revive range section") } /* end if */ /* Compute info about range */ @@ -1309,27 +1237,9 @@ H5HF_man_iblock_alloc_indirect(H5HF_hdr_t *hdr, hid_t dxpl_id, /* Check for serialized section */ if(old_sec_node->sect_info.state == H5FS_SECT_SERIALIZED) { - H5HF_indirect_t *sec_iblock; /* Pointer to section indirect block */ - unsigned sec_entry; /* Entry within section indirect block */ - - /* Look up indirect block containing indirect blocks for section */ - if(H5HF_man_locate_block(hdr, dxpl_id, old_sec_node->sect_info.addr, TRUE, &sec_iblock, &sec_entry, H5AC_READ) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") - - /* Increment reference count on indirect block that free section is in */ - if(H5HF_iblock_incr(sec_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") - - /* Set the pointer to the section's indirect block */ - old_sec_node->u.indirect.iblock = sec_iblock; - - /* Unlock indirect block */ - if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, sec_iblock->addr, sec_iblock, H5AC__NO_FLAGS_SET) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") - sec_iblock = NULL; - - /* Section is "live" now */ - old_sec_node->sect_info.state = H5FS_SECT_LIVE; + /* Revive indirect section */ + if(H5HF_sect_indirect_revive(hdr, dxpl_id, old_sec_node) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTREVIVE, FAIL, "can't revive indirect section") } /* end if */ /* Compute info about range */ diff --git a/src/H5HFint.c b/src/H5HFint.c index 5b49c6d..4148d14 100644 --- a/src/H5HFint.c +++ b/src/H5HFint.c @@ -327,8 +327,8 @@ HDfprintf(stderr, "%s: sec_node->u.range.num_entries = %u\n", FUNC, sec_node->u. /* Check for serialized 'single' section */ if(sec_node->sect_info.state == H5FS_SECT_SERIALIZED) { - if(H5HF_man_iblock_alloc_single(hdr, dxpl_id, sec_node) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize direct block for single free section") + if(H5HF_sect_single_revive(hdr, dxpl_id, sec_node) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section") } /* end if */ HDassert(sec_node->sect_info.state == H5FS_SECT_LIVE); @@ -412,8 +412,7 @@ HDfprintf(stderr, "%s: blk_off = %Zu\n", FUNC, blk_off); #ifdef QAK HDfprintf(stderr, "%s: dblock->block_off = %Hu\n", FUNC, dblock->block_off); #endif /* QAK */ - UINT64ENCODE_VAR(id, (dblock->block_off + blk_off), hdr->heap_off_size); - UINT64ENCODE_VAR(id, obj_size, hdr->id_len); + H5HF_ID_ENCODE(id, hdr, (dblock->block_off + blk_off), obj_size); } /* end if */ else { HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "inserting within mapped managed blocks not supported yet") @@ -468,6 +467,7 @@ HDfprintf(stderr, "%s: obj_off = %Hu, obj_len = %Zu\n", FUNC, obj_off, obj_len); */ HDassert(hdr); HDassert(obj_off > 0); + HDassert(obj_len > 0); HDassert(obj); /* Check for root direct block */ @@ -527,3 +527,136 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF_man_read() */ + +/*------------------------------------------------------------------------- + * Function: H5HF_man_remove + * + * Purpose: Remove an object from a managed heap + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 15 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_man_remove(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t obj_off, size_t obj_len) +{ + H5HF_free_section_t *sec_node; /* Pointer to free space section for block */ + H5HF_direct_t *dblock; /* Pointer to direct block to query */ + haddr_t dblock_addr; /* Direct block address */ + size_t dblock_size; /* Direct block size */ + size_t blk_off; /* Offset of object in block */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_man_remove) +#ifdef QAK +HDfprintf(stderr, "%s: obj_off = %Hu, obj_len = %Zu\n", FUNC, obj_off, obj_len); +#endif /* QAK */ + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(obj_off > 0); + HDassert(obj_len > 0); + + /* Check for bad offset or length */ + if(obj_off > hdr->man_alloc_size) + HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object offset too large") + if(obj_len > hdr->man_dtable.cparam.start_block_size) + HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object size too large for direct block") + if(obj_len > hdr->standalone_size) + HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object should be standalone") + + /* Check for root direct block */ + if(hdr->man_dtable.curr_root_rows == 0) { +#ifdef QAK +HDfprintf(stderr, "%s: direct root block\n", FUNC); +#endif /* QAK */ + /* Set direct block info */ + dblock_addr = hdr->man_dtable.table_addr; + dblock_size = hdr->man_dtable.cparam.start_block_size; + + /* Lock direct block */ + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, NULL, 0, H5AC_WRITE))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block") + } /* end if */ + else { + H5HF_indirect_t *iblock; /* Pointer to indirect block */ + unsigned entry; /* Entry of block */ + +#ifdef QAK +HDfprintf(stderr, "%s: indirect root block\n", FUNC); +#endif /* QAK */ + /* Look up indirect block containing direct block */ + if(H5HF_man_locate_block(hdr, dxpl_id, obj_off, FALSE, &iblock, &entry, H5AC_WRITE) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") +#ifdef QAK +HDfprintf(stderr, "%s: entry address = %a\n", FUNC, iblock->ents[entry].addr); +#endif /* QAK */ + + /* Set direct block info */ + dblock_addr = iblock->ents[entry].addr; + dblock_size = hdr->man_dtable.row_block_size[entry / hdr->man_dtable.cparam.width]; + + /* Lock direct block */ + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, iblock, entry, H5AC_WRITE))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block") + + /* Unlock indirect block */ + if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, iblock->addr, iblock, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") + iblock = NULL; + } /* end else */ +#ifdef QAK +HDfprintf(stderr, "%s: dblock_addr = %a, dblock_size = %Zu\n", FUNC, dblock_addr, dblock_size); +#endif /* QAK */ + + /* Compute offset of object within block */ + HDassert((obj_off - dblock->block_off) < (hsize_t)dblock_size); + blk_off = (size_t)(obj_off - dblock->block_off); +#ifdef QAK +HDfprintf(stderr, "%s: blk_off = %Zu\n", FUNC, blk_off); +#endif /* QAK */ + + /* Create free space section node */ + if(NULL == (sec_node = H5FL_MALLOC(H5HF_free_section_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list section") + + /* Set section's information */ + sec_node->sect_info.addr = obj_off; + sec_node->sect_info.size = obj_len; + sec_node->sect_info.cls = &hdr->sect_cls[H5FS_SECT_FHEAP_SINGLE]; + sec_node->sect_info.state = H5FS_SECT_LIVE; + sec_node->u.single.parent = dblock->parent; + if(dblock->parent) { + if(H5HF_iblock_incr(dblock->parent) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") + } /* end if */ + sec_node->u.single.par_entry = dblock->par_entry; + sec_node->u.single.dblock_addr = dblock_addr; + sec_node->u.single.dblock_size = dblock_size; + + /* Unlock direct block */ + if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block") + dblock = NULL; + + /* Return free space to the heap's list of space */ + if(H5HF_space_return(hdr, dxpl_id, sec_node) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add direct block free space to global list") + + /* Update statistics about heap */ + hdr->nobjs--; + + /* Mark heap header as modified */ + if(H5HF_hdr_dirty(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_man_remove() */ + diff --git a/src/H5HFiter.c b/src/H5HFiter.c index 31fd6c8..abc592a 100644 --- a/src/H5HFiter.c +++ b/src/H5HFiter.c @@ -436,7 +436,7 @@ H5HF_man_iter_next(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter, unsigned nentries) biter->curr->row = biter->curr->entry / hdr->man_dtable.cparam.width; biter->curr->col = biter->curr->entry % hdr->man_dtable.cparam.width; } /* end else */ - HDassert(biter->curr->row <= biter->curr->context->nrows); +/* HDassert(biter->curr->row <= biter->curr->context->nrows); */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5HF_man_iter_next() */ diff --git a/src/H5HFpkg.h b/src/H5HFpkg.h index 96e5b57..1927445 100644 --- a/src/H5HFpkg.h +++ b/src/H5HFpkg.h @@ -113,6 +113,16 @@ #define H5HF_SIZEOF_OFFSET_BITS(b) (((b) + 7) / 8) #define H5HF_SIZEOF_OFFSET_LEN(l) H5HF_SIZEOF_OFFSET_BITS(H5V_log2_of2((unsigned)(l))) +/* Encode a heap ID */ +#define H5HF_ID_ENCODE(i, h, o, l) \ + UINT64ENCODE_VAR((i), (o), (h)->heap_off_size); \ + UINT64ENCODE_VAR((i), (l), (h)->heap_len_size) + +/* Decode a heap ID */ +#define H5HF_ID_DECODE(i, h, o, l) \ + UINT64DECODE_VAR((i), (o), (h)->heap_off_size); \ + UINT64DECODE_VAR((i), (l), (h)->heap_len_size) + /* Free space section types for fractal heap */ /* (values stored in free space data structures in file) */ #define H5FS_SECT_FHEAP_SINGLE 0 /* Section is actual bytes in a direct block */ @@ -236,7 +246,7 @@ typedef struct H5HF_hdr_t { H5F_t *f; /* Pointer to file for heap */ size_t sizeof_size; /* Size of file sizes */ size_t sizeof_addr; /* Size of file addresses */ - size_t id_len; /* Size of heap IDs */ + size_t id_len; /* Size of heap IDs (in bytes) */ size_t nsect_classes; /* Number of free space section classes */ H5FS_section_class_t *sect_cls; /* Array of free space section classes */ H5FS_t *fspace; /* Free space list for objects in heap */ @@ -254,6 +264,7 @@ typedef struct H5HF_hdr_t { /* Information derived from user parameters (not stored in header) */ unsigned char heap_off_size; /* Size of heap offsets (in bytes) */ + unsigned char heap_len_size; /* Size of heap ID lengths (in bytes) */ hbool_t debug_objs; /* Is the heap storing objects in 'debug' format */ hbool_t have_io_filter; /* Does the heap have I/O filters for the direct blocks? */ hbool_t write_once; /* Is heap being written in "write once" mode? */ @@ -325,6 +336,13 @@ typedef struct H5HF_parent_t { unsigned entry; /* Location of block in parent's entry table */ } H5HF_parent_t; +/* User data for free space section 'add' callback */ +typedef struct { + H5HF_hdr_t *hdr; /* Fractal heap header */ + hid_t dxpl_id; /* DXPL ID for operation */ + H5HF_direct_t *dblock; /* Direct block */ +} H5HF_add_ud1_t; + /*****************************/ /* Package Private Variables */ /*****************************/ @@ -390,6 +408,7 @@ H5_DLL herr_t H5HF_hdr_adj_free(H5HF_hdr_t *hdr, ssize_t amt); H5_DLL herr_t H5HF_hdr_extend_heap(H5HF_hdr_t *hdr, hsize_t new_size, hsize_t extra_free); H5_DLL herr_t H5HF_hdr_inc_alloc(H5HF_hdr_t *hdr, hsize_t new_alloc_size, unsigned nentries); +H5_DLL herr_t H5HF_hdr_empty(H5HF_hdr_t *hdr); /* Indirect block routines */ H5_DLL herr_t H5HF_iblock_incr(H5HF_indirect_t *iblock); @@ -397,8 +416,6 @@ H5_DLL herr_t H5HF_iblock_decr(H5HF_indirect_t *iblock); H5_DLL herr_t H5HF_iblock_dirty(H5HF_indirect_t *iblock); H5_DLL H5HF_indirect_t * H5HF_man_iblock_place_dblock(H5HF_hdr_t *fh, hid_t dxpl_id, size_t min_dblock_size, size_t *entry_p, size_t *dblock_size); -H5_DLL herr_t H5HF_man_iblock_alloc_single(H5HF_hdr_t *hdr, hid_t dxpl_id, - H5HF_free_section_t *sec_node); H5_DLL herr_t H5HF_man_iblock_alloc_range(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t **sec_node); H5_DLL herr_t H5HF_man_iblock_alloc_indirect(H5HF_hdr_t *hdr, hid_t dxpl_id, @@ -413,14 +430,14 @@ H5_DLL herr_t H5HF_man_dblock_new(H5HF_hdr_t *fh, hid_t dxpl_id, size_t request) H5_DLL herr_t H5HF_man_dblock_create(hid_t dxpl_id, H5HF_hdr_t *hdr, H5HF_indirect_t *par_iblock, unsigned par_entry, size_t block_size, hsize_t block_off, haddr_t *addr_p, H5HF_free_section_t **ret_sec_node); +H5_DLL herr_t H5HF_man_dblock_destroy(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_direct_t *dblock, haddr_t dblock_addr); H5_DLL H5HF_direct_t *H5HF_man_dblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t dblock_addr, size_t dblock_size, H5HF_indirect_t *par_iblock, unsigned par_entry, H5AC_protect_t rw); /* Routines for internal operations */ -H5_DLL herr_t H5HF_free_section_free_cb(void *item, void UNUSED *key, - void UNUSED *op_data); H5_DLL herr_t H5HF_man_locate_block(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t obj_off, hbool_t locate_indirect, H5HF_indirect_t **par_iblock, unsigned *par_entry, H5AC_protect_t rw); @@ -431,6 +448,8 @@ H5_DLL herr_t H5HF_man_insert(H5HF_hdr_t *fh, hid_t dxpl_id, void *id); H5_DLL herr_t H5HF_man_read(H5HF_hdr_t *fh, hid_t dxpl_id, hsize_t obj_off, size_t obj_len, void *obj); +H5_DLL herr_t H5HF_man_remove(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t obj_off, + size_t obj_len); /* Metadata cache callbacks */ H5_DLL herr_t H5HF_cache_hdr_dest(H5F_t *f, H5HF_hdr_t *hdr); @@ -470,14 +489,27 @@ H5_DLL hbool_t H5HF_man_iter_ready(H5HF_block_iter_t *biter); H5_DLL herr_t H5HF_space_start(H5HF_hdr_t *hdr, hid_t dxpl_id); H5_DLL htri_t H5HF_space_find(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t request, H5HF_free_section_t **node); -H5_DLL herr_t H5HF_space_add(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *node); +H5_DLL herr_t H5HF_space_add(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *node); +H5_DLL herr_t H5HF_space_return(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *node); H5_DLL herr_t H5HF_space_close(H5HF_hdr_t *hdr, hid_t dxpl_id); +/* Free space section routines */ +H5_DLL herr_t H5HF_sect_single_revive(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect); +H5_DLL herr_t H5HF_sect_range_revive(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect); +H5_DLL herr_t H5HF_sect_indirect_revive(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect); + /* Testing routines */ #ifdef H5HF_TESTING -H5_DLL herr_t H5HF_get_cparam_test(H5HF_t *fh, H5HF_create_t *cparam); -H5_DLL hsize_t H5HF_get_dblock_free_test(H5HF_t *fh, unsigned row); -H5_DLL size_t H5HF_get_dblock_overhead(H5HF_t *fh); +H5_DLL herr_t H5HF_get_cparam_test(const H5HF_t *fh, H5HF_create_t *cparam); +H5_DLL size_t H5HF_get_dblock_overhead(const H5HF_t *fh); +H5_DLL hsize_t H5HF_get_dblock_size_test(const H5HF_t *fh, unsigned row); +H5_DLL hsize_t H5HF_get_dblock_free_test(const H5HF_t *fh, unsigned row); +H5_DLL herr_t H5HF_get_id_off_test(const H5HF_t *fh, const void *id, hsize_t *obj_off); #endif /* H5HF_TESTING */ #endif /* _H5HFpkg_H */ diff --git a/src/H5HFprivate.h b/src/H5HFprivate.h index d6b1e15..bb562de 100644 --- a/src/H5HFprivate.h +++ b/src/H5HFprivate.h @@ -87,6 +87,7 @@ H5_DLL herr_t H5HF_insert(H5HF_t *fh, hid_t dxpl_id, size_t size, H5_DLL herr_t H5HF_get_obj_len(H5HF_t *fh, const void *id, size_t *obj_len_p/*out*/); H5_DLL herr_t H5HF_read(H5HF_t *fh, hid_t dxpl_id, const void *id, void *obj/*out*/); +H5_DLL herr_t H5HF_remove(H5HF_t *fh, hid_t dxpl_id, const void *id); H5_DLL herr_t H5HF_close(H5HF_t *fh, hid_t dxpl_id); /* Debugging routines */ diff --git a/src/H5HFsection.c b/src/H5HFsection.c index 6cbe4cb..f164cdb 100644 --- a/src/H5HFsection.c +++ b/src/H5HFsection.c @@ -50,21 +50,43 @@ /********************/ /* Local Prototypes */ /********************/ + +/* Shared routines */ +static herr_t H5HF_sect_node_alloc(H5FS_section_class_t *sect_cls, + unsigned sect_type, haddr_t sect_addr, hsize_t sect_size, + H5FS_section_info_t **sect); +static herr_t H5HF_sect_node_free(H5HF_free_section_t *sect, + H5HF_indirect_t *parent); + +/* 'single' section callbacks */ static herr_t H5HF_sect_single_deserialize(H5FS_section_class_t *sect_cls, const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size, H5FS_section_info_t **sect); -static herr_t H5HF_sect_range_init(H5FS_section_class_t *cls, const void *udata); +static htri_t H5HF_sect_single_can_merge(const H5FS_section_info_t *sect1, + const H5FS_section_info_t *sect2, void *udata); +static herr_t H5HF_sect_single_merge(H5FS_section_info_t *sect1, + H5FS_section_info_t *sect2, void *udata); +static htri_t H5HF_sect_single_can_shrink(H5FS_section_info_t *sect, void *udata); +static herr_t H5HF_sect_single_shrink(H5FS_section_info_t **sect, void *udata); +static herr_t H5HF_sect_single_free(H5FS_section_info_t *sect); + +/* 'range' section callbacks */ +static herr_t H5HF_sect_range_init_cls(H5FS_section_class_t *cls, const void *udata); static herr_t H5HF_sect_range_serialize(const H5FS_section_info_t *sect, uint8_t *buf); static herr_t H5HF_sect_range_deserialize(H5FS_section_class_t *sect_cls, const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size, H5FS_section_info_t **sect); +static herr_t H5HF_sect_range_free(H5FS_section_info_t *sect); static herr_t H5HF_sect_range_debug(const H5FS_section_info_t *sect, FILE *stream, int indent, int fwidth); -static herr_t H5HF_sect_indirect_init(H5FS_section_class_t *cls, const void *udata); + +/* 'indirect' section callbacks */ +static herr_t H5HF_sect_indirect_init_cls(H5FS_section_class_t *cls, const void *udata); static herr_t H5HF_sect_indirect_serialize(const H5FS_section_info_t *sect, uint8_t *buf); static herr_t H5HF_sect_indirect_deserialize(H5FS_section_class_t *sect_cls, const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size, H5FS_section_info_t **sect); +static herr_t H5HF_sect_indirect_free(H5FS_section_info_t *sect); static herr_t H5HF_sect_indirect_debug(const H5FS_section_info_t *sect, FILE *stream, int indent, int fwidth); @@ -76,32 +98,47 @@ static herr_t H5HF_sect_indirect_debug(const H5FS_section_info_t *sect, /* Class info for "single" free space sections */ /* (No callbacks necessary) */ H5FS_section_class_t H5FS_SECT_CLS_FHEAP_SINGLE[1] = {{ - H5FS_SECT_FHEAP_SINGLE, - 0, - NULL, - NULL, - H5HF_sect_single_deserialize, - NULL, + H5FS_SECT_FHEAP_SINGLE, /* Section type */ + 0, /* Extra serialized size */ + NULL, /* Initialize section class */ + NULL, /* Serialize section */ + H5HF_sect_single_deserialize, /* Deserialize section */ + H5HF_sect_single_can_merge, /* Can sections merge? */ + H5HF_sect_single_merge, /* Merge sections */ + H5HF_sect_single_can_shrink, /* Can section shrink container?*/ + H5HF_sect_single_shrink, /* Shrink container w/section */ + H5HF_sect_single_free, /* Free section */ + NULL, /* Dump debugging for section */ }}; /* Class info for "range" free space sections */ H5FS_section_class_t H5FS_SECT_CLS_FHEAP_RANGE[1] = {{ - H5FS_SECT_FHEAP_RANGE, - 0, - H5HF_sect_range_init, - H5HF_sect_range_serialize, - H5HF_sect_range_deserialize, - H5HF_sect_range_debug, + H5FS_SECT_FHEAP_RANGE, /* Section type */ + 0, /* Extra serialized size */ + H5HF_sect_range_init_cls, /* Initialize section class */ + H5HF_sect_range_serialize, /* Serialize section */ + H5HF_sect_range_deserialize, /* Deserialize section */ + NULL, /* Can sections merge? */ + NULL, /* Merge sections */ + NULL, /* Can section shrink container?*/ + NULL, /* Shrink container w/section */ + H5HF_sect_range_free, /* Free section */ + H5HF_sect_range_debug, /* Dump debugging for section */ }}; /* Class info for "indirect" free space sections */ H5FS_section_class_t H5FS_SECT_CLS_FHEAP_INDIRECT[1] = {{ - H5FS_SECT_FHEAP_INDIRECT, - 0, - H5HF_sect_indirect_init, - H5HF_sect_indirect_serialize, - H5HF_sect_indirect_deserialize, - H5HF_sect_indirect_debug, + H5FS_SECT_FHEAP_INDIRECT, /* Section type */ + 0, /* Extra serialized size */ + H5HF_sect_indirect_init_cls, /* Initialize section class */ + H5HF_sect_indirect_serialize, /* Serialize section */ + H5HF_sect_indirect_deserialize, /* Deserialize section */ + NULL, /* Can sections merge? */ + NULL, /* Merge sections */ + NULL, /* Can section shrink container?*/ + NULL, /* Shrink container w/section */ + H5HF_sect_indirect_free, /* Free section */ + H5HF_sect_indirect_debug, /* Dump debugging for section */ }}; /* Declare a free list to manage the H5HF_free_section_t struct */ @@ -120,63 +157,6 @@ H5FL_DEFINE(H5HF_free_section_t); /*------------------------------------------------------------------------- - * Function: H5HF_free_section_free_cb - * - * Purpose: Free a free section node - * - * Return: Success: non-negative - * - * Failure: negative - * - * Programmer: Quincey Koziol - * Monday, March 13, 2006 - * - *------------------------------------------------------------------------- - */ -herr_t -H5HF_free_section_free_cb(void *_sect, void UNUSED *key, void UNUSED *op_data) -{ - H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; - herr_t ret_value = 0; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5HF_free_section_free_cb) - - HDassert(sect); - - /* Check for live reference to an indirect block */ - if(sect->sect_info.state == H5FS_SECT_LIVE) { - H5HF_indirect_t *iblock; /* Indirect block referenced */ - - /* Find indirect block that free section references */ - switch(sect->sect_info.cls->type) { - case H5FS_SECT_FHEAP_SINGLE: - iblock = sect->u.single.parent; - break; - - case H5FS_SECT_FHEAP_RANGE: - iblock = sect->u.range.iblock; - break; - - case H5FS_SECT_FHEAP_INDIRECT: - iblock = sect->u.indirect.iblock; - break; - } /* end switch */ - - /* Release indirect block, if there was one */ - if(iblock) - if(H5HF_iblock_decr(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") - } /* end if */ - - /* Release the sections */ - H5FL_FREE(H5HF_free_section_t, sect); - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_free_section_free_cb() */ - - -/*------------------------------------------------------------------------- * Function: H5HF_sect_node_alloc * * Purpose: Allocate a free space section node of a particular type @@ -225,6 +205,114 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_sect_node_free + * + * Purpose: Free a section node + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_node_free(H5HF_free_section_t *sect, H5HF_indirect_t *parent) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_node_free) + + HDassert(sect); + + /* Release indirect block, if there was one */ + if(parent) + if(H5HF_iblock_decr(parent) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on parent indirect block") + + /* Release the section */ + H5FL_FREE(H5HF_free_section_t, sect); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_node_free() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_single_revive + * + * Purpose: Update the memory information for a 'single' free section + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 8 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_single_revive(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect) +{ + H5HF_indirect_t *sec_iblock; /* Pointer to section indirect block */ + unsigned sec_entry; /* Entry within section indirect block */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_single_revive) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(sect); + HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED); + + /* Check for root direct block */ + if(hdr->man_dtable.curr_root_rows == 0) { + /* Set the information for the section */ + sect->u.single.parent = NULL; + sect->u.single.par_entry = 0; + + /* Set direct block info */ + HDassert(H5F_addr_defined(hdr->man_dtable.table_addr)); + sect->u.single.dblock_addr = hdr->man_dtable.table_addr; + sect->u.single.dblock_size = hdr->man_dtable.cparam.start_block_size; + } /* end if */ + else { + /* Look up indirect block containing direct blocks for range */ + if(H5HF_man_locate_block(hdr, dxpl_id, sect->sect_info.addr, FALSE, &sec_iblock, &sec_entry, H5AC_READ) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") + + /* Increment reference count on indirect block that free section is in */ + if(H5HF_iblock_incr(sec_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") + + /* Set the information for the section */ + sect->u.single.parent = sec_iblock; + sect->u.single.par_entry = sec_entry; + + /* Set direct block info */ + sect->u.single.dblock_addr = sec_iblock->ents[sec_entry].addr; + sect->u.single.dblock_size = hdr->man_dtable.row_block_size[sec_entry / hdr->man_dtable.cparam.width]; + + /* Unlock indirect block */ + if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, sec_iblock->addr, sec_iblock, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") + sec_iblock = NULL; + } /* end else */ + + /* Section is "live" now */ + sect->sect_info.state = H5FS_SECT_LIVE; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_sect_single_revive() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_sect_single_deserialize * * Purpose: Deserialize a buffer into a "live" single section @@ -263,7 +351,276 @@ done: /*------------------------------------------------------------------------- - * Function: H5HF_sect_range_init + * Function: H5HF_sect_single_can_merge + * + * Purpose: Can two sections of this type merge? + * + * Note: Second section must be "after" first section + * + * Return: Success: non-negative (TRUE/FALSE) + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF_sect_single_can_merge(const H5FS_section_info_t *sect1, + const H5FS_section_info_t *sect2, void UNUSED *udata) +{ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_sect_single_can_merge) + + /* Check arguments. */ + HDassert(sect1); + HDassert(sect2); + HDassert(H5F_addr_lt(sect1->addr, sect2->addr)); + +#ifdef QAK +HDfprintf(stderr, "%s: sect1->size = %Hu, sect1->addr = %a\n", "H5HF_sect_single_can_merge", sect1->size, sect1->addr); +HDfprintf(stderr, "%s: sect2->size = %Hu, sect2->addr = %a\n", "H5HF_sect_single_can_merge", sect2->size, sect2->addr); +#endif /* QAK */ + + /* Single section can only merge with other single sections */ + if(sect1->cls->type != sect2->cls->type) + HGOTO_DONE(FALSE) + + /* Check if second section adjoins first section */ + /* (This can only occurs within a direct block, due to the direct block + * overhead at the beginning of a block) + */ + if(H5F_addr_eq(sect1->addr + sect1->size, sect2->addr)) + HGOTO_DONE(TRUE) + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_single_can_merge() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_single_merge + * + * Purpose: Merge two sections of this type + * + * Note: Second section always merges into first node + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF_sect_single_merge(H5FS_section_info_t *sect1, H5FS_section_info_t *sect2, + void UNUSED *udata) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_single_merge) + + /* Check arguments. */ + HDassert(sect1); + HDassert(sect2); + HDassert(H5F_addr_eq(sect1->addr + sect1->size, sect2->addr)); + +#ifdef QAK +HDfprintf(stderr, "%s: sect1->size = %Hu, sect1->addr = %a\n", "H5HF_sect_single_merge", sect1->size, sect1->addr); +HDfprintf(stderr, "%s: sect2->size = %Hu, sect2->addr = %a\n", "H5HF_sect_single_merge", sect2->size, sect2->addr); +#endif /* QAK */ + + /* Add second section's size to first section */ + sect1->size += sect2->size; + + /* Get rid of second section */ + if(H5HF_sect_single_free(sect2) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_single_merge() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_single_can_shrink + * + * Purpose: Can this section shrink the heap? + * + * Return: Success: non-negative (TRUE/FALSE) + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF_sect_single_can_shrink(H5FS_section_info_t *_sect, void *_udata) +{ + H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Fractal heap free section */ + H5HF_add_ud1_t *udata = (H5HF_add_ud1_t *)_udata; /* User callback data */ + H5HF_hdr_t *hdr; /* Fractal heap header */ + H5HF_direct_t *dblock = NULL; /* Pointer to direct block for section */ + haddr_t dblock_addr; /* Section's direct block's address */ + size_t dblock_size; /* Section's direct block's size */ + size_t dblock_overhead; /* Direct block's overhead */ + hid_t dxpl_id; /* DXPL ID for operation */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_single_can_shrink) + + /* Check arguments. */ + HDassert(sect); + HDassert(udata); + HDassert(udata->hdr); + +#ifdef QAK +HDfprintf(stderr, "%s: sect->sect_info.size = %Hu, sect->sect_info.addr = %a\n", FUNC, sect->sect_info.size, sect->sect_info.addr); +#endif /* QAK */ + + /* Initialize some local convenience variables */ + hdr = udata->hdr; + dxpl_id = udata->dxpl_id; + + /* Revive the section, if it's still serialized */ + if(sect->sect_info.state != H5FS_SECT_LIVE) { + if(H5HF_sect_single_revive(hdr, dxpl_id, sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section") + } /* end if */ + + /* Protect the direct block for the section */ + dblock_addr = sect->u.single.dblock_addr; + dblock_size = sect->u.single.dblock_size; +#ifdef QAK +HDfprintf(stderr, "%s: dblock_size = %u, dblock_addr = %a\n", FUNC, dblock_size, dblock_addr); +#endif /* QAK */ + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, sect->u.single.parent, sect->u.single.par_entry, H5AC_READ))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block") + + /* Check for section occupying entire direct block */ + dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr); + if(H5F_addr_eq(dblock->block_off + dblock_overhead, sect->sect_info.addr) && + (dblock_size - dblock_overhead) == sect->sect_info.size) { + /* Stash the direct block pointer away for the 'shrink' callback */ + udata->dblock = dblock; + + /* Indicate that the heap can be shrunk */ + HGOTO_DONE(TRUE) + } /* end if */ + +done: + /* Unprotect the direct block, if we aren't going to use it in the 'shrink' callback */ + if(ret_value != TRUE) + if(dblock && H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block") + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_single_can_shrink() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_single_shrink + * + * Purpose: Shrink heap w/section + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF_sect_single_shrink(H5FS_section_info_t **_sect, void *_udata) +{ + H5HF_free_section_t **sect = (H5HF_free_section_t **)_sect; /* Fractal heap free section */ + H5HF_add_ud1_t *udata = (H5HF_add_ud1_t *)_udata; /* User callback data */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_single_shrink) + + /* Check arguments. */ + HDassert(sect); + HDassert(*sect); + HDassert((*sect)->sect_info.state == H5FS_SECT_LIVE); + HDassert(udata); + HDassert(udata->hdr); + HDassert(udata->dblock); + +#ifdef QAK +HDfprintf(stderr, "%s: (*sect)->sect_info.size = %Hu, (*sect)->sect_info.addr = %a\n", "H5HF_sect_single_shrink", (*sect)->sect_info.size, (*sect)->sect_info.addr); +#endif /* QAK */ + + /* Destroy direct block */ + if(H5HF_man_dblock_destroy(udata->hdr, udata->dxpl_id, udata->dblock, (*sect)->u.single.dblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release direct block") + + /* Mark section as "dead", since it's direct block is destroyed */ + (*sect)->sect_info.state = H5FS_SECT_SERIALIZED; + + /* Release section */ + if(H5HF_sect_single_free((H5FS_section_info_t *)*sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node") + + /* Set section pointer to NULL, to indicate that the section was released */ + *sect = NULL; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_single_shrink() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_single_free + * + * Purpose: Free a 'single' section node + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_single_free(H5FS_section_info_t *_sect) +{ + H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Pointer to section to free */ + H5HF_indirect_t *parent = NULL; /* Parent indirect block for section */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_single_free) + + HDassert(sect); + + /* Check for live reference to an indirect block */ + if(sect->sect_info.state == H5FS_SECT_LIVE) { + /* Get parent indirect block, if there was one */ + if(sect->u.single.parent) + parent = sect->u.single.parent; + } /* end if */ + + /* Release the section */ + if(H5HF_sect_node_free(sect, parent) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_single_free() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_range_init_cls * * Purpose: Initialize the "range" class structure * @@ -277,9 +634,9 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5HF_sect_range_init(H5FS_section_class_t *cls, const void UNUSED *udata) +H5HF_sect_range_init_cls(H5FS_section_class_t *cls, const void UNUSED *udata) { - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_sect_range_init) + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_sect_range_init_cls) /* Check arguments. */ HDassert(cls); @@ -290,7 +647,61 @@ H5HF_sect_range_init(H5FS_section_class_t *cls, const void UNUSED *udata) + 2; /* # of entries */ FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5HF_sect_range_init() */ +} /* H5HF_sect_range_init_cls() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_range_revive + * + * Purpose: Update the memory information for a 'range' free section + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 8 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_range_revive(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect) +{ + H5HF_indirect_t *sec_iblock; /* Pointer to section indirect block */ + unsigned sec_entry; /* Entry within section indirect block */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_range_revive) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(sect); + HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED); + + /* Look up indirect block containing direct blocks for range */ + if(H5HF_man_locate_block(hdr, dxpl_id, sect->sect_info.addr, FALSE, &sec_iblock, &sec_entry, H5AC_READ) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") + + /* Increment reference count on indirect block that free section is in */ + if(H5HF_iblock_incr(sec_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") + + /* Set the pointer to the section's indirect block */ + sect->u.range.iblock = sec_iblock; + + /* Unlock indirect block */ + if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, sec_iblock->addr, sec_iblock, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") + sec_iblock = NULL; + + /* Section is "live" now */ + sect->sect_info.state = H5FS_SECT_LIVE; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_sect_range_revive() */ /*------------------------------------------------------------------------- @@ -379,6 +790,47 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_sect_range_free + * + * Purpose: Free a 'range' section node + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_range_free(H5FS_section_info_t *_sect) +{ + H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Pointer to section to free */ + H5HF_indirect_t *parent = NULL; /* Parent indirect block for section */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_range_free) + + HDassert(sect); + + /* Check for live reference to an indirect block */ + if(sect->sect_info.state == H5FS_SECT_LIVE) { + /* Get parent indirect block, if there was one */ + if(sect->u.range.iblock) + parent = sect->u.range.iblock; + } /* end if */ + + /* Release the section */ + if(H5HF_sect_node_free(sect, parent) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_range_free() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_sect_range_debug * * Purpose: Dump debugging information about an range free space section @@ -419,7 +871,7 @@ H5HF_sect_range_debug(const H5FS_section_info_t *_sect, /*------------------------------------------------------------------------- - * Function: H5HF_sect_indirect_init + * Function: H5HF_sect_indirect_init_cls * * Purpose: Initialize the "indirect" class structure * @@ -433,9 +885,9 @@ H5HF_sect_range_debug(const H5FS_section_info_t *_sect, *------------------------------------------------------------------------- */ static herr_t -H5HF_sect_indirect_init(H5FS_section_class_t *cls, const void UNUSED *udata) +H5HF_sect_indirect_init_cls(H5FS_section_class_t *cls, const void UNUSED *udata) { - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_sect_indirect_init) + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_sect_indirect_init_cls) /* Check arguments. */ HDassert(cls); @@ -448,7 +900,61 @@ H5HF_sect_indirect_init(H5FS_section_class_t *cls, const void UNUSED *udata) + 2; /* Indirect # of rows */ FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5HF_sect_indirect_init() */ +} /* H5HF_sect_indirect_init_cls() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_indirect_revive + * + * Purpose: Update the memory information for a 'indirect' free section + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 8 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_indirect_revive(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect) +{ + H5HF_indirect_t *sec_iblock; /* Pointer to section indirect block */ + unsigned sec_entry; /* Entry within section indirect block */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_indirect_revive) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(sect); + HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED); + + /* Look up indirect block containing indirect blocks for section */ + if(H5HF_man_locate_block(hdr, dxpl_id, sect->sect_info.addr, TRUE, &sec_iblock, &sec_entry, H5AC_READ) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") + + /* Increment reference count on indirect block that free section is in */ + if(H5HF_iblock_incr(sec_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") + + /* Set the pointer to the section's indirect block */ + sect->u.indirect.iblock = sec_iblock; + + /* Unlock indirect block */ + if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, sec_iblock->addr, sec_iblock, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") + sec_iblock = NULL; + + /* Section is "live" now */ + sect->sect_info.state = H5FS_SECT_LIVE; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_sect_indirect_revive() */ /*------------------------------------------------------------------------- @@ -549,6 +1055,47 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_sect_indirect_free + * + * Purpose: Free a 'indirect' section node + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Wednesday, May 17, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_indirect_free(H5FS_section_info_t *_sect) +{ + H5HF_free_section_t *sect = (H5HF_free_section_t *)_sect; /* Pointer to section to free */ + H5HF_indirect_t *parent = NULL; /* Parent indirect block for section */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_indirect_free) + + HDassert(sect); + + /* Check for live reference to an indirect block */ + if(sect->sect_info.state == H5FS_SECT_LIVE) { + /* Get parent indirect block, if there was one */ + if(sect->u.indirect.iblock) + parent = sect->u.indirect.iblock; + } /* end if */ + + /* Release the sections */ + if(H5HF_sect_node_free(sect, parent) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_indirect_free() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_sect_indirect_debug * * Purpose: Dump debugging information about an indirect free space section diff --git a/src/H5HFspace.c b/src/H5HFspace.c index 7f68817..91cc742 100644 --- a/src/H5HFspace.c +++ b/src/H5HFspace.c @@ -127,7 +127,7 @@ H5HF_space_start(H5HF_hdr_t *hdr, hid_t dxpl_id) if(H5F_addr_defined(hdr->fs_addr)) { /* Open an existing free space structure for the heap */ if(NULL == (hdr->fspace = H5FS_open(hdr->f, dxpl_id, hdr->fs_addr, - H5HF_free_section_free_cb, hdr->nsect_classes, hdr->sect_cls, hdr))) + hdr->nsect_classes, hdr->sect_cls, hdr))) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize free space info") } /* end if */ else { @@ -142,8 +142,7 @@ H5HF_space_start(H5HF_hdr_t *hdr, hid_t dxpl_id) /* Create the free space structure for the heap */ if(NULL == (hdr->fspace = H5FS_create(hdr->f, dxpl_id, &hdr->fs_addr, - &fs_create, H5HF_free_section_free_cb, - hdr->nsect_classes, hdr->sect_cls, hdr))) + &fs_create, hdr->nsect_classes, hdr->sect_cls, hdr))) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize free space info") } /* end else */ @@ -233,7 +232,7 @@ H5HF_space_add(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *node) HDassert(hdr->fspace); /* Add to the free space for the heap */ - if(H5FS_add(hdr->f, dxpl_id, hdr->fspace, (H5FS_section_info_t *)node) < 0) + if(H5FS_add(hdr->f, dxpl_id, hdr->fspace, (H5FS_section_info_t *)node, 0, NULL) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't add section to heap free space") done: @@ -242,6 +241,54 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_space_return + * + * Purpose: Return a freedsection to the free space for the heap + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 15 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_space_return(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *node) +{ + H5HF_add_ud1_t udata; /* User data for free space manager 'add' */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_space_return) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(node); + + /* Check if the free space for the heap has been initialized */ + if(!hdr->fspace_open) + if(H5HF_space_start(hdr, dxpl_id) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space") + + /* Construct user data */ + udata.hdr = hdr; + udata.dxpl_id = dxpl_id; + udata.dblock = NULL; + + /* Add to the free space for the heap */ + if(H5FS_add(hdr->f, dxpl_id, hdr->fspace, (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't add section to heap free space") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_space_return() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_space_close * * Purpose: Close the free space for the heap diff --git a/src/H5HFtest.c b/src/H5HFtest.c index 2327fe6..a171acd 100644 --- a/src/H5HFtest.c +++ b/src/H5HFtest.c @@ -84,7 +84,7 @@ *------------------------------------------------------------------------- */ herr_t -H5HF_get_cparam_test(H5HF_t *fh, H5HF_create_t *cparam) +H5HF_get_cparam_test(const H5HF_t *fh, H5HF_create_t *cparam) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_get_cparam_test) @@ -102,6 +102,68 @@ H5HF_get_cparam_test(H5HF_t *fh, H5HF_create_t *cparam) /*------------------------------------------------------------------------- + * Function: H5HF_get_dblock_overhead + * + * Purpose: Retrieve the size of direct block overhead + * + * Return: Success: Size of direct block overhead + * + * Failure: 0 + * + * Programmer: Quincey Koziol + * Tuesday, May 9, 2006 + * + *------------------------------------------------------------------------- + */ +size_t +H5HF_get_dblock_overhead(const H5HF_t *fh) +{ + size_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_get_dblock_overhead) + + /* Check arguments. */ + HDassert(fh); + + /* Return direct block overhead */ + ret_value = H5HF_MAN_ABS_DIRECT_OVERHEAD(fh->hdr); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_get_dblock_overhead() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_get_dblock_size_test + * + * Purpose: Retrieve the size of a direct block for a given row + * + * Return: Success: Size of direct block + * + * Failure: 0 + * + * Programmer: Quincey Koziol + * Monday, May 15, 2006 + * + *------------------------------------------------------------------------- + */ +hsize_t +H5HF_get_dblock_size_test(const H5HF_t *fh, unsigned row) +{ + hsize_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_get_dblock_size_test) + + /* Check arguments. */ + HDassert(fh); + + /* Return direct block free space */ + ret_value = fh->hdr->man_dtable.row_block_size[row]; + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_get_dblock_size_test() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_get_dblock_free_test * * Purpose: Retrieve the size of direct block free space for a given @@ -117,7 +179,7 @@ H5HF_get_cparam_test(H5HF_t *fh, H5HF_create_t *cparam) *------------------------------------------------------------------------- */ hsize_t -H5HF_get_dblock_free_test(H5HF_t *fh, unsigned row) +H5HF_get_dblock_free_test(const H5HF_t *fh, unsigned row) { hsize_t ret_value; /* Return value */ @@ -134,32 +196,35 @@ H5HF_get_dblock_free_test(H5HF_t *fh, unsigned row) /*------------------------------------------------------------------------- - * Function: H5HF_get_dblock_overhead + * Function: H5HF_get_id_off_test * - * Purpose: Retrieve the size of direct block overhead + * Purpose: Retrieve the offset for a heap ID * - * Return: Success: Size of direct block overhead + * Return: Success: non-negative * - * Failure: 0 + * Failure: negative * * Programmer: Quincey Koziol - * Tuesday, May 9, 2006 + * Monday, May 15, 2006 * *------------------------------------------------------------------------- */ -size_t -H5HF_get_dblock_overhead(H5HF_t *fh) +herr_t +H5HF_get_id_off_test(const H5HF_t *fh, const void *_id, hsize_t *obj_off) { - size_t ret_value; /* Return value */ + const uint8_t *id = (const uint8_t *)_id; /* Object ID */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_get_dblock_overhead) + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_get_id_off_test) /* Check arguments. */ HDassert(fh); + HDassert(fh->hdr); + HDassert(id); + HDassert(obj_off); - /* Return direct block overhead */ - ret_value = H5HF_MAN_ABS_DIRECT_OVERHEAD(fh->hdr); + /* Get the offset for a heap ID */ + UINT64DECODE_VAR(id, *obj_off, fh->hdr->heap_off_size); \ - FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_get_dblock_overhead() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5HF_get_id_off_test() */ diff --git a/src/H5err.txt b/src/H5err.txt index 91cdb95..ca8f515 100644 --- a/src/H5err.txt +++ b/src/H5err.txt @@ -70,7 +70,7 @@ MAJOR, H5E_TST, Ternary Search Trees MAJOR, H5E_RS, Reference Counted Strings MAJOR, H5E_ERROR, Error API MAJOR, H5E_SLIST, Skip Lists -MAJOR, H5E_FSPACE, File Free Space +MAJOR, H5E_FSPACE, Free Space Manager MAJOR, H5E_NONE_MAJOR, No error # Sections (for grouping minor errors) @@ -89,6 +89,7 @@ SECTION, DSPACE, Dataspace errors SECTION, PLIST, Property list errors SECTION, MPI, Parallel MPI errors SECTION, HEAP, Heap errors +SECTION, FSPACE, Free space errors SECTION, PIPELINE, I/O pipeline errors SECTION, SYSTEM, System level errors SECTION, NONE, No error @@ -172,6 +173,7 @@ MINOR, BTREE, H5E_CANTSWAP, Unable to swap records MINOR, BTREE, H5E_CANTINSERT, Unable to insert object MINOR, BTREE, H5E_CANTLIST, Unable to list node MINOR, BTREE, H5E_CANTMODIFY, Unable to modify record +MINOR, BTREE, H5E_CANTREMOVE, Unable to remove object # Object header related errors MINOR, OHDR, H5E_LINKCOUNT, Bad object header link count @@ -217,6 +219,11 @@ MINOR, HEAP, H5E_CANTRESTORE, Can't restore condition MINOR, HEAP, H5E_CANTCOMPUTE, Can't compute value MINOR, HEAP, H5E_CANTEXTEND, Can't extend heap's space +# Free space manager errors +MINOR, FSPACE, H5E_CANTMERGE, Can't merge objects +MINOR, FSPACE, H5E_CANTREVIVE, Can't revive object +MINOR, FSPACE, H5E_CANTSHRINK, Can't shrink container + # I/O pipeline errors MINOR, PIPELINE, H5E_NOFILTER, Requested filter is not available MINOR, PIPELINE, H5E_CALLBACK, Callback failed diff --git a/test/fheap.c b/test/fheap.c index b35d208..90845b2 100644 --- a/test/fheap.c +++ b/test/fheap.c @@ -49,6 +49,7 @@ /* Heap metadata macros */ #define DBLOCK_OVERHEAD(fh) H5HF_get_dblock_overhead(fh) /* # of bytes in direct block overhead */ #define HEAP_ID_LEN 12 /* # of bytes to use for heap ID */ +#define DBLOCK_SIZE(fh, r) H5HF_get_dblock_size_test(fh, r) #define DBLOCK_FREE(fh, r) H5HF_get_dblock_free_test(fh, r) const char *FILENAME[] = { @@ -194,6 +195,7 @@ add_obj(H5HF_t *fh, hid_t dxpl, /* Initialize object buffer */ obj = H5MM_malloc(obj_size); + HDassert(obj); for(u = 0; u < obj_size; u++) obj[u] = u + obj_init; @@ -5217,6 +5219,185 @@ error: /*------------------------------------------------------------------------- + * Function: test_abs_fill_row_skip_add_skipped + * + * Purpose: Test filling first row of direct blocks, then + * add object too large for any blocks in first three rows of + * direct blocks, to force extension of indirect block (and range + * of skipped blocks). + * + * Then add more objects to fill up remainder of partial direct + * block and all the skipped blocks, and one more object (to + * start next "normal" block). + * + * Return: Success: 0 + * + * Failure: 1 + * + * Programmer: Quincey Koziol + * Monday, May 15, 2006 + * + *------------------------------------------------------------------------- + */ +static int +test_abs_fill_row_skip_add_skipped(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) +{ + hid_t file = -1; /* File ID */ + hid_t dxpl = H5P_DATASET_XFER_DEFAULT; /* DXPL to use */ + char filename[1024]; /* Filename to use */ + H5F_t *f = NULL; /* Internal file object pointer */ + H5HF_t *fh = NULL; /* Fractal heap wrapper */ + haddr_t fh_addr; /* Address of fractal heap */ + size_t id_len; /* Size of fractal heap IDs */ + unsigned nobjs = 0; /* Number of objects inserted */ + size_t obj_size; /* Size of object */ + hsize_t free_space; /* Size of free space in heap */ + hsize_t heap_size; /* Total size of heap */ + + /* Set the filename to use for this test (dependent on fapl) */ + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); + + /* Create the file to work on */ + if((file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) + TEST_ERROR + + /* Get a pointer to the internal file object */ + if(NULL == (f = H5I_object(file))) + STACK_ERROR + + /* Create absolute heap */ + if(NULL == (fh = H5HF_create(f, H5P_DATASET_XFER_DEFAULT, cparam))) + FAIL_STACK_ERROR + if(H5HF_get_id_len(fh, &id_len) < 0) + FAIL_STACK_ERROR + if(id_len > HEAP_ID_LEN) + FAIL_STACK_ERROR + if(H5HF_get_heap_addr(fh, &fh_addr) < 0) + FAIL_STACK_ERROR + if(!H5F_addr_defined(fh_addr)) + FAIL_STACK_ERROR + + /* + * Test absolute heap + */ + TESTING("filling first row, then skipping rows, then backfill and extend"); + + /* Fill first row of direct blocks */ + heap_size = 0; + free_space = 0; + if(fill_root_row(fh, dxpl, cparam, &heap_size, &free_space, 0, &nobjs)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Insert large object, to force creation of indirect block and + * range of skipped blocks that are too small to hold the large object + */ + obj_size = (2 * cparam->managed.start_block_size) + 1; + heap_size += cparam->managed.width * DBLOCK_SIZE(fh, 1); + heap_size += cparam->managed.width * DBLOCK_SIZE(fh, 2); + heap_size += cparam->managed.width * DBLOCK_SIZE(fh, 3); + free_space += cparam->managed.width * DBLOCK_FREE(fh, 1); + free_space += cparam->managed.width * DBLOCK_FREE(fh, 2); + free_space += cparam->managed.width * DBLOCK_FREE(fh, 3); + if(add_obj(fh, dxpl, heap_size, &free_space, &nobjs, 20, obj_size)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Insert object to fill remainder of 4 * start size block */ + obj_size = DBLOCK_FREE(fh, 3) - obj_size; + if(add_obj(fh, dxpl, heap_size, &free_space, &nobjs, 20, obj_size)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Insert objects to fill remaining heaps in second row */ + if(fill_row(fh, dxpl, cparam, &heap_size, &free_space, 1, &nobjs)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Insert objects to fill remaining heaps in third row */ + if(fill_row(fh, dxpl, cparam, &heap_size, &free_space, 2, &nobjs)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Insert one more object, to create new 4 * start size direct block */ + obj_size = SMALL_OBJ_SIZE1; + if(add_obj(fh, dxpl, heap_size, &free_space, &nobjs, 10, obj_size)) + FAIL_STACK_ERROR + + PASSED() + + /* Close the fractal heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Close the file */ + if(H5Fclose(file) < 0) + TEST_ERROR + + /* All tests passed */ + return(0); + +error: + H5E_BEGIN_TRY { + if(fh) + H5HF_close(fh, dxpl); + H5Fclose(file); + } H5E_END_TRY; + return(1); +} /* test_abs_fill_row_skip_add_skipped() */ + + +/*------------------------------------------------------------------------- * Function: test_abs_fill_direct_skip_indirect_start_block_add_skipped * * Purpose: Test filling all direct blocks in root indirect block, then @@ -6838,28 +7019,27 @@ error: /*------------------------------------------------------------------------- - * Function: test_abs_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped + * Function: test_abs_fill_2nd_direct_fill_direct_skip2_3rd_indirect_start_block_add_skipped * * Purpose: Test filling all direct blocks in root indirect block and all - * direct blocks in 2nd level indirect blocks, all 3rd level - * indirect blocks in first row except the last one, fill direct - * blocks in lasts 3rd level indirect block, then insert object - * insert object that is too large to hold in last 3rd level - * indirect block's row of 2nd level indirect blocks (forcing the - * use of the next row of 3rd level blocks), then backfill all - * skipped direct blocks & extend. + * direct blocks in 2nd level indirect blocks, fill all direct + * blocks in 3rd level indirect block, then insert object + * that is too large to hold in first & second rows of 2nd level + * indirect blocks (although this 3rd level indirect block only + * has one row of 2nd level indirect blocks) of 3rd level indirect + * block, then backfill & extend all skipped direct blocks. * * Return: Success: 0 * * Failure: 1 * * Programmer: Quincey Koziol - * Tues, April 18, 2006 + * Tuesday, April 11, 2006 * *------------------------------------------------------------------------- */ static int -test_abs_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) +test_abs_fill_2nd_direct_fill_direct_skip2_3rd_indirect_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) { hid_t file = -1; /* File ID */ hid_t dxpl = H5P_DATASET_XFER_DEFAULT; /* DXPL to use */ @@ -6914,7 +7094,7 @@ HDfprintf(stderr, "num_first_indirect_rows = %u\n", num_first_indirect_rows); /* * Test absolute heap */ - TESTING("filling direct blocks, filling 2nd level indirect blocks, filling first row of 3rd level indirect blocks, except last one, fill all direct blocks in last 3rd level indirect block, and insert object too large for it's 2nd level indirect blocks, then backfill and extend"); + TESTING("filling direct blocks, filling 2nd level indirect blocks, filling 3rd level indirect block's direct blocks, and skip first two rows of indirect blocks of 3rd level indirect block, then backfill and extend"); /* Fill direct blocks in root indirect block */ heap_size = 0; @@ -6933,7 +7113,7 @@ HDfprintf(stderr, "num_first_indirect_rows = %u\n", num_first_indirect_rows); FAIL_STACK_ERROR } /* end if */ - /* Fill all rows of 2nd level indirect blocks in 4th level indirect block */ + /* Fill all rows of 2nd level indirect blocks */ if(fill_all_2nd_indirect_rows(fh, dxpl, cparam, &heap_size, &free_space, &nobjs)) FAIL_STACK_ERROR @@ -6948,24 +7128,7 @@ HDfprintf(stderr, "num_first_indirect_rows = %u\n", num_first_indirect_rows); FAIL_STACK_ERROR } /* end if */ - /* Fill first row (except one) of 3rd level indirect blocks */ - for(u = 0; u < cparam->managed.width - 1; u++) - /* Fill 3rd level indirect block */ - if(fill_3rd_indirect(fh, dxpl, cparam, &heap_size, &free_space, &nobjs, 1)) - FAIL_STACK_ERROR - - /* Check for closing & re-opening the heap */ - if(tparam->reopen_heap) { - /* Close heap */ - if(H5HF_close(fh, dxpl) < 0) - TEST_ERROR - - /* Re-open heap */ - if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) - FAIL_STACK_ERROR - } /* end if */ - - /* Fill all direct block rows in last third level indirect block */ + /* Fill all direct block rows in third level indirect block */ if(fill_all_direct(fh, dxpl, cparam, &heap_size, &free_space, &nobjs)) FAIL_STACK_ERROR @@ -6984,7 +7147,7 @@ HDfprintf(stderr, "num_first_indirect_rows = %u\n", num_first_indirect_rows); * range of skipped (indirect) blocks that are too small to hold the large * object */ - obj_size = (1 << ((num_first_indirect_rows + H5V_log2_of2(cparam->managed.start_block_size)) - 2)) + 1; + obj_size = (1 << ((num_first_indirect_rows + H5V_log2_of2(cparam->managed.start_block_size)) - 1)) + 1; #ifdef QAK HDfprintf(stderr, "obj_size = %Zu\n", obj_size); #endif /* QAK */ @@ -7003,7 +7166,10 @@ HDfprintf(stderr, "obj_size = %Zu\n", obj_size); } /* end if */ /* Insert object to fill space in (large) block created */ - obj_size = DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size; + obj_size = DBLOCK_FREE(fh, num_first_indirect_rows + 1) - obj_size; +#ifdef QAK +HDfprintf(stderr, "obj_size = %Zu\n", obj_size); +#endif /* QAK */ if(add_obj(fh, dxpl, heap_size, &free_space, &nobjs, 20, obj_size)) FAIL_STACK_ERROR @@ -7018,8 +7184,9 @@ HDfprintf(stderr, "obj_size = %Zu\n", obj_size); FAIL_STACK_ERROR } /* end if */ - /* Fill rows skipped over in 2nd level indirect block's direct blocks - * (and rows of next 3rd level indirect block's direct blocks) + /* Fill rows skipped over in (first 3rd level indirect block's) 2nd level + * indirect block's direct blocks + * (and second 3rd level indirect block's direct blocks) */ for(u = 0; u < num_first_indirect_rows; u++) { /* Direct block rows in 2nd level indirect blocks */ @@ -7027,7 +7194,7 @@ HDfprintf(stderr, "obj_size = %Zu\n", obj_size); if(fill_row(fh, dxpl, cparam, &heap_size, &free_space, u, &nobjs)) FAIL_STACK_ERROR - /* Direct block row in current 2nd level indirect block */ + /* Direct block row in 3rd level indirect block */ if(fill_row(fh, dxpl, cparam, &heap_size, &free_space, u, &nobjs)) FAIL_STACK_ERROR } /* end for */ @@ -7068,21 +7235,20 @@ error: H5Fclose(file); } H5E_END_TRY; return(1); -} /* test_abs_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped() */ +} /* test_abs_fill_2nd_direct_fill_direct_skip2_3rd_indirect_start_block_add_skipped() */ /*------------------------------------------------------------------------- - * Function: test_abs_fill_1st_row_3rd_direct_fill_2nd_direct_less_one_wrap_start_block_add_skipped + * Function: test_abs_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped * * Purpose: Test filling all direct blocks in root indirect block and all * direct blocks in 2nd level indirect blocks, all 3rd level - * indirect blocks in first row, fill direct blocks in 2nd row 3rd - * level indirect block, fill all direct blocks in 1st row of - * 2nd level indirect blocks except the last one, then insert - * object that is too large to hold in 3rd level indirect block's - * first row of 2nd level indirect blocks (forcing the use of the - * next row of 2nd level blocks), then backfill all skipped direct - * blocks & extend. + * indirect blocks in first row except the last one, fill direct + * blocks in lasts 3rd level indirect block, then insert object + * insert object that is too large to hold in last 3rd level + * indirect block's row of 2nd level indirect blocks (forcing the + * use of the next row of 3rd level blocks), then backfill all + * skipped direct blocks & extend. * * Return: Success: 0 * @@ -7094,7 +7260,7 @@ error: *------------------------------------------------------------------------- */ static int -test_abs_fill_1st_row_3rd_direct_fill_2nd_direct_less_one_wrap_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) +test_abs_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) { hid_t file = -1; /* File ID */ hid_t dxpl = H5P_DATASET_XFER_DEFAULT; /* DXPL to use */ @@ -7110,7 +7276,7 @@ test_abs_fill_1st_row_3rd_direct_fill_2nd_direct_less_one_wrap_start_block_add_s size_t obj_size; /* Size of object */ hsize_t free_space; /* Size of free space in heap */ hsize_t heap_size; /* Total size of heap */ - unsigned u; /* Local index variables */ + unsigned u, v; /* Local index variables */ /* Set the filename to use for this test (dependent on fapl) */ h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); @@ -7149,7 +7315,7 @@ HDfprintf(stderr, "num_first_indirect_rows = %u\n", num_first_indirect_rows); /* * Test absolute heap */ - TESTING("filling direct blocks, filling 2nd level indirect blocks, filling first row of 3rd level indirect blocks, fill all direct blocks in next 3rd level indirect block, fill all 1st row of 2nd level indirect blocks, except last one, and insert object too large for 2nd level indirect block, then backfill and extend"); + TESTING("filling direct blocks, filling 2nd level indirect blocks, filling first row of 3rd level indirect blocks, except last one, fill all direct blocks in last 3rd level indirect block, and insert object too large for it's 2nd level indirect blocks, then backfill and extend"); /* Fill direct blocks in root indirect block */ heap_size = 0; @@ -7183,9 +7349,11 @@ HDfprintf(stderr, "num_first_indirect_rows = %u\n", num_first_indirect_rows); FAIL_STACK_ERROR } /* end if */ - /* Fill first row of 3rd level indirect blocks */ - if(fill_3rd_indirect_row(fh, dxpl, cparam, &heap_size, &free_space, &nobjs, 1)) - FAIL_STACK_ERROR + /* Fill first row (except one) of 3rd level indirect blocks */ + for(u = 0; u < cparam->managed.width - 1; u++) + /* Fill 3rd level indirect block */ + if(fill_3rd_indirect(fh, dxpl, cparam, &heap_size, &free_space, &nobjs, 1)) + FAIL_STACK_ERROR /* Check for closing & re-opening the heap */ if(tparam->reopen_heap) { @@ -7198,7 +7366,7 @@ HDfprintf(stderr, "num_first_indirect_rows = %u\n", num_first_indirect_rows); FAIL_STACK_ERROR } /* end if */ - /* Fill all direct block rows in 2nd row third level indirect block */ + /* Fill all direct block rows in last third level indirect block */ if(fill_all_direct(fh, dxpl, cparam, &heap_size, &free_space, &nobjs)) FAIL_STACK_ERROR @@ -7213,13 +7381,246 @@ HDfprintf(stderr, "num_first_indirect_rows = %u\n", num_first_indirect_rows); FAIL_STACK_ERROR } /* end if */ - /* Fill first row (except one) of 2nd level indirect blocks */ - for(u = 0; u < cparam->managed.width - 1; u++) { - if(fill_2nd_indirect(fh, dxpl, cparam, &heap_size, &free_space, &nobjs, 1)) - FAIL_STACK_ERROR - } /* end for */ - - /* Check for closing & re-opening the heap */ + /* Insert large object, to force creation of indirect block and + * range of skipped (indirect) blocks that are too small to hold the large + * object + */ + obj_size = (1 << ((num_first_indirect_rows + H5V_log2_of2(cparam->managed.start_block_size)) - 2)) + 1; +#ifdef QAK +HDfprintf(stderr, "obj_size = %Zu\n", obj_size); +#endif /* QAK */ + if(add_obj(fh, dxpl, heap_size, &free_space, &nobjs, 20, obj_size)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Insert object to fill space in (large) block created */ + obj_size = DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size; + if(add_obj(fh, dxpl, heap_size, &free_space, &nobjs, 20, obj_size)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Fill rows skipped over in 2nd level indirect block's direct blocks + * (and rows of next 3rd level indirect block's direct blocks) + */ + for(u = 0; u < num_first_indirect_rows; u++) { + /* Direct block rows in 2nd level indirect blocks */ + for(v = 0; v < cparam->managed.width; v++) + if(fill_row(fh, dxpl, cparam, &heap_size, &free_space, u, &nobjs)) + FAIL_STACK_ERROR + + /* Direct block row in current 2nd level indirect block */ + if(fill_row(fh, dxpl, cparam, &heap_size, &free_space, u, &nobjs)) + FAIL_STACK_ERROR + } /* end for */ + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Add one more object, to create another "large" block */ + obj_size = SMALL_OBJ_SIZE1; + if(add_obj(fh, dxpl, heap_size, &free_space, &nobjs, 10, obj_size)) + FAIL_STACK_ERROR + + PASSED() + + /* Close the fractal heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Close the file */ + if(H5Fclose(file) < 0) + TEST_ERROR + + /* All tests passed */ + return(0); + +error: + H5E_BEGIN_TRY { + if(fh) + H5HF_close(fh, dxpl); + H5Fclose(file); + } H5E_END_TRY; + return(1); +} /* test_abs_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped() */ + + +/*------------------------------------------------------------------------- + * Function: test_abs_fill_1st_row_3rd_direct_fill_2nd_direct_less_one_wrap_start_block_add_skipped + * + * Purpose: Test filling all direct blocks in root indirect block and all + * direct blocks in 2nd level indirect blocks, all 3rd level + * indirect blocks in first row, fill direct blocks in 2nd row 3rd + * level indirect block, fill all direct blocks in 1st row of + * 2nd level indirect blocks except the last one, then insert + * object that is too large to hold in 3rd level indirect block's + * first row of 2nd level indirect blocks (forcing the use of the + * next row of 2nd level blocks), then backfill all skipped direct + * blocks & extend. + * + * Return: Success: 0 + * + * Failure: 1 + * + * Programmer: Quincey Koziol + * Tues, April 18, 2006 + * + *------------------------------------------------------------------------- + */ +static int +test_abs_fill_1st_row_3rd_direct_fill_2nd_direct_less_one_wrap_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) +{ + hid_t file = -1; /* File ID */ + hid_t dxpl = H5P_DATASET_XFER_DEFAULT; /* DXPL to use */ + char filename[1024]; /* Filename to use */ + H5F_t *f = NULL; /* Internal file object pointer */ + H5HF_t *fh = NULL; /* Fractal heap wrapper */ + haddr_t fh_addr; /* Address of fractal heap */ + size_t id_len; /* Size of fractal heap IDs */ + unsigned first_row_bits; /* Number of bits used bit addresses in first row */ + unsigned first_indirect_block_size; /* Range of addresses covered by each of the first indirect blocks */ + unsigned num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */ + unsigned nobjs = 0; /* Number of objects inserted */ + size_t obj_size; /* Size of object */ + hsize_t free_space; /* Size of free space in heap */ + hsize_t heap_size; /* Total size of heap */ + unsigned u; /* Local index variables */ + + /* Set the filename to use for this test (dependent on fapl) */ + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); + + /* Create the file to work on */ + if((file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) + TEST_ERROR + + /* Get a pointer to the internal file object */ + if(NULL == (f = H5I_object(file))) + STACK_ERROR + + /* Create absolute heap */ + if(NULL == (fh = H5HF_create(f, H5P_DATASET_XFER_DEFAULT, cparam))) + FAIL_STACK_ERROR + if(H5HF_get_id_len(fh, &id_len) < 0) + FAIL_STACK_ERROR + if(id_len > HEAP_ID_LEN) + FAIL_STACK_ERROR + if(H5HF_get_heap_addr(fh, &fh_addr) < 0) + FAIL_STACK_ERROR + if(!H5F_addr_defined(fh_addr)) + FAIL_STACK_ERROR + + /* Compute # of bits used in first row */ + first_row_bits = H5V_log2_of2(cparam->managed.start_block_size) + + H5V_log2_of2(cparam->managed.width); + first_indirect_block_size = 2 * cparam->managed.max_direct_size; + num_first_indirect_rows = (H5V_log2_of2(first_indirect_block_size) - first_row_bits) + 1; +#ifdef QAK +HDfprintf(stderr, "first_row_bits = %u\n", first_row_bits); +HDfprintf(stderr, "first_indirect_block_size = %u\n", first_indirect_block_size); +HDfprintf(stderr, "num_first_indirect_rows = %u\n", num_first_indirect_rows); +#endif /* QAK */ + + /* + * Test absolute heap + */ + TESTING("filling direct blocks, filling 2nd level indirect blocks, filling first row of 3rd level indirect blocks, fill all direct blocks in next 3rd level indirect block, fill all 1st row of 2nd level indirect blocks, except last one, and insert object too large for 2nd level indirect block, then backfill and extend"); + + /* Fill direct blocks in root indirect block */ + heap_size = 0; + free_space = 0; + if(fill_root_direct(fh, dxpl, cparam, &heap_size, &free_space, &nobjs)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Fill all rows of 2nd level indirect blocks in 4th level indirect block */ + if(fill_all_2nd_indirect_rows(fh, dxpl, cparam, &heap_size, &free_space, &nobjs)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Fill first row of 3rd level indirect blocks */ + if(fill_3rd_indirect_row(fh, dxpl, cparam, &heap_size, &free_space, &nobjs, 1)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Fill all direct block rows in 2nd row third level indirect block */ + if(fill_all_direct(fh, dxpl, cparam, &heap_size, &free_space, &nobjs)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Fill first row (except one) of 2nd level indirect blocks */ + for(u = 0; u < cparam->managed.width - 1; u++) { + if(fill_2nd_indirect(fh, dxpl, cparam, &heap_size, &free_space, &nobjs, 1)) + FAIL_STACK_ERROR + } /* end for */ + + /* Check for closing & re-opening the heap */ if(tparam->reopen_heap) { /* Close heap */ if(H5HF_close(fh, dxpl) < 0) @@ -8767,25 +9168,25 @@ error: #ifndef QAK /*------------------------------------------------------------------------- - * Function: test_abs_frag_simple + * Function: test_abs_skip_direct_skip_indirect_two_rows_add_skipped * - * Purpose: Test inserting small object to create root direct block, then - * insert objects small enough to fit into first row of direct - * blocks, but not to share a block with another object, until - * initial-block-size * 2 blocks are reached. Then, go back and - * fill in the space in the blocks skipped. + * Purpose: Test adding object too large for all but the last row in the + * direct blocks in root indirect block, then + * add object too large for initial block in first two rows of + * indirect blocks, to force extension of non-root + * indirect block (and range of skipped blocks). * * Return: Success: 0 * * Failure: 1 * * Programmer: Quincey Koziol - * Tuesday, April 18, 2006 + * Saturday, April 15, 2006 * *------------------------------------------------------------------------- */ static int -test_abs_frag_simple(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) +test_abs_skip_direct_skip_indirect_two_rows_add_skipped(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) { hid_t file = -1; /* File ID */ hid_t dxpl = H5P_DATASET_XFER_DEFAULT; /* DXPL to use */ @@ -8794,11 +9195,13 @@ test_abs_frag_simple(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tpar H5HF_t *fh = NULL; /* Fractal heap wrapper */ haddr_t fh_addr; /* Address of fractal heap */ size_t id_len; /* Size of fractal heap IDs */ + unsigned num_direct_rows; /* Number of rows (of direct blocks) in root indirect block */ + unsigned row; /* Current row */ unsigned nobjs = 0; /* Number of objects inserted */ size_t obj_size; /* Size of object */ hsize_t free_space; /* Size of free space in heap */ hsize_t heap_size; /* Total size of heap */ - unsigned u; /* Local index variables */ + unsigned v; /* Local index variables */ /* Set the filename to use for this test (dependent on fapl) */ h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); @@ -8823,12 +9226,160 @@ test_abs_frag_simple(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tpar if(!H5F_addr_defined(fh_addr)) FAIL_STACK_ERROR + /* Compute # direct block rows in root indirect block */ + num_direct_rows = (H5V_log2_of2(cparam->managed.max_direct_size) - + H5V_log2_of2(cparam->managed.start_block_size)) + 3; + /* * Test absolute heap */ - TESTING("fragmenting small blocks, then backfill and extend"); + TESTING("skipping direct blocks to last row and skipping two rows of root indirect block, then backfill and extend"); - /* Insert objects small enough to fit into initial blocks, but not to + /* Compute heap size & free space when half direct blocks allocated */ + heap_size = 0; + free_space = 0; + row = 0; + do{ + heap_size += cparam->managed.width * DBLOCK_SIZE(fh, row); + free_space += cparam->managed.width * DBLOCK_FREE(fh, row); + row++; + } while(row < (num_direct_rows / 2)); + + /* Insert object to extend root block to middle of root direct blocks + */ + obj_size = (DBLOCK_SIZE(fh, row - 1) / 2) + 1; + if(add_obj(fh, dxpl, heap_size, &free_space, &nobjs, 10, obj_size)) + FAIL_STACK_ERROR + + /* Compute heap size & free space when all direct blocks allocated */ + do{ + heap_size += cparam->managed.width * DBLOCK_SIZE(fh, row); + free_space += cparam->managed.width * DBLOCK_FREE(fh, row); + row++; + } while(row < num_direct_rows); + + /* Insert large objects into last row of direct blocks in root indirect + * block, to force extension of root indirect block that covers the first + * row of indirect blocks in root indirect block + */ + obj_size = (cparam->managed.max_direct_size / 2) + 1; + for(v = 0; v < cparam->managed.width; v++) + if(add_obj(fh, dxpl, heap_size, &free_space, &nobjs, 20, obj_size)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Compute heap size & free space when root indirect block doubles again */ + do{ + heap_size += cparam->managed.width * DBLOCK_SIZE(fh, row); + free_space += cparam->managed.width * DBLOCK_FREE(fh, row); + row++; + } while(row < (2 * num_direct_rows)); + + /* Insert large object, to force creation of indirect blocks with + * range of skipped blocks that are too small to hold the large object + */ + obj_size = (cparam->managed.max_direct_size / 2) + 1; + if(add_obj(fh, dxpl, heap_size, &free_space, &nobjs, 20, obj_size)) + FAIL_STACK_ERROR + + PASSED() + + /* Close the fractal heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Close the file */ + if(H5Fclose(file) < 0) + TEST_ERROR + + /* All tests passed */ + return(0); + +error: + H5E_BEGIN_TRY { + if(fh) + H5HF_close(fh, dxpl); + H5Fclose(file); + } H5E_END_TRY; + return(1); +} /* test_abs_skip_direct_skip_indirect_two_rows_add_skipped() */ +#endif /* QAK */ + +#ifndef QAK + +/*------------------------------------------------------------------------- + * Function: test_abs_frag_simple + * + * Purpose: Test inserting small object to create root direct block, then + * insert objects small enough to fit into first row of direct + * blocks, but not to share a block with another object, until + * initial-block-size * 2 blocks are reached. Then, go back and + * fill in the space in the blocks skipped. + * + * Return: Success: 0 + * + * Failure: 1 + * + * Programmer: Quincey Koziol + * Tuesday, April 18, 2006 + * + *------------------------------------------------------------------------- + */ +static int +test_abs_frag_simple(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) +{ + hid_t file = -1; /* File ID */ + hid_t dxpl = H5P_DATASET_XFER_DEFAULT; /* DXPL to use */ + char filename[1024]; /* Filename to use */ + H5F_t *f = NULL; /* Internal file object pointer */ + H5HF_t *fh = NULL; /* Fractal heap wrapper */ + haddr_t fh_addr; /* Address of fractal heap */ + size_t id_len; /* Size of fractal heap IDs */ + unsigned nobjs = 0; /* Number of objects inserted */ + size_t obj_size; /* Size of object */ + hsize_t free_space; /* Size of free space in heap */ + hsize_t heap_size; /* Total size of heap */ + unsigned u; /* Local index variables */ + + /* Set the filename to use for this test (dependent on fapl) */ + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); + + /* Create the file to work on */ + if((file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) + TEST_ERROR + + /* Get a pointer to the internal file object */ + if(NULL == (f = H5I_object(file))) + STACK_ERROR + + /* Create absolute heap */ + if(NULL == (fh = H5HF_create(f, H5P_DATASET_XFER_DEFAULT, cparam))) + FAIL_STACK_ERROR + if(H5HF_get_id_len(fh, &id_len) < 0) + FAIL_STACK_ERROR + if(id_len > HEAP_ID_LEN) + FAIL_STACK_ERROR + if(H5HF_get_heap_addr(fh, &fh_addr) < 0) + FAIL_STACK_ERROR + if(!H5F_addr_defined(fh_addr)) + FAIL_STACK_ERROR + + /* + * Test absolute heap + */ + TESTING("fragmenting small blocks, then backfill and extend"); + + /* Insert objects small enough to fit into initial blocks, but not to * share them with other objects of the same size, until the next larger * block size is reached. */ @@ -9458,6 +10009,7 @@ error: } /* test_abs_frag_3rd_direct() */ #endif /* QAK */ +#ifndef QAK /*------------------------------------------------------------------------- * Function: test_abs_random_managed @@ -9487,8 +10039,8 @@ test_abs_random_managed(hsize_t size_limit, hid_t fapl, H5HF_create_t *cparam, f unsigned long seed; /* Random # seed */ size_t num_ids = 0; /* # of heap IDs in array */ size_t alloc_ids = 0; /* # of heap IDs allocated in array */ - unsigned char *obj; /* Buffer for object to insert */ - unsigned char *robj; /* Buffer for reading object */ + unsigned char *obj = NULL; /* Buffer for object to insert */ + unsigned char *robj = NULL; /* Buffer for reading object */ hsize_t total_obj_added; /* Size of objects added */ size_t obj_size; /* Size of object */ size_t obj_loc; /* Location of object in buffer */ @@ -9541,16 +10093,14 @@ HDfprintf(stderr, "Random # seed was: %lu\n", seed); /* Loop over adding objects to the heap, until the size limit is reached */ total_obj_added = 0; while(total_obj_added < size_limit) { - /* Choose a random size of object (non-zero) */ - do { - obj_size = HDrandom() % cparam->standalone_size; - } while(obj_size == 0); -#ifdef QAK -HDfprintf(stderr, "total_obj_added = %Hu, obj_size = %Zu\n", total_obj_added, obj_size); -#endif /* QAK */ + /* Choose a random size of object (from 1 up to stand alone block size) */ + obj_size = (HDrandom() % (cparam->standalone_size - 1)) + 1; /* Increment object count */ num_ids++; +#ifdef QAK +HDfprintf(stderr, "num_ids = %Zu, total_obj_added = %Hu, obj_size = %Zu\n", num_ids, total_obj_added, obj_size); +#endif /* QAK */ /* Check for needing to increase size of heap ID array */ if(num_ids > alloc_ids) { @@ -9632,95 +10182,555 @@ error: /*------------------------------------------------------------------------- - * Function: main + * Function: test_abs_random_pow2_managed * - * Purpose: Test the fractal heap code + * Purpose: Test inserting random sized objects (that are smaller than the + * standalone size) with a "power of 2 distribution" into a heap, + * and read them back. * - * Return: Success: + * Return: Success: 0 * - * Failure: + * Failure: 1 * * Programmer: Quincey Koziol - * Friday, February 24, 2006 + * Monday, May 15, 2006 * *------------------------------------------------------------------------- */ -int -main(void) +static int +test_abs_random_pow2_managed(hsize_t size_limit, hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) { - fheap_test_param_t tparam; /* Testing parameters */ - H5HF_create_t cparam; /* Creation parameters for heap */ - hid_t fapl = -1; /* File access property list for data files */ - fheap_test_type_t curr_test; /* Current test being worked on */ - unsigned nerrors = 0; /* Cumulative error count */ + hid_t file = -1; /* File ID */ + hid_t dxpl = H5P_DATASET_XFER_DEFAULT; /* DXPL to use */ + char filename[1024]; /* Filename to use */ + H5F_t *f = NULL; /* Internal file object pointer */ + H5HF_t *fh = NULL; /* Fractal heap wrapper */ + haddr_t fh_addr; /* Address of fractal heap */ + size_t id_len; /* Size of fractal heap IDs */ + unsigned long seed; /* Random # seed */ + size_t num_ids = 0; /* # of heap IDs in array */ + size_t alloc_ids = 0; /* # of heap IDs allocated in array */ + unsigned char *obj = NULL; /* Buffer for object to insert */ + unsigned char *robj = NULL; /* Buffer for reading object */ + hsize_t total_obj_added; /* Size of objects added */ + size_t obj_size; /* Size of object */ + size_t obj_loc; /* Location of object in buffer */ + unsigned char *ids = NULL; /* Array of heap IDs */ + unsigned u; /* Local index variables */ - /* Reset library */ - h5_reset(); - fapl = h5_fileaccess(); + /* Set the filename to use for this test (dependent on fapl) */ + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); - /* Initialize heap's creation parameters */ - init_small_cparam(&cparam); + /* Create the file to work on */ + if((file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) + TEST_ERROR - /* Iterate over the testing parameters */ -#ifndef QAK - for(curr_test = FHEAP_TEST_NORMAL; curr_test < FHEAP_TEST_NTESTS; curr_test++) { -#else /* QAK */ -HDfprintf(stderr, "Uncomment test loop!\n"); -/* curr_test = FHEAP_TEST_NORMAL; */ -curr_test = FHEAP_TEST_REOPEN; + /* Get a pointer to the internal file object */ + if(NULL == (f = H5I_object(file))) + STACK_ERROR + + /* Create absolute heap */ + if(NULL == (fh = H5HF_create(f, H5P_DATASET_XFER_DEFAULT, cparam))) + FAIL_STACK_ERROR + if(H5HF_get_id_len(fh, &id_len) < 0) + FAIL_STACK_ERROR + if(id_len > HEAP_ID_LEN) + FAIL_STACK_ERROR + if(H5HF_get_heap_addr(fh, &fh_addr) < 0) + FAIL_STACK_ERROR + if(!H5F_addr_defined(fh_addr)) + FAIL_STACK_ERROR +#ifdef QAK +HDfprintf(stderr, "Fractal heap header address: %a\n", fh_addr); #endif /* QAK */ - /* Clear the testing parameters */ - HDmemset(&tparam, 0, sizeof(fheap_test_param_t)); - /* Set appropriate testing parameters for each test */ - switch(curr_test) { - /* "Normal" testing parameters */ - case FHEAP_TEST_NORMAL: - puts("Testing with normal parameters"); - break; + /* + * Test absolute heap + */ + TESTING("inserting random-sized objects with power of 2 distribution (smaller than standalone size)"); - /* "Re-open heap" testing parameters */ - case FHEAP_TEST_REOPEN: - puts("Testing with reopen heap flag set"); - tparam.reopen_heap = TRUE; - break; + /* Choose random # seed */ + seed = (unsigned long)HDtime(NULL); +#ifdef QAK +HDfprintf(stderr, "Random # seed was: %lu\n", seed); +#endif /* QAK */ + HDsrandom(seed); - /* An unknown test? */ - default: - goto error; - } /* end switch */ + /* Initialize the buffer for objects to insert */ + obj = H5MM_malloc(cparam->standalone_size); + for(u = 0; u < cparam->standalone_size; u++) + obj[u] = (unsigned char)u; - /* Test fractal heap creation */ - nerrors += test_create(fapl, &cparam, &tparam); - nerrors += test_reopen(fapl, &cparam, &tparam); + /* Loop over adding objects to the heap, until the size limit is reached */ + total_obj_added = 0; + while(total_obj_added < size_limit) { + unsigned size_range = 10; /* Object size range */ - /* - * Test fractal heap object insertion + /* Determine the size of the range for this object */ + /* (50% of the objects inserted will use the initial size range, + * 25% of the objects will be twice as large, 12.5% will be + * four times larger, etc.) */ -#ifdef ALL_INSERT_TESTS - /* Simple insertion */ - nerrors += test_abs_insert_first(fapl, &cparam, &tparam); - nerrors += test_abs_insert_second(fapl, &cparam, &tparam); - nerrors += test_abs_insert_root_mult(fapl, &cparam, &tparam); - nerrors += test_abs_insert_force_indirect(fapl, &cparam, &tparam); - nerrors += test_abs_insert_fill_second(fapl, &cparam, &tparam); - nerrors += test_abs_insert_third_direct(fapl, &cparam, &tparam); - nerrors += test_abs_fill_first_row(fapl, &cparam, &tparam); - nerrors += test_abs_start_second_row(fapl, &cparam, &tparam); - nerrors += test_abs_fill_second_row(fapl, &cparam, &tparam); - nerrors += test_abs_start_third_row(fapl, &cparam, &tparam); - nerrors += test_abs_fill_fourth_row(fapl, &cparam, &tparam); - nerrors += test_abs_fill_all_root_direct(fapl, &cparam, &tparam); - nerrors += test_abs_first_recursive_indirect(fapl, &cparam, &tparam); - nerrors += test_abs_second_direct_recursive_indirect(fapl, &cparam, &tparam); - nerrors += test_abs_fill_first_recursive_indirect(fapl, &cparam, &tparam); - nerrors += test_abs_second_recursive_indirect(fapl, &cparam, &tparam); - nerrors += test_abs_fill_second_recursive_indirect(fapl, &cparam, &tparam); - nerrors += test_abs_fill_recursive_indirect_row(fapl, &cparam, &tparam); - nerrors += test_abs_start_2nd_recursive_indirect(fapl, &cparam, &tparam); - nerrors += test_abs_recursive_indirect_two_deep(fapl, &cparam, &tparam); - nerrors += test_abs_start_3rd_recursive_indirect(fapl, &cparam, &tparam); - nerrors += test_abs_fill_first_3rd_recursive_indirect(fapl, &cparam, &tparam); + while(HDrandom() < (RAND_MAX / 2) && size_range < cparam->standalone_size) + size_range *= 2; + if(size_range > cparam->standalone_size) + size_range = cparam->standalone_size; + + /* Choose a random size of object (from 1 up to stand alone block size) */ + obj_size = (HDrandom() % (size_range - 1)) + 1; + + /* Increment object count */ + num_ids++; +#ifdef QAK +if((num_ids % 100000) == 1) + HDfprintf(stderr, "num_ids = %Zu, total_obj_added = %Hu, obj_size = %Zu\n", num_ids, total_obj_added, obj_size); +#endif /* QAK */ + + /* Check for needing to increase size of heap ID array */ + if(num_ids > alloc_ids) { + alloc_ids = MAX(1024, (alloc_ids * 2)); + if(NULL == (ids = H5MM_realloc(ids, HEAP_ID_LEN * alloc_ids))) + FAIL_STACK_ERROR + } /* end if */ + + /* Insert object */ + obj_loc = cparam->standalone_size - obj_size; + if(H5HF_insert(fh, dxpl, obj_size, &obj[obj_loc], &ids[(num_ids - 1) * HEAP_ID_LEN]) < 0) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Increment the amount of objects added */ + total_obj_added += obj_size; + } /* end while */ + + /* Allocate buffer for reading objects */ + robj = H5MM_malloc(cparam->standalone_size); + + /* Verify reading the objects written out */ + for(u = 0; u < num_ids; u++) { + /* Get object length */ + if(H5HF_get_obj_len(fh, &ids[u * HEAP_ID_LEN], &obj_size) < 0) + FAIL_STACK_ERROR + + /* Clear read buffer */ + HDmemset(robj, 0, obj_size); + + /* Read in object */ + if(H5HF_read(fh, dxpl, &ids[u * HEAP_ID_LEN], robj) < 0) + FAIL_STACK_ERROR + + /* Check for correct object */ + obj_loc = cparam->standalone_size - obj_size; + if(HDmemcmp(&obj[obj_loc], robj, obj_size)) + FAIL_STACK_ERROR + } /* end for */ + + PASSED() + + /* Close the fractal heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Close the file */ + if(H5Fclose(file) < 0) + TEST_ERROR + + /* All tests passed */ + H5MM_xfree(obj); + H5MM_xfree(robj); + H5MM_xfree(ids); + return(0); + +error: + H5E_BEGIN_TRY { + if(fh) + H5HF_close(fh, dxpl); + H5Fclose(file); + H5MM_xfree(obj); + H5MM_xfree(robj); + H5MM_xfree(ids); + } H5E_END_TRY; + HDfprintf(stderr, "Random # seed was: %lu\n", seed); + return(1); +} /* test_abs_random_pow2_managed() */ +#endif /* QAK */ + +#ifndef QAK + +/*------------------------------------------------------------------------- + * Function: test_abs_remove_bogus + * + * Purpose: Test removing bogus heap IDs + * + * Return: Success: 0 + * + * Failure: 1 + * + * Programmer: Quincey Koziol + * Monday, May 15, 2006 + * + *------------------------------------------------------------------------- + */ +static int +test_abs_remove_bogus(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) +{ + hid_t file = -1; /* File ID */ + hid_t dxpl = H5P_DATASET_XFER_DEFAULT; /* DXPL to use */ + char filename[1024]; /* Filename to use */ + H5F_t *f = NULL; /* Internal file object pointer */ + H5HF_t *fh = NULL; /* Fractal heap wrapper */ + haddr_t fh_addr; /* Address of fractal heap */ + unsigned char heap_id[HEAP_ID_LEN]; /* Heap ID for object */ + size_t id_len; /* Size of fractal heap IDs */ + unsigned nobjs = 0; /* Number of objects inserted */ + hsize_t free_space; /* Size of free space in heap */ + hsize_t heap_size; /* Total size of heap */ + hsize_t obj_off; /* Offset of object in heap */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Set the filename to use for this test (dependent on fapl) */ + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); + + /* Create the file to work on */ + if((file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) + TEST_ERROR + + /* Get a pointer to the internal file object */ + if(NULL == (f = H5I_object(file))) + STACK_ERROR + + /* Create absolute heap */ + if(NULL == (fh = H5HF_create(f, dxpl, cparam))) + FAIL_STACK_ERROR + if(H5HF_get_id_len(fh, &id_len) < 0) + FAIL_STACK_ERROR + if(id_len > HEAP_ID_LEN) + FAIL_STACK_ERROR + if(H5HF_get_heap_addr(fh, &fh_addr) < 0) + FAIL_STACK_ERROR + if(!H5F_addr_defined(fh_addr)) + FAIL_STACK_ERROR + if(check_stats(fh, (hsize_t)0, (hsize_t)0, (hsize_t)0, (hsize_t)0, (hsize_t)0)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close (empty) heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* + * Test removing bogus IDs from heap + */ + TESTING("removing bad heap IDs from absolute heap"); + + /* Set heap ID to random (non-null) value */ + for(u = 0; u < HEAP_ID_LEN; u++) + heap_id[u] = HDrandom() + 1; + + /* Try removing bogus heap ID from empty heap */ + H5E_BEGIN_TRY { + ret = H5HF_remove(fh, dxpl, heap_id); + } H5E_END_TRY; + if(ret >= 0) + FAIL_STACK_ERROR + + /* Fill root direct blocks */ + heap_size = 0; + free_space = 0; + if(fill_root_direct(fh, dxpl, cparam, &heap_size, &free_space, &nobjs)) + FAIL_STACK_ERROR + + /* Get offset of random heap ID */ + if(H5HF_get_id_off_test(fh, heap_id, &obj_off) < 0) + FAIL_STACK_ERROR + + /* Make certain we can't accidentally use a valid heap ID */ + while(obj_off < heap_size) { + /* Set heap ID to random (non-null) value */ + for(u = 0; u < HEAP_ID_LEN; u++) + heap_id[u] = HDrandom() + 1; + + /* Get offset of random heap ID */ + if(H5HF_get_id_off_test(fh, heap_id, &obj_off) < 0) + FAIL_STACK_ERROR + } /* end while */ + + /* Try removing bogus heap ID from empty heap */ + H5E_BEGIN_TRY { + ret = H5HF_remove(fh, dxpl, heap_id); + } H5E_END_TRY; + if(ret >= 0) + FAIL_STACK_ERROR + + PASSED() + + /* Close the fractal heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Close the file */ + if(H5Fclose(file) < 0) + TEST_ERROR + + /* All tests passed */ + return(0); + +error: + H5E_BEGIN_TRY { + if(fh) + H5HF_close(fh, dxpl); + H5Fclose(file); + } H5E_END_TRY; + return(1); +} /* test_abs_remove_bogus() */ +#endif /* QAK */ + + +/*------------------------------------------------------------------------- + * Function: test_abs_remove_one + * + * Purpose: Test removing single object from heap + * + * Return: Success: 0 + * + * Failure: 1 + * + * Programmer: Quincey Koziol + * Monday, May 15, 2006 + * + *------------------------------------------------------------------------- + */ +static int +test_abs_remove_one(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) +{ + hid_t file = -1; /* File ID */ + hid_t dxpl = H5P_DATASET_XFER_DEFAULT; /* DXPL to use */ + char filename[1024]; /* Filename to use */ + H5F_t *f = NULL; /* Internal file object pointer */ + H5HF_t *fh = NULL; /* Fractal heap wrapper */ + haddr_t fh_addr; /* Address of fractal heap */ + unsigned char heap_id[HEAP_ID_LEN]; /* Heap ID for object */ + unsigned char obj[SMALL_OBJ_SIZE1]; /* Buffer for object to insert */ + size_t id_len; /* Size of fractal heap IDs */ + hsize_t free_space; /* Size of free space in heap */ + hsize_t heap_size; /* Total size of heap */ + unsigned u; /* Local index variable */ + + /* Set the filename to use for this test (dependent on fapl) */ + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); + + /* Create the file to work on */ + if((file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) + TEST_ERROR + + /* Get a pointer to the internal file object */ + if(NULL == (f = H5I_object(file))) + STACK_ERROR + + /* Create absolute heap */ + if(NULL == (fh = H5HF_create(f, dxpl, cparam))) + FAIL_STACK_ERROR + if(H5HF_get_id_len(fh, &id_len) < 0) + FAIL_STACK_ERROR + if(id_len > HEAP_ID_LEN) + FAIL_STACK_ERROR + if(H5HF_get_heap_addr(fh, &fh_addr) < 0) + FAIL_STACK_ERROR + if(!H5F_addr_defined(fh_addr)) + FAIL_STACK_ERROR + if(check_stats(fh, (hsize_t)0, (hsize_t)0, (hsize_t)0, (hsize_t)0, (hsize_t)0)) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close (empty) heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* + * Test removing first (small) object from absolute heap + */ + TESTING("removing single object from absolute heap"); + + /* Initialize the buffer for objects to insert */ + for(u = 0; u < sizeof(obj); u++) + obj[u] = u; + + /* Insert object into heap */ + if(H5HF_insert(fh, dxpl, sizeof(obj), obj, &heap_id) < 0) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close (empty) heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Check up on heap... */ + heap_size = DBLOCK_SIZE(fh, 0); + free_space = DBLOCK_FREE(fh, 0) - sizeof(obj); + if(check_stats(fh, heap_size, heap_size, (hsize_t)0, free_space, (hsize_t)1)) + FAIL_STACK_ERROR + + /* Remove object from heap */ + if(H5HF_remove(fh, dxpl, heap_id) < 0) + FAIL_STACK_ERROR + + /* Check for closing & re-opening the heap */ + if(tparam->reopen_heap) { + /* Close (empty) heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Re-open heap */ + if(NULL == (fh = H5HF_open(f, dxpl, fh_addr))) + FAIL_STACK_ERROR + } /* end if */ + + /* Check up on heap... */ + if(check_stats(fh, (hsize_t)0, (hsize_t)0, (hsize_t)0, (hsize_t)0, (hsize_t)0)) + FAIL_STACK_ERROR + + PASSED() + + /* Close the fractal heap */ + if(H5HF_close(fh, dxpl) < 0) + TEST_ERROR + + /* Close the file */ + if(H5Fclose(file) < 0) + TEST_ERROR + + /* All tests passed */ + return(0); + +error: + H5E_BEGIN_TRY { + if(fh) + H5HF_close(fh, dxpl); + H5Fclose(file); + } H5E_END_TRY; + return(1); +} /* test_abs_remove_one() */ + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Test the fractal heap code + * + * Return: Success: + * + * Failure: + * + * Programmer: Quincey Koziol + * Friday, February 24, 2006 + * + *------------------------------------------------------------------------- + */ +int +main(void) +{ + fheap_test_param_t tparam; /* Testing parameters */ + H5HF_create_t cparam; /* Creation parameters for heap */ + hid_t fapl = -1; /* File access property list for data files */ + fheap_test_type_t curr_test; /* Current test being worked on */ + unsigned nerrors = 0; /* Cumulative error count */ + + /* Reset library */ + h5_reset(); + fapl = h5_fileaccess(); + + /* Initialize heap's creation parameters */ + init_small_cparam(&cparam); + + /* Iterate over the testing parameters */ +#ifndef QAK + for(curr_test = FHEAP_TEST_NORMAL; curr_test < FHEAP_TEST_NTESTS; curr_test++) { +#else /* QAK */ +HDfprintf(stderr, "Uncomment test loop!\n"); +curr_test = FHEAP_TEST_NORMAL; +/* curr_test = FHEAP_TEST_REOPEN; */ +#endif /* QAK */ + /* Clear the testing parameters */ + HDmemset(&tparam, 0, sizeof(fheap_test_param_t)); + + /* Set appropriate testing parameters for each test */ + switch(curr_test) { + /* "Normal" testing parameters */ + case FHEAP_TEST_NORMAL: + puts("Testing with normal parameters"); + break; + + /* "Re-open heap" testing parameters */ + case FHEAP_TEST_REOPEN: + puts("Testing with reopen heap flag set"); + tparam.reopen_heap = TRUE; + break; + + /* An unknown test? */ + default: + goto error; + } /* end switch */ + + /* Test fractal heap creation */ + nerrors += test_create(fapl, &cparam, &tparam); + nerrors += test_reopen(fapl, &cparam, &tparam); + + /* + * Test fractal heap object insertion + */ +#ifdef ALL_INSERT_TESTS + /* Simple insertion */ + nerrors += test_abs_insert_first(fapl, &cparam, &tparam); + nerrors += test_abs_insert_second(fapl, &cparam, &tparam); + nerrors += test_abs_insert_root_mult(fapl, &cparam, &tparam); + nerrors += test_abs_insert_force_indirect(fapl, &cparam, &tparam); + nerrors += test_abs_insert_fill_second(fapl, &cparam, &tparam); + nerrors += test_abs_insert_third_direct(fapl, &cparam, &tparam); + nerrors += test_abs_fill_first_row(fapl, &cparam, &tparam); + nerrors += test_abs_start_second_row(fapl, &cparam, &tparam); + nerrors += test_abs_fill_second_row(fapl, &cparam, &tparam); + nerrors += test_abs_start_third_row(fapl, &cparam, &tparam); + nerrors += test_abs_fill_fourth_row(fapl, &cparam, &tparam); + nerrors += test_abs_fill_all_root_direct(fapl, &cparam, &tparam); + nerrors += test_abs_first_recursive_indirect(fapl, &cparam, &tparam); + nerrors += test_abs_second_direct_recursive_indirect(fapl, &cparam, &tparam); + nerrors += test_abs_fill_first_recursive_indirect(fapl, &cparam, &tparam); + nerrors += test_abs_second_recursive_indirect(fapl, &cparam, &tparam); + nerrors += test_abs_fill_second_recursive_indirect(fapl, &cparam, &tparam); + nerrors += test_abs_fill_recursive_indirect_row(fapl, &cparam, &tparam); + nerrors += test_abs_start_2nd_recursive_indirect(fapl, &cparam, &tparam); + nerrors += test_abs_recursive_indirect_two_deep(fapl, &cparam, &tparam); + nerrors += test_abs_start_3rd_recursive_indirect(fapl, &cparam, &tparam); + nerrors += test_abs_fill_first_3rd_recursive_indirect(fapl, &cparam, &tparam); nerrors += test_abs_fill_3rd_recursive_indirect_row(fapl, &cparam, &tparam); nerrors += test_abs_fill_all_3rd_recursive_indirect(fapl, &cparam, &tparam); nerrors += test_abs_start_4th_recursive_indirect(fapl, &cparam, &tparam); @@ -9745,6 +10755,7 @@ HDfprintf(stderr, "Uncomment tests!\n"); nerrors += test_abs_skip_2nd_block(fapl, &cparam, &tparam); nerrors += test_abs_skip_2nd_block_add_skipped(fapl, &cparam, &tparam); nerrors += test_abs_fill_one_partial_skip_2nd_block_add_skipped(fapl, &cparam, &tparam); + nerrors += test_abs_fill_row_skip_add_skipped(fapl, &cparam, &tparam); nerrors += test_abs_fill_direct_skip_indirect_start_block_add_skipped(fapl, &cparam, &tparam); nerrors += test_abs_fill_direct_skip_2nd_indirect_start_block_add_skipped(fapl, &cparam, &tparam); nerrors += test_abs_fill_2nd_direct_less_one_wrap_start_block_add_skipped(fapl, &cparam, &tparam); @@ -9753,6 +10764,7 @@ HDfprintf(stderr, "Uncomment tests!\n"); nerrors += test_abs_fill_2nd_direct_skip_start_block_add_skipped(fapl, &cparam, &tparam); nerrors += test_abs_fill_2nd_direct_skip_2nd_indirect_start_block_add_skipped(fapl, &cparam, &tparam); nerrors += test_abs_fill_2nd_direct_fill_direct_skip_3rd_indirect_start_block_add_skipped(fapl, &cparam, &tparam); + nerrors += test_abs_fill_2nd_direct_fill_direct_skip2_3rd_indirect_start_block_add_skipped(fapl, &cparam, &tparam); nerrors += test_abs_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped(fapl, &cparam, &tparam); nerrors += test_abs_fill_1st_row_3rd_direct_fill_2nd_direct_less_one_wrap_start_block_add_skipped(fapl, &cparam, &tparam); nerrors += test_abs_fill_3rd_direct_fill_direct_skip_start_block_add_skipped(fapl, &cparam, &tparam); @@ -9764,6 +10776,13 @@ HDfprintf(stderr, "Uncomment tests!\n"); HDfprintf(stderr, "Uncomment tests!\n"); #endif /* QAK */ + /* Additional skipped block insertion tests */ +#ifndef QAK + nerrors += test_abs_skip_direct_skip_indirect_two_rows_add_skipped(fapl, &cparam, &tparam); +#else /* QAK */ +HDfprintf(stderr, "Uncomment tests!\n"); +#endif /* QAK */ + /* Fragmented block insertion */ #ifndef QAK nerrors += test_abs_frag_simple(fapl, &cparam, &tparam); @@ -9775,7 +10794,23 @@ HDfprintf(stderr, "Uncomment tests!\n"); #endif /* QAK */ /* Random object insertion */ - nerrors += test_abs_random_managed((hsize_t)1000000, fapl, &cparam, &tparam); +#ifndef QAK + nerrors += test_abs_random_managed((hsize_t)(100*1000*1000), fapl, &cparam, &tparam); + nerrors += test_abs_random_pow2_managed((hsize_t)(100*1000*1000), fapl, &cparam, &tparam); +#else /* QAK */ +HDfprintf(stderr, "Uncomment tests!\n"); +#endif /* QAK */ + + /* + * Test fractal heap object deletion + */ + /* Simple removal */ +#ifndef QAK + nerrors += test_abs_remove_bogus(fapl, &cparam, &tparam); +#else /* QAK */ +HDfprintf(stderr, "Uncomment tests!\n"); +#endif /* QAK */ + nerrors += test_abs_remove_one(fapl, &cparam, &tparam); #ifndef QAK } /* end for */ #endif /* QAK */ -- cgit v0.12