diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/H5Edefin.h | 2 | ||||
-rw-r--r-- | src/H5Einit.h | 10 | ||||
-rw-r--r-- | src/H5Epubgen.h | 4 | ||||
-rw-r--r-- | src/H5Eterm.h | 4 | ||||
-rw-r--r-- | src/H5FS.c | 379 | ||||
-rw-r--r-- | src/H5FSdbg.c | 39 | ||||
-rw-r--r-- | src/H5FSpkg.h | 28 | ||||
-rw-r--r-- | src/H5FSprivate.h | 43 | ||||
-rw-r--r-- | src/H5HF.c | 10 | ||||
-rw-r--r-- | src/H5HFcache.c | 45 | ||||
-rw-r--r-- | src/H5HFdbg.c | 20 | ||||
-rw-r--r-- | src/H5HFdblock.c | 184 | ||||
-rw-r--r-- | src/H5HFdtable.c | 39 | ||||
-rw-r--r-- | src/H5HFhdr.c | 766 | ||||
-rw-r--r-- | src/H5HFiblock.c | 1107 | ||||
-rw-r--r-- | src/H5HFint.c | 91 | ||||
-rw-r--r-- | src/H5HFiter.c | 113 | ||||
-rw-r--r-- | src/H5HFpkg.h | 101 | ||||
-rw-r--r-- | src/H5HFprivate.h | 14 | ||||
-rw-r--r-- | src/H5HFsection.c | 1126 | ||||
-rw-r--r-- | src/H5HFspace.c | 56 | ||||
-rw-r--r-- | src/H5HFstat.c | 4 | ||||
-rw-r--r-- | src/H5HFtest.c | 121 | ||||
-rw-r--r-- | src/H5err.txt | 2 |
24 files changed, 2918 insertions, 1390 deletions
diff --git a/src/H5Edefin.h b/src/H5Edefin.h index d10ec5f..f297a50 100644 --- a/src/H5Edefin.h +++ b/src/H5Edefin.h @@ -74,6 +74,8 @@ hid_t H5E_CANTGETSIZE_g = FAIL; /* Unable to compute size */ hid_t H5E_CANTRESTORE_g = FAIL; /* Can't restore condition */ hid_t H5E_CANTCOMPUTE_g = FAIL; /* Can't compute value */ hid_t H5E_CANTEXTEND_g = FAIL; /* Can't extend heap's space */ +hid_t H5E_CANTATTACH_g = FAIL; /* Can't attach object */ +hid_t H5E_CANTUPDATE_g = FAIL; /* Can't update object */ /* Function entry/exit interface errors */ hid_t H5E_CANTINIT_g = FAIL; /* Unable to initialize object */ diff --git a/src/H5Einit.h b/src/H5Einit.h index c6909d2..aedbac3 100644 --- a/src/H5Einit.h +++ b/src/H5Einit.h @@ -264,6 +264,16 @@ if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't extend heap's space"))==NULL) HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") if((H5E_CANTEXTEND_g = H5I_register(H5I_ERROR_MSG, msg))<0) HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +assert(H5E_CANTATTACH_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't attach object"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_CANTATTACH_g = H5I_register(H5I_ERROR_MSG, msg))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +assert(H5E_CANTUPDATE_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "Can't update object"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_CANTUPDATE_g = H5I_register(H5I_ERROR_MSG, msg))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") /* Function entry/exit interface errors */ assert(H5E_CANTINIT_g==(-1)); diff --git a/src/H5Epubgen.h b/src/H5Epubgen.h index 01ed436..b989db7 100644 --- a/src/H5Epubgen.h +++ b/src/H5Epubgen.h @@ -122,9 +122,13 @@ H5_DLLVAR hid_t H5E_CANTGETSIZE_g; /* Unable to compute size */ #define H5E_CANTRESTORE (H5OPEN H5E_CANTRESTORE_g) #define H5E_CANTCOMPUTE (H5OPEN H5E_CANTCOMPUTE_g) #define H5E_CANTEXTEND (H5OPEN H5E_CANTEXTEND_g) +#define H5E_CANTATTACH (H5OPEN H5E_CANTATTACH_g) +#define H5E_CANTUPDATE (H5OPEN H5E_CANTUPDATE_g) H5_DLLVAR hid_t H5E_CANTRESTORE_g; /* Can't restore condition */ H5_DLLVAR hid_t H5E_CANTCOMPUTE_g; /* Can't compute value */ H5_DLLVAR hid_t H5E_CANTEXTEND_g; /* Can't extend heap's space */ +H5_DLLVAR hid_t H5E_CANTATTACH_g; /* Can't attach object */ +H5_DLLVAR hid_t H5E_CANTUPDATE_g; /* Can't update object */ /* Function entry/exit interface errors */ #define H5E_CANTINIT (H5OPEN H5E_CANTINIT_g) diff --git a/src/H5Eterm.h b/src/H5Eterm.h index 1643db9..c2c206e 100644 --- a/src/H5Eterm.h +++ b/src/H5Eterm.h @@ -75,7 +75,9 @@ H5E_CANTGETSIZE_g= /* Heap errors */ H5E_CANTRESTORE_g= H5E_CANTCOMPUTE_g= -H5E_CANTEXTEND_g= +H5E_CANTEXTEND_g= +H5E_CANTATTACH_g= +H5E_CANTUPDATE_g= /* Function entry/exit interface errors */ H5E_CANTINIT_g= @@ -71,12 +71,6 @@ typedef struct H5FS_node_t { H5SL_t *sect_list; /* Skip list to hold pointers to actual free list section node */ } H5FS_node_t; -/* Free space section bin info */ -typedef struct H5FS_bin_t { - size_t sect_count; /* Total # of sections in this bin */ - H5SL_t *bin_list; /* Skip list of differently sized sections */ -} H5FS_bin_t; - /* User data for skip list iterator callback for syncing section info */ typedef struct { H5F_t *f; /* Pointer to the file */ @@ -102,28 +96,6 @@ typedef struct { /* Package Typedefs */ /********************/ -/* Main free space info */ -struct H5FS_t { - /* Stored values (from header) */ - H5FS_hdr_t *hdr; /* Pointer to header info */ - - /* Computed/cached values */ - haddr_t addr; /* Address of free space header on disk */ - unsigned nbins; /* Number of bins */ - size_t serial_size; /* Total serialized size of all section nodes */ - size_t size_count; /* Number of differently sized sections */ - 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 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_t *merge_list; /* Skip list to hold sections for detecting merges */ - H5FS_bin_t *bins; /* Array of lists of lists of free sections */ -}; - /********************/ /* Local Prototypes */ @@ -133,9 +105,8 @@ 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); -static herr_t H5FS_add_bin_node(H5FS_t *fspace, H5FS_section_info_t *node); +static herr_t H5FS_sect_increase(H5FS_t *fspace); +static herr_t H5FS_sect_decrease(H5FS_t *fspace); static htri_t H5FS_find_bin_node(H5FS_t *fspace, hsize_t request, H5FS_section_info_t **node); static herr_t H5FS_serialize_sect_cb(void *_item, void UNUSED *key, void *_udata); static herr_t H5FS_serialize_node_cb(void *_item, void UNUSED *key, void *_udata); @@ -367,7 +338,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, - size_t nclasses, H5FS_section_class_t *classes, const void *cls_init_udata) + size_t nclasses, const 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 */ @@ -390,10 +361,17 @@ 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->sect_cls = classes; + if(NULL == (fspace->sect_cls = H5FL_SEQ_MALLOC(H5FS_section_class_t, nclasses))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space section class array ") /* Initialize the section classes for this free space list */ for(u = 0; u < nclasses; u++) { + /* Make certain that section class type can be used as an array index into this array */ + HDassert(u == classes[u]->type); + + /* Copy the class information into the free space manager */ + HDmemcpy(&fspace->sect_cls[u], classes[u], sizeof(H5FS_section_class_t)); + /* Call the class initialization routine, if there is one */ if(fspace->sect_cls[u].init_cls) if((fspace->sect_cls[u].init_cls)(&fspace->sect_cls[u], cls_init_udata) < 0) @@ -495,7 +473,7 @@ done: */ 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) + const 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 */ @@ -532,10 +510,17 @@ HDfprintf(stderr, "%s: Opening free space manager\n", FUNC); /* Set immutable free list parameters */ fspace->addr = fs_addr; HDassert(fspace->hdr->nclasses == nclasses); - fspace->sect_cls = classes; + if(NULL == (fspace->sect_cls = H5FL_SEQ_MALLOC(H5FS_section_class_t, nclasses))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space section class array ") /* Initialize the section classes for this free space list */ for(u = 0; u < nclasses; u++) { + /* Make certain that section class type can be used as an array index into this array */ + HDassert(u == classes[u]->type); + + /* Copy the class information into the free space manager */ + HDmemcpy(&fspace->sect_cls[u], classes[u], sizeof(H5FS_section_class_t)); + /* Call the class initialization routine, if there is one */ if(fspace->sect_cls[u].init_cls) if((fspace->sect_cls[u].init_cls)(&fspace->sect_cls[u], cls_init_udata) < 0) @@ -601,14 +586,11 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5FS_sect_increase(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) +H5FS_sect_increase(H5FS_t *fspace) { - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_increase) + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FS_sect_increase) /* Check arguments. */ - HDassert(f); HDassert(fspace); HDassert(fspace->hdr); @@ -618,8 +600,7 @@ 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); -done: - FUNC_LEAVE_NOAPI(ret_value) + FUNC_LEAVE_NOAPI(SUCCEED) } /* H5FS_sect_increase() */ @@ -639,14 +620,13 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5FS_sect_decrease(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) +H5FS_sect_decrease(H5FS_t *fspace) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_decrease) /* Check arguments. */ - HDassert(f); HDassert(fspace); HDassert(fspace->hdr); @@ -884,14 +864,15 @@ H5FS_sect_unlink_rest(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info 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; + fspace->serial_size -= fspace->sect_cls[sect->type].serial_size; #ifdef QAK +HDfprintf(stderr, "%s: fspace->hdr->tot_space = %Hu\n", FUNC, fspace->hdr->tot_space); 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); +HDfprintf(stderr, "%s: fspace->sect_cls[%u].serial_size = %Zu\n", FUNC, sect->type, fspace->sect_cls[sect->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) + if(H5FS_sect_decrease(fspace) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't increase free space section size on disk") /* Decrement amount of free space managed */ @@ -1121,10 +1102,9 @@ H5FS_sect_link_rest(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t HDassert(sect); /* Add section to the address-ordered list of sections */ - if(fspace->merge_list == NULL) { + 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") @@ -1133,10 +1113,10 @@ H5FS_sect_link_rest(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t 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; + fspace->serial_size += fspace->sect_cls[sect->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) + if(H5FS_sect_increase(fspace) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't increase free space section size on disk") /* Increment amount of free space managed */ @@ -1173,13 +1153,22 @@ H5FS_sect_link(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *sec HDassert(fspace); HDassert(sect); - /* Add node to size tracked data structures */ + /* Add section to size tracked data structures */ +#ifdef QAK +HDfprintf(stderr, "%s: Check 1.0 - fspace->hdr->tot_space = %Hu\n", FUNC, fspace->hdr->tot_space); +#endif /* QAK */ if(H5FS_sect_link_size(fspace, sect) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't add section to size tracking data structures") +#ifdef QAK +HDfprintf(stderr, "%s: Check 2.0 - fspace->hdr->tot_space = %Hu\n", FUNC, fspace->hdr->tot_space); +#endif /* QAK */ /* 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") +#ifdef QAK +HDfprintf(stderr, "%s: Check 3.0 - fspace->hdr->tot_space = %Hu\n", FUNC, fspace->hdr->tot_space); +#endif /* QAK */ done: FUNC_LEAVE_NOAPI(ret_value) @@ -1205,7 +1194,7 @@ 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 */ + H5FS_section_class_t *sect_cls = NULL; /* Section's class */ hbool_t merged; /* Flag to indicate merge occurred */ htri_t status; /* Status value */ herr_t ret_value = SUCCEED; /* Return value */ @@ -1221,6 +1210,9 @@ H5FS_sect_merge(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, /* Loop until no more merging */ do { + H5FS_section_class_t *tmp_sect_cls; /* Temporary section's class */ + H5FS_section_info_t *tmp_sect_node; /* Temporary free space section */ + /* Reset 'merge occurred' flag */ merged = FALSE; @@ -1228,27 +1220,32 @@ H5FS_sect_merge(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, 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; + if(tmp_sect_node) { + tmp_sect_cls = &fspace->sect_cls[tmp_sect_node->type]; /* Use class for left-most section */ + if(tmp_sect_cls->can_merge) { + /* Determine if the sections can merge */ + if((status = (*tmp_sect_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(tmp_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 */ + /* (rescan the class of the node, the 'can merge' callback can change it) */ + tmp_sect_cls = &fspace->sect_cls[tmp_sect_node->type]; /* Use class for left-most section */ + if((*tmp_sect_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 */ } /* end if */ @@ -1256,31 +1253,38 @@ H5FS_sect_merge(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, 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; + if(tmp_sect_node) { + tmp_sect_cls = &fspace->sect_cls[(*sect)->type]; /* Use class for left-most section */ + if(tmp_sect_cls->can_merge) { + /* Determine if the sections can merge */ + if((status = (*tmp_sect_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(tmp_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 */ + /* (rescan the class of the node, the 'can merge' callback can change it) */ + tmp_sect_cls = &fspace->sect_cls[(*sect)->type]; /* Use class for left-most section */ + if((*tmp_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 */ } /* end if */ } while(merged); + HDassert(*sect); /* 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) + sect_cls = &fspace->sect_cls[(*sect)->type]; + 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 @@ -1288,7 +1292,10 @@ 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) + /* (rescan the class of the node, the 'can shrink' callback can change it) */ + sect_cls = &fspace->sect_cls[(*sect)->type]; + HDassert(sect_cls->shrink); + 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 */ @@ -1321,7 +1328,7 @@ H5FS_add(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t *sect, 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); +HDfprintf(stderr, "%s: sect->size = %Hu, sect->addr = %a, sect->type = %u\n", FUNC, sect->size, sect->addr, sect->type); #endif /* QAK */ /* Check arguments. */ @@ -1341,11 +1348,17 @@ HDfprintf(stderr, "%s: Returning space\n", FUNC); HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't merge sections") } /* end if */ - /* Add new (possibly merged or even discarded) node to free sections */ + /* Add new (possibly merged) node to free sections data structures */ + /* (If section has been completely merged away or discarded, 'sect' will + * be NULL at this point - QAK) + */ 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") +#ifdef QAK +HDfprintf(stderr, "%s: fspace->hdr->tot_space = %Hu\n", FUNC, fspace->hdr->tot_space); +#endif /* QAK */ /* Mark free space sections as changed */ /* (if we're not deserializing all the sections) */ if(!(flags & H5FS_ADD_DESERIALIZING)) @@ -1517,16 +1530,18 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5FS_sect_free_cb(void *_sect, void UNUSED *key, void UNUSED *op_data) +H5FS_sect_free_cb(void *_sect, void UNUSED *key, void *op_data) { - H5FS_section_info_t *sect = (H5FS_section_info_t *)_sect; + H5FS_section_info_t *sect = (H5FS_section_info_t *)_sect; /* Section to free */ + const H5FS_t *fspace = (const H5FS_t *)op_data; /* Free space manager for section */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FS_sect_free_cb) HDassert(sect); + HDassert(fspace); /* Call the 'free' method for the section's class */ - (*sect->cls->free)(sect); + (*fspace->sect_cls[sect->type].free)(sect); FUNC_LEAVE_NOAPI(0) } /* H5FS_sect_free_cb() */ @@ -1547,16 +1562,17 @@ H5FS_sect_free_cb(void *_sect, void UNUSED *key, void UNUSED *op_data) *------------------------------------------------------------------------- */ static herr_t -H5FS_node_free_cb(void *item, void UNUSED *key, void UNUSED *op_data) +H5FS_node_free_cb(void *item, void UNUSED *key, void *op_data) { H5FS_node_t *fspace_node = (H5FS_node_t *)item; /* Temporary pointer to free space list node */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FS_node_free_cb) HDassert(fspace_node); + HDassert(op_data); /* Release the skip list for sections of this size */ - H5SL_destroy(fspace_node->sect_list, H5FS_sect_free_cb, NULL); + H5SL_destroy(fspace_node->sect_list, H5FS_sect_free_cb, op_data); /* Release free space list node */ H5FL_FREE(H5FS_node_t, fspace_node); @@ -1583,39 +1599,41 @@ H5FS_node_free_cb(void *item, void UNUSED *key, void UNUSED *op_data) static herr_t H5FS_serialize_sect_cb(void *_item, void UNUSED *key, void *_udata) { - H5FS_section_info_t *sect_info = (H5FS_section_info_t *)_item; /* Free space section to work on */ + H5FS_section_class_t *sect_cls; /* Class of section */ + H5FS_section_info_t *sect= (H5FS_section_info_t *)_item; /* Free space section to work on */ H5FS_iter_ud2_t *udata = (H5FS_iter_ud2_t *)_udata; /* Callback info */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5FS_serialize_sect_cb) /* Check arguments. */ - HDassert(sect_info); + HDassert(sect); HDassert(udata->fspace); HDassert(udata->p); /* The address of the section */ - UINT64ENCODE_VAR(*udata->p, sect_info->addr, udata->fspace->sect_off_size); + UINT64ENCODE_VAR(*udata->p, sect->addr, udata->fspace->sect_off_size); #ifdef QAK -HDfprintf(stderr, "%s: sect_info->addr = %a\n", FUNC, sect_info->addr); +HDfprintf(stderr, "%s: sect->addr = %a\n", FUNC, sect->addr); #endif /* QAK */ /* The type of this section */ - *(*udata->p)++ = (uint8_t)sect_info->cls->type; + *(*udata->p)++ = (uint8_t)sect->type; #ifdef QAK -HDfprintf(stderr, "%s: sect_info->cls->type = %u\n", FUNC, (unsigned)sect_info->cls->type); +HDfprintf(stderr, "%s: sect->type = %u\n", FUNC, (unsigned)sect->type); #endif /* QAK */ /* Call 'serialize' callback for this section */ - if(sect_info->cls->serialize) { - if((*sect_info->cls->serialize)(sect_info, *udata->p) < 0) + sect_cls = &udata->fspace->sect_cls[sect->type]; + if(sect_cls->serialize) { + if((*sect_cls->serialize)(sect, *udata->p) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTSERIALIZE, FAIL, "can't syncronize section") /* Update offset in serialization buffer */ - (*udata->p) += sect_info->cls->serial_size; + (*udata->p) += sect_cls->serial_size; } /* end if */ else - HDassert(sect_info->cls->serial_size == 0); + HDassert(sect_cls->serial_size == 0); done: FUNC_LEAVE_NOAPI(ret_value) @@ -1765,7 +1783,10 @@ HDfprintf(stderr, "%s: fspace->serial_size = %Zu\n", FUNC, fspace->serial_size); /* 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) +#ifdef QAK +HDfprintf(stderr, "%s: Releasing space for serialized sections\n", FUNC); +#endif /* QAK */ + if(H5MF_xfree(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, fspace->hdr->sect_addr, 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 */ @@ -1780,6 +1801,9 @@ HDfprintf(stderr, "%s: fspace->serial_size = %Zu\n", FUNC, fspace->serial_size); fspace->hdr->alloc_sect_size = (size_t)fspace->hdr->sect_size * (double)fspace->hdr->expand_percent / 100.0; /* Allocate space for the new serialized sections on disk */ +#ifdef QAK +HDfprintf(stderr, "%s: Allocating space for serialized sections\n", FUNC); +#endif /* QAK */ 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 */ @@ -1800,7 +1824,7 @@ HDfprintf(stderr, "%s: fspace->hdr->alloc_sect_size = %Hu\n", FUNC, fspace->hdr- * 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) + if(H5MF_xfree(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, fspace->hdr->sect_addr, fspace->hdr->alloc_sect_size)<0) HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, FAIL, "unable to free free space sections") /* Compute new size */ @@ -1810,6 +1834,9 @@ HDfprintf(stderr, "%s: fspace->hdr->alloc_sect_size = %Hu\n", FUNC, fspace->hdr- fspace->hdr->alloc_sect_size = new_size; /* Allocate space for the new serialized sections on disk */ +#ifdef QAK +HDfprintf(stderr, "%s: Allocating space for larger serialized sections, fspace->hdr->sect_size = %Hu\n", FUNC, fspace->hdr->sect_size); +#endif /* QAK */ 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 */ @@ -1836,7 +1863,7 @@ HDfprintf(stderr, "%s: fspace->hdr->alloc_sect_size = %Hu\n", FUNC, fspace->hdr- * 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) + if(H5MF_xfree(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, fspace->hdr->sect_addr, fspace->hdr->alloc_sect_size)<0) HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, FAIL, "unable to free free space sections") /* Compute new size */ @@ -1850,6 +1877,9 @@ HDfprintf(stderr, "%s: fspace->hdr->alloc_sect_size = %Hu\n", FUNC, fspace->hdr- fspace->hdr->alloc_sect_size = new_size; /* Allocate space for the new serialized sections on disk */ +#ifdef QAK +HDfprintf(stderr, "%s: Allocating space for smaller serialized sections\n", FUNC); +#endif /* QAK */ 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 */ @@ -1900,6 +1930,9 @@ HDfprintf(stderr, "%s: Serializing single section\n", FUNC); /* The size of the section */ UINT64ENCODE_VAR(p, fspace->single->size, fspace->sect_len_size); +#ifdef QAK +HDfprintf(stderr, "%s: fspace->single->size = %Hu\n", FUNC, fspace->single->size); +#endif /* QAK */ /* Serialize the single node */ if(H5FS_serialize_sect_cb(fspace->single, NULL, &udata) < 0) @@ -2020,8 +2053,9 @@ HDfprintf(stderr, "%s: fspace->hdr->sect_size = %Hu\n", FUNC, fspace->hdr->sect_ /* Check for any serialized sections */ if(fspace->hdr->sect_count > 0) { - hsize_t old_sect_count; /* Section count from header */ - unsigned sect_cnt_size; /* The size of the section size counts */ + hsize_t old_sect_count; /* Section count from header */ + hsize_t old_tot_space; /* Total space managed from header */ + unsigned sect_cnt_size; /* The size of the section size counts */ /* Compute the size of the section counts */ sect_cnt_size = MAX(1, (H5V_log2_gen(fspace->hdr->sect_count) + 7) / 8); @@ -2032,10 +2066,13 @@ HDfprintf(stderr, "%s: fspace->sect_len_size = %u\n", FUNC, fspace->sect_len_siz /* Reset the section count, the "add" routine will update it */ old_sect_count = fspace->hdr->sect_count; + old_tot_space = fspace->hdr->tot_space; #ifdef QAK HDfprintf(stderr, "%s: fspace->hdr->sect_count = %Hu\n", FUNC, fspace->hdr->sect_count); +HDfprintf(stderr, "%s: fspace->hdr->tot_space = %Hu\n", FUNC, fspace->hdr->tot_space); #endif /* QAK */ fspace->hdr->sect_count = 0; + fspace->hdr->tot_space = 0; /* Walk through the buffer, deserializing sections */ do { @@ -2077,12 +2114,11 @@ HDfprintf(stderr, "%s: sect_type = %u\n", FUNC, sect_type); /* Call 'deserialize' callback for this section */ HDassert(fspace->sect_cls[sect_type].deserialize); - if((*fspace->sect_cls[sect_type].deserialize)(fspace->sect_cls, p, sect_addr, sect_size, &new_sect) < 0) + if(NULL == (new_sect = (*fspace->sect_cls[sect_type].deserialize)(p, sect_addr, sect_size))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTDECODE, FAIL, "can't deserialize section") - HDassert(new_sect); /* Update offset in serialization buffer */ - p += new_sect->cls->serial_size; + p += fspace->sect_cls[sect_type].serial_size; /* Insert section in free space manager */ if(H5FS_add(f, dxpl_id, fspace, new_sect, H5FS_ADD_DESERIALIZING, NULL) < 0) @@ -2094,6 +2130,7 @@ HDfprintf(stderr, "%s: sect_type = %u\n", FUNC, sect_type); HDassert((size_t)(p - sect_buf) == old_sect_size); HDassert(old_sect_size == fspace->hdr->sect_size); HDassert(old_sect_count == fspace->hdr->sect_count); + HDassert(old_tot_space == fspace->hdr->tot_space); } /* end if */ done: @@ -2254,6 +2291,39 @@ done: /*------------------------------------------------------------------------- + * Function: H5FS_get_sect_count + * + * Purpose: Retrieve the number of sections managed + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Tuesday, May 30, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5FS_get_sect_count(const H5FS_t *fspace, hsize_t *nsects) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FS_get_sect_count, FAIL) + + /* Check arguments. */ + HDassert(fspace); + HDassert(nsects); + + /* Get the section count */ + *nsects = fspace->hdr->sect_count; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS_get_sect_count() */ + + +/*------------------------------------------------------------------------- * Function: H5FS_flush_cb * * Purpose: Skip list iterator callback to syncronize free space sections @@ -2333,6 +2403,64 @@ done: /*------------------------------------------------------------------------- + * Function: H5FS_delete + * + * Purpose: Delete a free space manager on disk + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Tuesday, May 30, 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5FS_delete(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr) +{ + H5FS_hdr_t *fs_hdr = NULL; /* Free space header loaded from file */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FS_delete, FAIL) +#ifdef QAK +HDfprintf(stderr, "%s: Deleting free space manager\n", FUNC); +#endif /* QAK */ + + /* Check arguments. */ + HDassert(f); + HDassert(H5F_addr_defined(fs_addr)); + + /* Protect the free space header */ + if(NULL == (fs_hdr = H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, NULL, NULL, H5AC_WRITE))) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space header") + + /* Delete serialized section storage, if there are any */ +#ifdef QAK +HDfprintf(stderr, "%s: fs_hdr->sect_addr = %a\n", FUNC, fs_hdr->sect_addr); +#endif /* QAK */ + if(fs_hdr->sect_count > 0) { + HDassert(H5F_addr_defined(fs_hdr->sect_addr)); + HDassert(fs_hdr->sect_size > 0); + if(H5MF_xfree(f, H5FD_MEM_FSPACE_SECTS, dxpl_id, fs_hdr->sect_addr, fs_hdr->alloc_sect_size)<0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to release free space sections") + } /* end if */ + + /* Release header's disk space */ + if(H5MF_xfree(f, H5FD_MEM_FSPACE_HDR, dxpl_id, fs_addr, (hsize_t)H5FS_HEADER_SIZE(f))<0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to release free space header") + + /* Release the free space header */ + if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, fs_hdr, H5AC__DELETED_FLAG) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space header") + fs_hdr = NULL; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS_delete() */ + + +/*------------------------------------------------------------------------- * Function: H5FS_close * * Purpose: Destroy & deallocate free list structure, serializing sections @@ -2370,7 +2498,8 @@ H5FS_close(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) /* Check for single section to free */ if(fspace->single) { - fspace->single->cls->free(fspace->single); + /* Call the 'free' callback for the section */ + (*fspace->sect_cls[fspace->single->type].free)(fspace->single); fspace->single = NULL; } /* end if */ HDassert(fspace->single == NULL); @@ -2380,7 +2509,7 @@ 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, NULL); + H5SL_destroy(fspace->bins[u].bin_list, H5FS_node_free_cb, fspace); fspace->bins[u].bin_list = NULL; } /* end if */ @@ -2388,15 +2517,17 @@ H5FS_close(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace) } /* end if */ /* Release skip list for merging sections */ - if(fspace->merge_list) { + 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") + /* Release the memory for the free space section classes */ + fspace->sect_cls = H5FL_SEQ_FREE(H5FS_section_class_t, fspace->sect_cls); + /* Free free space info */ H5FL_FREE(H5FS_t, fspace); diff --git a/src/H5FSdbg.c b/src/H5FSdbg.c index dcbc846..a946cf0 100644 --- a/src/H5FSdbg.c +++ b/src/H5FSdbg.c @@ -158,6 +158,45 @@ done: /*------------------------------------------------------------------------- + * Function: H5FS_sect_debug + * + * Purpose: Prints debugging info about a free space section. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 30 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5FS_sect_debug(const H5FS_t *fspace, const H5FS_section_info_t *sect, FILE *stream, int indent, int fwidth) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FS_sect_debug, FAIL) + + /* + * Check arguments. + */ + HDassert(fspace); + HDassert(sect); + HDassert(stream); + HDassert(indent >= 0); + HDassert(fwidth >= 0); + + /* Call the section's debugging routine */ + if(fspace->sect_cls[sect->type].debug) + if((fspace->sect_cls[sect->type].debug)(sect, stream, indent, fwidth) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't dump section's debugging info") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FS_sect_debug() */ + + +/*------------------------------------------------------------------------- * Function: H5FS_sects_debug * * Purpose: Prints debugging info about the free space sections. diff --git a/src/H5FSpkg.h b/src/H5FSpkg.h index 98a945e..0f9aaad 100644 --- a/src/H5FSpkg.h +++ b/src/H5FSpkg.h @@ -98,6 +98,34 @@ typedef struct H5FS_hdr_t { hsize_t alloc_sect_size; /* Allocated size of the section info in the file */ } H5FS_hdr_t; +/* Free space section bin info */ +typedef struct H5FS_bin_t { + size_t sect_count; /* Total # of sections in this bin */ + H5SL_t *bin_list; /* Skip list of differently sized sections */ +} H5FS_bin_t; + +/* Main free space info */ +struct H5FS_t { + /* Stored values (from header) */ + H5FS_hdr_t *hdr; /* Pointer to header info */ + + /* Computed/cached values */ + haddr_t addr; /* Address of free space header on disk */ + unsigned nbins; /* Number of bins */ + size_t serial_size; /* Total serialized size of all section nodes */ + size_t size_count; /* Number of differently sized sections */ + 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 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_t *merge_list; /* Skip list to hold sections for detecting merges */ + H5FS_bin_t *bins; /* Array of lists of lists of free sections */ +}; + /*****************************/ /* Package Private Variables */ diff --git a/src/H5FSprivate.h b/src/H5FSprivate.h index 3b9311b..281bb57 100644 --- a/src/H5FSprivate.h +++ b/src/H5FSprivate.h @@ -54,7 +54,7 @@ /* Library Private Typedefs */ /****************************/ -/* Free space info (forward decl - defined in H5FS.c) */ +/* Free space info (forward decl - defined in H5FSpkg.h) */ typedef struct H5FS_t H5FS_t; /* Forward declaration free space section info */ @@ -71,28 +71,27 @@ typedef struct H5FS_section_class_t { /* 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 */ + H5FS_section_info_t *(*deserialize)(const uint8_t *, haddr_t, hsize_t); /* Routine to deserialize a buffer into a "live" section */ + htri_t (*can_merge)(H5FS_section_info_t *, 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 */ + 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 */ + 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; +/* State of section ("live" or "serialized") */ +typedef enum H5FS_section_state_t { + H5FS_SECT_LIVE, /* Section has "live" memory references */ + H5FS_SECT_SERIALIZED /* Section is in "serialized" form */ +} H5FS_section_state_t; + /* Free space section info */ struct H5FS_section_info_t { - haddr_t addr; /* Address of free space section in the address space */ - /* (Not actually used as address, used as unique ID for free space node) */ - hsize_t size; /* Size of free space section */ - H5FS_section_class_t *cls; /* Class of free space section */ - enum { - H5FS_SECT_LIVE, /* Section has "live" memory references */ - H5FS_SECT_SERIALIZED} /* Section is in "serialized" form */ - state; /* Whether the section is in "serialized" or "live" form */ + haddr_t addr; /* Address of free space section in the address space */ + hsize_t size; /* Size of free space section */ + unsigned type; /* Type of free space section (i.e. class) */ + H5FS_section_state_t state; /* Whether the section is in "serialized" or "live" form */ }; /* Free space client IDs for identifying user of free space */ @@ -128,16 +127,22 @@ H5FL_SEQ_EXTERN(H5FS_section_class_t); /***************************************/ H5_DLL H5FS_t *H5FS_create(H5F_t *f, hid_t dxpl_id, haddr_t *fs_addr, const H5FS_create_t *fs_create, size_t nclasses, - H5FS_section_class_t *classes, const void *cls_init_udata); + const 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, - size_t nclasses, H5FS_section_class_t *classes, const void *cls_init_udata); + size_t nclasses, const 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_get_sect_count(const H5FS_t *fspace, hsize_t *nsects); H5_DLL herr_t H5FS_flush(H5F_t *f, hid_t dxpl_id, unsigned flags); +H5_DLL herr_t H5FS_delete(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr); H5_DLL herr_t H5FS_close(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace); +/* Debugging routines for dumping file structures */ +H5_DLL herr_t H5FS_sect_debug(const H5FS_t *fspace, const H5FS_section_info_t *sect, + FILE *stream, int indent, int fwidth); + #endif /* _H5FSprivate_H */ @@ -568,10 +568,20 @@ H5HF_close(H5HF_t *fh, hid_t dxpl_id) HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't remove group from list of open objects") /* Close the free space information */ + /* (Can't put this in header "destroy" routine, because it has + * pointers to indirect blocks in the heap, which would create + * a reference loop and the objects couldn't be removed from + * the metadata cache - QAK) + */ if(H5HF_space_close(fh->hdr, dxpl_id) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info") /* Reset the block iterator */ + /* (Can't put this in header "destroy" routine, because it has + * pointers to indirect blocks in the heap, which would create + * a reference loop and the objects couldn't be removed from + * the metadata cache - QAK) + */ if(H5HF_man_iter_reset(&fh->hdr->next_block) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator") diff --git a/src/H5HFcache.c b/src/H5HFcache.c index 8b59876..d896a3e 100644 --- a/src/H5HFcache.c +++ b/src/H5HFcache.c @@ -328,6 +328,7 @@ HDfprintf(stderr, "%s: Load heap header, addr = %a\n", FUNC, addr); H5F_DECODE_LENGTH(f, p, hdr->total_size); H5F_DECODE_LENGTH(f, p, hdr->man_size); H5F_DECODE_LENGTH(f, p, hdr->man_alloc_size); + H5F_DECODE_LENGTH(f, p, hdr->man_iter_off); H5F_DECODE_LENGTH(f, p, hdr->std_size); H5F_DECODE_LENGTH(f, p, hdr->nobjs); @@ -435,6 +436,7 @@ HDfprintf(stderr, "%s: Flushing heap header, addr = %a, destroy = %u\n", FUNC, a H5F_ENCODE_LENGTH(f, p, hdr->total_size); H5F_ENCODE_LENGTH(f, p, hdr->man_size); H5F_ENCODE_LENGTH(f, p, hdr->man_alloc_size); + H5F_ENCODE_LENGTH(f, p, hdr->man_iter_off); H5F_ENCODE_LENGTH(f, p, hdr->std_size); H5F_ENCODE_LENGTH(f, p, hdr->nobjs); @@ -917,7 +919,7 @@ HDfprintf(stderr, "%s: Load indirect block, addr = %a\n", FUNC, addr); iblock->rc = 0; iblock->nrows = *nrows; iblock->addr = addr; - iblock->dirty = FALSE; + iblock->nchildren = 0; /* Compute size of indirect block */ iblock->size = H5HF_MAN_INDIRECT_SIZE(iblock->hdr, iblock); @@ -985,6 +987,12 @@ HDfprintf(stderr, "%s: Load indirect block, addr = %a\n", FUNC, addr); /* Decode child block address */ H5F_addr_decode(f, &p, &(iblock->ents[u].addr)); + /* Count child blocks */ + if(H5F_addr_defined(iblock->ents[u].addr)) { + iblock->nchildren++; + iblock->max_child = u; + } /* end if */ + #ifdef LATER /* Decode direct & indirect blocks differently (later, when direct blocks can be compressed) */ if(u < (iblock->hdr->man_dtable.max_direct_rows * iblock->hdr->man_dtable.cparam.width)) @@ -995,8 +1003,9 @@ HDfprintf(stderr, "%s: iblock->ents[%Zu] = {%a}\n", FUNC, u, iblock->ents[u].add #endif /* QAK */ } /* end for */ - /* Sanity check */ + /* Sanity checks */ HDassert((size_t)(p - buf) == iblock->size); + HDassert(iblock->nchildren); /* indirect blocks w/no children should have been deleted */ /* Set return value */ ret_value = iblock; @@ -1042,13 +1051,14 @@ HDfprintf(stderr, "%s: Flushing indirect block, addr = %a, destroy = %u\n", FUNC HDassert(iblock); if(iblock->cache_info.is_dirty) { - H5HF_hdr_t *hdr; /* Shared fractal heap information */ - uint8_t *buf = NULL; /* Temporary buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t u; /* Local index variable */ - - /* Sanity check */ - HDassert(iblock->dirty); + H5HF_hdr_t *hdr; /* Shared fractal heap information */ + uint8_t *buf = NULL; /* Temporary buffer */ + uint8_t *p; /* Pointer into raw data buffer */ +#ifndef NDEBUG + unsigned nchildren = 0; /* Track # of children */ + unsigned max_child = 0; /* Track max. child entry used */ +#endif /* NDEBUG */ + size_t u; /* Local index variable */ /* Get the pointer to the shared heap header */ hdr = iblock->hdr; @@ -1096,6 +1106,15 @@ HDfprintf(stderr, "%s: iblock->ents[%Zu] = {%a}\n", FUNC, u, iblock->ents[u].add /* Encode child block address */ H5F_addr_encode(f, &p, iblock->ents[u].addr); +#ifndef NDEBUG + /* Count child blocks */ + if(H5F_addr_defined(iblock->ents[u].addr)) { + nchildren++; + if(u > max_child) + max_child = u; + } /* end if */ +#endif /* NDEBUG */ + #ifdef LATER /* Encode direct & indirect blocks differently (when direct blocks can be compressed) */ if(u < (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width)) @@ -1105,6 +1124,10 @@ HDfprintf(stderr, "%s: iblock->ents[%Zu] = {%a}\n", FUNC, u, iblock->ents[u].add /* Sanity check */ HDassert((size_t)(p - buf) == iblock->size); +#ifndef NDEBUG + HDassert(nchildren == iblock->nchildren); + HDassert(max_child == iblock->max_child); +#endif /* NDEBUG */ /* Write the indirect block */ if(H5F_block_write(f, H5FD_MEM_FHEAP_IBLOCK, addr, iblock->size, dxpl_id, buf) < 0) @@ -1114,7 +1137,6 @@ HDfprintf(stderr, "%s: iblock->ents[%Zu] = {%a}\n", FUNC, u, iblock->ents[u].add H5FL_BLK_FREE(indirect_block, buf); /* Reset dirty flags */ - iblock->dirty = FALSE; iblock->cache_info.is_dirty = FALSE; } /* end if */ @@ -1153,9 +1175,8 @@ H5HF_cache_iblock_dest(H5F_t UNUSED *f, H5HF_indirect_t *iblock) */ HDassert(iblock); HDassert(iblock->rc == 0); - HDassert(!iblock->dirty); #ifdef QAK -HDfprintf(stderr, "%s: Destroying indirect block\n", "H5HF_cache_iblock_dest"); +HDfprintf(stderr, "%s: Destroying indirect block\n", FUNC); #endif /* QAK */ /* Decrement reference count on shared info */ diff --git a/src/H5HFdbg.c b/src/H5HFdbg.c index 81faf1e..c8945fd 100644 --- a/src/H5HFdbg.c +++ b/src/H5HFdbg.c @@ -63,6 +63,7 @@ typedef struct { /* User data for free space section iterator callback */ typedef struct { + H5FS_t *fspace; /* Free space manager */ FILE *stream; /* Stream for output */ int indent; /* Indention amount */ int fwidth; /* Field width mount */ @@ -232,9 +233,12 @@ H5HF_hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, "Total managed space data block size:", hdr->man_size); HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth, - "Total managed space allocated data block size:", + "Total managed space allocated:", hdr->man_alloc_size); HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth, + "Offset of managed space iterator:", + hdr->man_iter_off); + HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth, "Total standalone space data block size:", hdr->std_size); HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth, @@ -628,17 +632,16 @@ H5HF_sects_debug_cb(const H5FS_section_info_t *_sect, void *_udata) sect->sect_info.size); HDfprintf(udata->stream, "%*s%-*s %s\n", udata->indent, "", udata->fwidth, "Section type:", - (sect->sect_info.cls->type == H5FS_SECT_FHEAP_SINGLE ? "single" : - (sect->sect_info.cls->type == H5FS_SECT_FHEAP_RANGE ? "range" : - (sect->sect_info.cls->type == H5FS_SECT_FHEAP_INDIRECT ? "indirect" : "unknown")))); + (sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE ? "single" : + (sect->sect_info.type == H5HF_FSPACE_SECT_RANGE ? "range" : + (sect->sect_info.type == H5HF_FSPACE_SECT_INDIRECT ? "indirect" : "unknown")))); HDfprintf(udata->stream, "%*s%-*s %s\n", udata->indent, "", udata->fwidth, "Section state:", (sect->sect_info.state == H5FS_SECT_LIVE ? "live" : "serialized")); - /* Call the section's debugging routine */ - if(sect->sect_info.cls->debug) - if((sect->sect_info.cls->debug)(_sect, udata->stream, udata->indent + 3, MAX(0, udata->fwidth - 3)) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_BADITER, FAIL, "can't dump section's debugging info") + /* Dump section-specific debugging information */ + if(H5FS_sect_debug(udata->fspace, _sect, udata->stream, udata->indent + 3, MAX(0, udata->fwidth - 3)) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_BADITER, FAIL, "can't dump section's debugging info") done: FUNC_LEAVE_NOAPI(ret_value) @@ -688,6 +691,7 @@ H5HF_sects_debug(H5F_t *f, hid_t dxpl_id, haddr_t fh_addr, HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space") /* Prepare user data for section iteration callback */ + udata.fspace = hdr->fspace; udata.stream = stream; udata.indent = indent; udata.fwidth = fwidth; diff --git a/src/H5HFdblock.c b/src/H5HFdblock.c index 88c4e90..a4f1815 100644 --- a/src/H5HFdblock.c +++ b/src/H5HFdblock.c @@ -92,8 +92,7 @@ H5FL_DEFINE(H5HF_direct_t); */ 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) + unsigned par_entry, haddr_t *addr_p, H5HF_free_section_t **ret_sec_node) { H5HF_free_section_t *sec_node; /* Pointer to free space section for block */ H5HF_direct_t *dblock = NULL; /* Pointer to direct block */ @@ -106,7 +105,6 @@ H5HF_man_dblock_create(hid_t dxpl_id, H5HF_hdr_t *hdr, H5HF_indirect_t *par_iblo * Check arguments. */ HDassert(hdr); - HDassert(block_size > 0); HDassert(addr_p); /* @@ -124,49 +122,49 @@ H5HF_man_dblock_create(hid_t dxpl_id, H5HF_hdr_t *hdr, H5HF_indirect_t *par_iblo HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared heap header") /* Set info for direct block */ -#ifdef QAK -HDfprintf(stderr, "%s: size = %Zu, block_off = %Hu\n", FUNC, block_size, block_off); -#endif /* QAK */ - dblock->parent = par_iblock; - if(dblock->parent) { - if(H5HF_iblock_incr(par_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") + if(par_iblock) { + unsigned par_row = par_entry / hdr->man_dtable.cparam.width; /* Row for block */ + + /* Compute offset & size, based on parent's information */ + dblock->block_off = par_iblock->block_off; + dblock->block_off += hdr->man_dtable.row_block_off[par_row]; + dblock->block_off += hdr->man_dtable.row_block_size[par_row] * (par_entry % hdr->man_dtable.cparam.width); + dblock->size = hdr->man_dtable.row_block_size[par_row]; } /* end if */ - dblock->par_entry = par_entry; - dblock->size = block_size; - dblock->block_off = block_off; - dblock->blk_off_size = H5HF_SIZEOF_OFFSET_LEN(block_size); - free_space = block_size - H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr); + else { + /* Must be the root direct block */ + dblock->block_off = 0; + dblock->size = hdr->man_dtable.cparam.start_block_size; + } /* end else */ + dblock->blk_off_size = H5HF_SIZEOF_OFFSET_LEN(dblock->size); + free_space = dblock->size - H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr); /* Allocate buffer for block */ /* XXX: Change to using free-list factories */ - if((dblock->blk = H5FL_BLK_MALLOC(direct_block, block_size)) == NULL) + if((dblock->blk = H5FL_BLK_MALLOC(direct_block, dblock->size)) == NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") #ifdef H5_USING_PURIFY HDmemset(dblock->blk, 0, dblock->size); #endif /* H5_USING_PURIFY */ /* Allocate space for the header on disk */ - if(HADDR_UNDEF == (*addr_p = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)block_size))) + if(HADDR_UNDEF == (*addr_p = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)dblock->size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") +#ifdef QAK +HDfprintf(stderr, "%s: direct block address = %a\n", FUNC, *addr_p); +#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 = block_off + H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr); - sec_node->sect_info.size = free_space; - 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 = *addr_p; - sec_node->u.single.dblock_size = block_size; + /* Attach to parent indirect block, if there is one */ + dblock->parent = par_iblock; + if(dblock->parent) + if(H5HF_man_iblock_attach(dblock->parent, par_entry, *addr_p) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't attach direct block to parent indirect block") + dblock->par_entry = par_entry; + + /* Create a new 'single' section for the free space in the block */ + if(NULL == (sec_node = H5HF_sect_single_new((dblock->block_off + H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)), + free_space, dblock->parent, dblock->par_entry, *addr_p, dblock->size))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create section for new direct block's free space") /* Check what to do with section node */ if(ret_sec_node) @@ -182,6 +180,10 @@ HDmemset(dblock->blk, 0, dblock->size); if(H5AC_set(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, *addr_p, dblock, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add fractal heap direct block to cache") + /* Increase the allocated heap size */ + if(H5HF_hdr_inc_alloc(hdr, dblock->size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size") + done: if(ret_value < 0) if(dblock) @@ -196,6 +198,10 @@ done: * * Purpose: Destroy a managed direct block * + * Note: This routine does _not_ insert a range section for the + * destroyed direct block, that must be handled by the + * caller. + * * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol @@ -230,6 +236,10 @@ HDfprintf(stderr, "%s: root direct block\n", FUNC); /* Sanity check block iterator */ HDassert(!H5HF_man_iter_ready(&hdr->next_block)); + /* Reset root pointer information */ + hdr->man_dtable.curr_root_rows = 0; + hdr->man_dtable.table_addr = HADDR_UNDEF; + /* 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") @@ -239,21 +249,51 @@ HDfprintf(stderr, "%s: root direct block\n", FUNC); HDfprintf(stderr, "%s: root indirect block\n", FUNC); #endif /* QAK */ -/* Remove from parent indirect block */ + /* Detach from parent indirect block */ + if(H5HF_man_iblock_detach(dblock->parent, dxpl_id, dblock->par_entry) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't detach from parent indirect block") + dblock->parent = NULL; + dblock->par_entry = 0; -/* If this is the last block in the heap, move block iterator backwards */ + /* Adjust heap statistics */ + hdr->man_alloc_size -= dblock->size; -/* 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") +#ifdef QAK +HDfprintf(stderr, "%s: dblock->block_off = %Hu\n", FUNC, dblock->block_off); +HDfprintf(stderr, "%s: hdr->man_iter_off = %Hu\n", FUNC, hdr->man_iter_off); +#endif /* QAK */ + /* Check for this direct block being the highest in the heap */ + if((dblock->block_off + dblock->size) == hdr->man_iter_off) { + /* Move 'next block' iterator backwards (may shrink heap) */ + if(H5HF_hdr_reverse_iter(hdr, dxpl_id) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reverse 'next block' iterator") + } /* end if */ +#if 0 + else { + unsigned par_row, par_col; /* Row & column in parent indirect block */ + + /* Compute row & column in parent indirect block */ + par_row = dblock->par_entry / hdr->man_dtable.cparam.width; + par_col = dblock->par_entry % hdr->man_dtable.cparam.width; + + /* Add a 'range' section for the space in the destroyed block */ + if(H5HF_sect_range_add(hdr, dxpl_id, dblock->block_off, hdr->man_dtable.row_dblock_free[par_row], + dblock->parent, par_row, par_col, 1) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't create range section for direct block being destroyed") + } /* end else */ +#endif /* 0 */ } /* end else */ /* Release direct block's disk space */ +#ifdef QAK +HDfprintf(stderr, "%s: Before releasing direct block's space, dblock_addr = %a\n", FUNC, dblock_addr); +#endif /* QAK */ 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) + /* (direct block "destroy" callback will be called by cache) */ + if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__DIRTIED_FLAG|H5AC__DELETED_FLAG) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block") dblock = NULL; @@ -277,11 +317,10 @@ done: *------------------------------------------------------------------------- */ herr_t -H5HF_man_dblock_new(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t request) +H5HF_man_dblock_new(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t request, + H5HF_free_section_t **ret_sec_node) { haddr_t dblock_addr; /* Address of new direct block */ - hsize_t dblock_off; /* Direct block offset in heap address space */ - size_t dblock_size; /* Size of new direct block */ size_t min_dblock_size; /* Min. size of direct block to allocate */ herr_t ret_value = SUCCEED; /* Return value */ @@ -319,13 +358,11 @@ HDfprintf(stderr, "%s: Check 2 - min_dblock_size = %Zu\n", FUNC, min_dblock_size if(!H5F_addr_defined(hdr->man_dtable.table_addr) && min_dblock_size == hdr->man_dtable.cparam.start_block_size) { /* Create new direct block at starting offset */ - dblock_size = hdr->man_dtable.cparam.start_block_size; - dblock_off = 0; - if(H5HF_man_dblock_create(dxpl_id, hdr, NULL, 0, dblock_size, dblock_off, &dblock_addr, NULL) < 0) + if(H5HF_man_dblock_create(dxpl_id, hdr, NULL, 0, &dblock_addr, ret_sec_node) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block") #ifdef QAK -HDfprintf(stderr, "%s: dblock_addr = %a\n", FUNC, dblock_addr); +HDfprintf(stderr, "%s: root direct block, dblock_addr = %a\n", FUNC, dblock_addr); #endif /* QAK */ /* Point root at new direct block */ @@ -333,49 +370,50 @@ HDfprintf(stderr, "%s: dblock_addr = %a\n", FUNC, dblock_addr); hdr->man_dtable.table_addr = dblock_addr; /* Extend heap to cover new direct block */ - if(H5HF_hdr_extend_heap(hdr, (hsize_t)dblock_size, hdr->man_dtable.row_dblock_free[0]) < 0) + if(H5HF_hdr_adjust_heap(hdr, (hsize_t)hdr->man_dtable.cparam.start_block_size, (hssize_t)hdr->man_dtable.row_dblock_free[0]) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block") } /* end if */ - /* Root entry already exists, go get indirect block for new direct block */ + /* Root entry already exists, allocate direct block from root indirect block */ else { H5HF_indirect_t *iblock; /* Pointer to indirect block to create */ - size_t dblock_entry; /* Direct entry for new direct block */ + unsigned next_row; /* Iterator's next block row */ + unsigned next_entry; /* Iterator's next block entry */ + size_t next_size; /* Size of next direct block to create */ + + /* Update iterator to reflect any previous increments as well as allow for requested direct block size */ + if(H5HF_hdr_update_iter(hdr, dxpl_id, min_dblock_size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUPDATE, FAIL, "unable to update block iterator") + + /* Retrieve information about current iterator position */ + if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location") + HDassert(next_row < iblock->nrows); + next_size = hdr->man_dtable.row_block_size[next_row]; + + /* Check for skipping over blocks */ + if(min_dblock_size > next_size) { +HDfprintf(stderr, "%s: Skipping direct block sizes not supported, min_dblock_size = %Zu, next_size = %Zu\n", FUNC, min_dblock_size, next_size); +HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "skipping direct block sizes not supported yet") + } /* end if */ + + /* Advance "next block" iterator to next direct block entry */ + if(H5HF_hdr_inc_iter(hdr, (hsize_t)next_size, 1) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment 'next block' iterator") - /* Find indirect block with room for block of correct size */ - if(NULL == (iblock = H5HF_man_iblock_place_dblock(hdr, dxpl_id, min_dblock_size, &dblock_entry, &dblock_size))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to locate indirect block with space for direct block") #ifdef QAK HDfprintf(stderr, "%s: iblock = %p\n", FUNC, iblock); HDfprintf(stderr, "%s: iblock->addr = %a\n", FUNC, iblock->addr); -HDfprintf(stderr, "%s: dblock_entry = %Zu\n", FUNC, dblock_entry); -HDfprintf(stderr, "%s: dblock_size = %Zu\n", FUNC, dblock_size); +HDfprintf(stderr, "%s: next_entry = %u\n", FUNC, next_entry); #endif /* QAK */ - /* Compute the direct block's offset in the heap's address space */ - dblock_off = iblock->block_off; - dblock_off += hdr->man_dtable.row_block_off[dblock_entry / hdr->man_dtable.cparam.width]; - dblock_off += hdr->man_dtable.row_block_size[dblock_entry / hdr->man_dtable.cparam.width] * (dblock_entry % hdr->man_dtable.cparam.width); - /* Create new direct block at current location*/ - if(H5HF_man_dblock_create(dxpl_id, hdr, iblock, dblock_entry, dblock_size, dblock_off, &dblock_addr, NULL) < 0) + if(H5HF_man_dblock_create(dxpl_id, hdr, iblock, next_entry, &dblock_addr, ret_sec_node) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block") - #ifdef QAK HDfprintf(stderr, "%s: dblock_addr = %a\n", FUNC, dblock_addr); #endif /* QAK */ - - /* Point indirect block at new direct block */ - iblock->ents[dblock_entry].addr = dblock_addr; - - /* Mark indirect block as modified */ - if(H5HF_iblock_dirty(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty") } /* end else */ - /* Advance the allocated heap size/new block iterator */ - if(H5HF_hdr_inc_alloc(hdr, dblock_off + dblock_size, 1) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size") - done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF_man_dblock_new() */ diff --git a/src/H5HFdtable.c b/src/H5HFdtable.c index e51b45b..1461cd7 100644 --- a/src/H5HFdtable.c +++ b/src/H5HFdtable.c @@ -103,11 +103,11 @@ H5HF_dtable_init(H5HF_dtable_t *dtable) HDassert(dtable); /* Compute/cache some values */ - dtable->first_row_bits = H5V_log2_of2(dtable->cparam.start_block_size) + - H5V_log2_of2(dtable->cparam.width); + dtable->start_bits = H5V_log2_of2(dtable->cparam.start_block_size); + dtable->first_row_bits = dtable->start_bits + H5V_log2_of2(dtable->cparam.width); dtable->max_root_rows = (dtable->cparam.max_index - dtable->first_row_bits) + 1; - dtable->max_direct_rows = (H5V_log2_of2(dtable->cparam.max_direct_size) - - H5V_log2_of2(dtable->cparam.start_block_size)) + 2; + dtable->max_direct_bits = H5V_log2_of2(dtable->cparam.max_direct_size); + dtable->max_direct_rows = (dtable->max_direct_bits - dtable->start_bits) + 2; dtable->num_id_first_row = dtable->cparam.start_block_size * dtable->cparam.width; dtable->max_dir_blk_off_size = H5HF_SIZEOF_OFFSET_LEN(dtable->cparam.max_direct_size); @@ -245,3 +245,34 @@ H5HF_dtable_size_to_row(H5HF_dtable_t *dtable, size_t block_size) FUNC_LEAVE_NOAPI(row) } /* end H5HF_dtable_size_to_row() */ + +/*------------------------------------------------------------------------- + * Function: H5HF_dtable_size_to_rows + * + * Purpose: Compute # of rows of indirect block of a given size + * + * Return: Non-negative on success (can't fail) + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 31 2006 + * + *------------------------------------------------------------------------- + */ +unsigned +H5HF_dtable_size_to_rows(H5HF_dtable_t *dtable, hsize_t size) +{ + unsigned rows; /* # of rows required for indirect block */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_dtable_size_to_rows) + + /* + * Check arguments. + */ + HDassert(dtable); + + rows = (H5V_log2_gen(size) - dtable->first_row_bits) + 1; + + FUNC_LEAVE_NOAPI(rows) +} /* end H5HF_dtable_size_to_rows() */ + diff --git a/src/H5HFhdr.c b/src/H5HFhdr.c index 05d0a77..836d1e6 100644 --- a/src/H5HFhdr.c +++ b/src/H5HFhdr.c @@ -68,6 +68,10 @@ /* Local Prototypes */ /********************/ +/* Free space section routines */ +static herr_t H5HF_hdr_skip_ranges(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_indirect_t *iblock, unsigned start_entry, unsigned nentries); + /*********************/ /* Package Variables */ @@ -426,7 +430,7 @@ HDfprintf(stderr, "%s: Marking heap header as dirty\n", FUNC); HDassert(hdr); /* Mark header as dirty in cache */ - if(H5AC_mark_pinned_entry_dirty(hdr->f, hdr, FALSE, 0) < 0) + if(H5AC_mark_pinned_or_protected_entry_dirty(hdr->f, hdr) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark fractal heap header as dirty") /* Set the dirty flags for the heap header */ @@ -482,9 +486,9 @@ done: /*------------------------------------------------------------------------- - * Function: H5HF_hdr_extend_heap + * Function: H5HF_hdr_adjust_heap * - * Purpose: Extend heap to cover more space + * Purpose: Adjust heap space * * Return: Non-negative on success/Negative on failure * @@ -495,25 +499,31 @@ done: *------------------------------------------------------------------------- */ herr_t -H5HF_hdr_extend_heap(H5HF_hdr_t *hdr, hsize_t new_size, hsize_t extra_free) +H5HF_hdr_adjust_heap(H5HF_hdr_t *hdr, hsize_t new_size, hssize_t extra_free) { - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_hdr_extend_heap) + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_hdr_adjust_heap) /* * Check arguments. */ HDassert(hdr); - HDassert(new_size >= hdr->total_size); /* Set the total space in heap */ hdr->total_size = new_size; hdr->man_size = new_size; - /* Increment the free space in direct blocks */ + /* Adjust the free space in direct blocks */ hdr->total_man_free += extra_free; - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5HF_hdr_extend_heap() */ + /* 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_adjust_heap() */ /*------------------------------------------------------------------------- @@ -525,37 +535,752 @@ H5HF_hdr_extend_heap(H5HF_hdr_t *hdr, hsize_t new_size, hsize_t extra_free) * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu - * Apr 24 2006 + * May 23 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_hdr_inc_alloc(H5HF_hdr_t *hdr, size_t alloc_size) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_hdr_inc_alloc) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(alloc_size); + + /* Update the "allocated" size within the heap */ + hdr->man_alloc_size += alloc_size; +#ifdef QAK +HDfprintf(stderr, "%s: hdr->man_alloc_size = %Hu\n", "H5HF_hdr_inc_alloc", hdr->man_alloc_size); +#endif /* QAK */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HF_hdr_inc_alloc() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_hdr_start_iter + * + * Purpose: Start "next block" iterator at an offset/entry in the heap + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 30 2006 * *------------------------------------------------------------------------- */ herr_t -H5HF_hdr_inc_alloc(H5HF_hdr_t *hdr, hsize_t new_alloc_size, unsigned nentries) +H5HF_hdr_start_iter(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock, hsize_t curr_off, unsigned curr_entry) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5HF_hdr_inc_alloc) + FUNC_ENTER_NOAPI_NOINIT(H5HF_hdr_start_iter) /* * Check arguments. */ HDassert(hdr); - HDassert(new_alloc_size >= hdr->man_alloc_size); + HDassert(iblock); + + /* Set up "next block" iterator at correct location */ + if(H5HF_man_iter_start_entry(hdr, &hdr->next_block, iblock, curr_entry) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize block iterator") + + /* Set the offset of the iterator in the heap */ + hdr->man_iter_off = curr_off; - /* Advance the iterator for the current location with in the indirect block */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_hdr_start_iter() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_hdr_reset_iter + * + * Purpose: Reset "next block" iterator + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 31 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_hdr_reset_iter(H5HF_hdr_t *hdr, hsize_t curr_off) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_hdr_reset_iter) + + /* + * Check arguments. + */ + HDassert(hdr); + + /* Reset "next block" iterator */ + if(H5HF_man_iter_reset(&hdr->next_block) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator") + + /* Set the offset of the iterator in the heap */ + hdr->man_iter_off = curr_off; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_hdr_reset_iter() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_hdr_skip_blocks + * + * Purpose: Add skipped direct blocks to free space for heap + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Apr 3 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_hdr_skip_blocks(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_indirect_t *iblock, + unsigned start_entry, unsigned nentries) +{ + hsize_t sect_off; /* Offset of free section in heap */ + unsigned curr_row; /* Current row in indirect block */ + unsigned curr_col; /* Current column in indirect block */ + unsigned u; /* Local index variables */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_hdr_skip_blocks) +#ifdef QAK +HDfprintf(stderr, "%s: start_entry = %u, nentries = %u\n", FUNC, start_entry, nentries); +#endif /* QAK */ + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(iblock); + HDassert(nentries); + + /* Compute starting column & row */ + curr_row = start_entry / hdr->man_dtable.cparam.width; + curr_col = start_entry % hdr->man_dtable.cparam.width; + + /* Initialize information for rows skipped over */ + sect_off = iblock->block_off; + for(u = 0; u < curr_row; u++) + sect_off += hdr->man_dtable.row_block_size[u] * hdr->man_dtable.cparam.width; + sect_off += hdr->man_dtable.row_block_size[curr_row] * curr_col; +#ifdef QAK +HDfprintf(stderr, "%s: sect_off = %Zu\n", FUNC, sect_off); +#endif /* QAK */ + + /* Loop over the blocks to skip */ + for(u = start_entry; u < (start_entry + nentries); /* u is advanced in loop */) { + unsigned row_entries; /* Number of entries in a particular row */ + + /* Compute number of entries in (possible partial) current row */ + row_entries = MIN(hdr->man_dtable.cparam.width - curr_col, (start_entry + nentries) - u); +#ifdef QAK +HDfprintf(stderr, "%s: u = %u\n", FUNC, u); +HDfprintf(stderr, "%s: curr_col = %u, curr_row = %u\n", FUNC, curr_col, curr_row); +HDfprintf(stderr, "%s: row_entries = %u, hdr->man_dtable.row_dblock_free[%u] = %Hu\n", FUNC, row_entries, curr_row, hdr->man_dtable.row_dblock_free[curr_row]); +#endif /* QAK */ + + /* Add 'range' section for blocks skipped in this row */ + if(H5HF_sect_range_add(hdr, dxpl_id, sect_off, hdr->man_dtable.row_dblock_free[curr_row], + iblock, curr_row, curr_col, row_entries) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create range section for indirect block's free space") + + /* Advance row & column position */ + sect_off += row_entries * hdr->man_dtable.row_block_size[curr_row]; + curr_row++; + curr_col = 0; /* (first partial row aligns this) */ + + /* Increment index variable */ + u += row_entries; + } /* end for */ +#ifdef QAK +HDfprintf(stderr, "%s: sect_off = %Zu\n", FUNC, sect_off); +#endif /* QAK */ + + /* Advance the new block iterator */ + if(H5HF_hdr_inc_iter(hdr, (sect_off - hdr->man_iter_off), nentries) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_hdr_skip_blocks() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_hdr_skip_ranges + * + * Purpose: Add skipped indirect ranges to free space for heap + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Apr 4 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF_hdr_skip_ranges(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_indirect_t *iblock, + unsigned start_entry, unsigned nentries) +{ + hsize_t sect_off; /* Offset of free section in heap */ + size_t row_dblock_free_space; /* Size of free space for row of direct blocks in a row */ + size_t acc_row_dblock_free_space; /* Accumulated size of free space for row of direct blocks in a row */ + unsigned curr_row; /* Current row in indirect block */ + unsigned curr_col; /* Current column in indirect block */ + unsigned u, w; /* Local index variables */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_hdr_skip_ranges) +#ifdef QAK +HDfprintf(stderr, "%s: start_entry = %u, nentries = %u\n", FUNC, start_entry, nentries); +#endif /* QAK */ + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(iblock); + HDassert(nentries); + + /* Compute starting column & row */ + curr_row = start_entry / hdr->man_dtable.cparam.width; + curr_col = start_entry % hdr->man_dtable.cparam.width; +#ifdef QAK +HDfprintf(stderr, "%s: curr_col = %u, curr_row = %u\n", FUNC, curr_col, curr_row); +#endif /* QAK */ + + /* Initialize information for rows skipped over */ + sect_off = iblock->block_off; + for(u = 0; u < curr_row; u++) + sect_off += hdr->man_dtable.row_block_size[u] * hdr->man_dtable.cparam.width; + sect_off += hdr->man_dtable.row_block_size[curr_row] * curr_col; +#ifdef QAK +HDfprintf(stderr, "%s: sect_off = %Zu\n", FUNC, sect_off); +#endif /* QAK */ + + /* Loop over the blocks to skip */ + for(u = start_entry; u < (start_entry + nentries); /* u is advanced in loop */) { + unsigned row_entries; /* Number of entries in a particular row */ + unsigned num_rows; /* Number of rows in indirect blocks referenced */ + + /* Compute number of rows in indirect blocks covered by entry */ + num_rows = (H5V_log2_of2((uint32_t)hdr->man_dtable.row_block_size[curr_row]) - + H5V_log2_of2(hdr->man_dtable.cparam.start_block_size)) - 1; + + /* Compute number of entries in (possible partial) current row */ + row_entries = MIN(hdr->man_dtable.cparam.width - curr_col, (start_entry + nentries) - u); +#ifdef QAK +HDfprintf(stderr, "%s: u = %u\n", FUNC, u); +HDfprintf(stderr, "%s: curr_col = %u, curr_row = %u\n", FUNC, curr_col, curr_row); +HDfprintf(stderr, "%s: row_entries = %u, num_rows = %u\n", FUNC, row_entries, num_rows); +#endif /* QAK */ + + /* Loop over rows in indirect blocks covered */ + acc_row_dblock_free_space = 0; + for(w = 0; w < num_rows; w++) { + + /* Compute free space in direct blocks for this row */ + row_dblock_free_space = hdr->man_dtable.cparam.width * hdr->man_dtable.row_dblock_free[w]; + acc_row_dblock_free_space += row_dblock_free_space; +#ifdef QAK +HDfprintf(stderr, "%s: w = %u\n", FUNC, w); +HDfprintf(stderr, "%s: hdr->man_dtable.row_dblock_free[%u] = %Zu\n", FUNC, w, hdr->man_dtable.row_dblock_free[w]); +#endif /* QAK */ + + /* Add "indirect" free space section for blocks in this row */ + + /* Create free list section node for blocks skipped over */ + if(H5HF_sect_indirect_add(hdr, dxpl_id, (sect_off + hdr->man_dtable.row_block_off[w]), + hdr->man_dtable.row_dblock_free[w], iblock, curr_row, curr_col, row_entries, w, num_rows) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create indirect section for indirect block's free space") + } /* end for */ +#ifdef QAK +HDfprintf(stderr, "%s: acc_row_dblock_free_space = %Zu\n", FUNC, acc_row_dblock_free_space); +#endif /* QAK */ + + /* Advance row & column position */ + sect_off += row_entries * hdr->man_dtable.row_block_size[curr_row]; + curr_row++; + curr_col = 0; /* (first partial row aligns this) */ + + /* 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 new block iterator */ + if(H5HF_hdr_inc_iter(hdr, (sect_off - hdr->man_iter_off), nentries) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_hdr_skip_ranges() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_hdr_update_iter + * + * Purpose: Update state of heap to account for current iterator + * position. + * + * Note: Creates necessary indirect blocks + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Mar 14 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_hdr_update_iter(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_size) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_hdr_update_iter) +#ifdef QAK +HDfprintf(stderr, "%s: min_dblock_size = %Zu\n", FUNC, min_dblock_size); +#endif /* QAK */ + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(min_dblock_size > 0); + + /* Check for creating first indirect block */ + if(hdr->man_dtable.curr_root_rows == 0) { + if(H5HF_man_iblock_root_create(hdr, dxpl_id, min_dblock_size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "unable to create root indirect block") + } /* end if */ + else { + H5HF_indirect_t *iblock; /* Pointer to indirect block */ + hbool_t walked_up, walked_down; /* Condition variables for finding direct block location */ + unsigned next_row; /* Iterator's next block row */ + unsigned next_entry; /* Iterator's next block entry */ + unsigned min_dblock_row; /* Minimum row for direct block size request */ + +#ifdef QAK +HDfprintf(stderr, "%s: searching root indirect block\n", FUNC); +#endif /* QAK */ + /* Compute min. row for direct block requested */ + min_dblock_row = H5HF_dtable_size_to_row(&hdr->man_dtable, min_dblock_size); +#ifdef QAK +HDfprintf(stderr, "%s: min_dblock_size = %Zu, min_dblock_row = %u\n", FUNC, min_dblock_size, min_dblock_row); +#endif /* QAK */ + + /* Initialize block iterator, if necessary */ + if(!H5HF_man_iter_ready(&hdr->next_block)) { +#ifdef QAK +HDfprintf(stderr, "%s: hdr->man_iter_off = %Hu\n", FUNC, hdr->man_iter_off); +#endif /* QAK */ + /* Start iterator with previous offset of iterator */ + if(H5HF_man_iter_start_offset(hdr, dxpl_id, &hdr->next_block, hdr->man_iter_off) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to set block iterator location") + } /* end if */ + + /* Get information about current iterator location */ + if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location") + +#ifdef QAK +HDfprintf(stderr, "%s: Check 1.0\n", FUNC); +HDfprintf(stderr, "%s: iblock = %p\n", FUNC, iblock); +HDfprintf(stderr, "%s: iblock->nrows = %u\n", FUNC, iblock->nrows); +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 && 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 */ + + /* Compute the number of entries to skip in the current block */ + min_entry = min_dblock_row * hdr->man_dtable.cparam.width; + if(min_dblock_row >= iblock->nrows) + skip_entries = (iblock->nrows * hdr->man_dtable.cparam.width) - next_entry; + else + skip_entries = min_entry - next_entry; +#ifdef QAK +HDfprintf(stderr, "%s: min_entry = %u, skip_entries = %u\n", FUNC, min_entry, skip_entries); +#endif /* QAK */ + + /* Add skipped direct blocks to heap's free space */ + if(H5HF_hdr_skip_blocks(hdr, dxpl_id, iblock, next_entry, skip_entries) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space") + + /* Get information about new iterator location */ + if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "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); +HDfprintf(stderr, "%s: iblock->nrows = %u\n", FUNC, iblock->nrows); +HDfprintf(stderr, "%s: next_row = %u\n", FUNC, next_row); +HDfprintf(stderr, "%s: next_entry = %u\n", FUNC, next_entry); +#endif /* QAK */ + + /* Check for walking off end of indirect block */ + /* (walk up iterator) */ + while(next_row >= iblock->nrows) { +#ifdef QAK +HDfprintf(stderr, "%s: Off the end of a block\n", FUNC); +#endif /* QAK */ + /* Check for needing to expand root indirect block */ + if(iblock->parent == NULL) { +#ifdef QAK +HDfprintf(stderr, "%s: Doubling root block\n", FUNC); +#endif /* QAK */ + if(H5HF_man_iblock_root_double(hdr, dxpl_id, min_dblock_size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "unable to double root indirect block") + } /* end if */ + else { +#ifdef QAK +HDfprintf(stderr, "%s: Walking up a level\n", FUNC); +#endif /* QAK */ + /* Move iterator up one level */ + if(H5HF_man_iter_up(&hdr->next_block) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location") + + /* Increment location of next block at this level */ + if(H5HF_man_iter_next(hdr, &hdr->next_block, 1) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't advance fractal heap block location") + } /* end else */ + + /* Get information about new iterator location */ + if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location") + + /* Indicate that we walked up */ + walked_up = TRUE; + } /* end while */ +#ifdef QAK +HDfprintf(stderr, "%s: Check 3.0\n", FUNC); +HDfprintf(stderr, "%s: iblock = %p\n", FUNC, iblock); +HDfprintf(stderr, "%s: iblock->nrows = %u\n", FUNC, iblock->nrows); +HDfprintf(stderr, "%s: next_row = %u\n", FUNC, next_row); +HDfprintf(stderr, "%s: next_entry = %u\n", FUNC, next_entry); +#endif /* QAK */ + + /* Check for walking into child indirect block */ + /* (walk down iterator) */ + if(next_row >= hdr->man_dtable.max_direct_rows) { + unsigned child_nrows; /* Number of rows in new indirect block */ + +#ifdef QAK +HDfprintf(stderr, "%s: Walking down into child indirect block\n", FUNC); +#endif /* QAK */ +#ifdef QAK +HDfprintf(stderr, "%s: Check 3.1\n", FUNC); +HDfprintf(stderr, "%s: iblock = %p\n", FUNC, iblock); +HDfprintf(stderr, "%s: iblock->nrows = %u\n", FUNC, iblock->nrows); +HDfprintf(stderr, "%s: next_row = %u\n", FUNC, next_row); +HDfprintf(stderr, "%s: next_entry = %u\n", FUNC, next_entry); +#endif /* QAK */ + HDassert(!H5F_addr_defined(iblock->ents[next_entry].addr)); + + /* Compute # of rows in next child indirect block to use */ + child_nrows = H5HF_dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[next_row]); +#ifdef QAK +HDfprintf(stderr, "%s: child_nrows = %u\n", FUNC, child_nrows); +#endif /* QAK */ + + /* Check for skipping over indirect blocks */ + /* (that don't have direct blocks large enough to hold direct block size requested) */ + if(hdr->man_dtable.row_block_size[child_nrows - 1] < min_dblock_size) { + unsigned child_rows_needed; /* Number of rows needed to hold direct block */ + unsigned child_entry; /* Entry of child indirect block */ + +#ifdef QAK +HDfprintf(stderr, "%s: Skipping indirect block row that is too small\n", FUNC); +#endif /* QAK */ + /* Compute # of rows needed in child indirect block */ + 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); +#endif /* QAK */ + + /* Add skipped indirect ranges to heap's free space */ + if(H5HF_hdr_skip_ranges(hdr, dxpl_id, iblock, next_entry, (child_entry - next_entry)) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space") + } /* end if */ + else { + H5HF_indirect_t *new_iblock; /* Pointer to new indirect block */ + haddr_t new_iblock_addr; /* New indirect block's address */ + +#ifdef QAK +HDfprintf(stderr, "%s: Allocating new child indirect block\n", FUNC); +#endif /* QAK */ + /* Allocate new indirect block */ + if(H5HF_man_iblock_create(hdr, dxpl_id, iblock, next_entry, child_nrows, child_nrows, &new_iblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap indirect block") + + /* Lock new indirect block */ + if(NULL == (new_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, new_iblock_addr, child_nrows, iblock, next_entry, H5AC_WRITE))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") + + /* Move iterator down one level */ + if(H5HF_man_iter_down(&hdr->next_block, new_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location") + + /* Check for skipping over rows and add free section for skipped rows */ + if(min_dblock_size > hdr->man_dtable.cparam.start_block_size) { + unsigned new_entry; /* Entry of direct block which is large enough */ + + /* Compute entry for direct block size requested */ + new_entry = hdr->man_dtable.cparam.width * min_dblock_row; +#ifdef QAK +HDfprintf(stderr, "%s: Skipping rows in new child indirect block - new_entry = %u\n", FUNC, new_entry); +#endif /* QAK */ + + /* Add skipped blocks to heap's free space */ + if(H5HF_hdr_skip_blocks(hdr, dxpl_id, new_iblock, 0, new_entry) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space") + } /* end if */ + + /* Unprotect child indirect block */ + if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, new_iblock->addr, new_iblock, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") + } /* end else */ + + /* Get information about new iterator location */ + if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location") + + /* Indicate that we walked down */ + walked_down = TRUE; + } /* end if */ + } while(walked_down || walked_up); + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_hdr_update_iter() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_hdr_inc_iter + * + * Purpose: Advance "next block" iterator + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 23 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_hdr_inc_iter(H5HF_hdr_t *hdr, hsize_t adv_size, unsigned nentries) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_hdr_inc_iter) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(nentries); +#ifdef QAK +HDfprintf(stderr, "%s: hdr->man_iter_off = %Hu, adv_size = %Hu\n", FUNC, hdr->man_iter_off, adv_size); +#endif /* QAK */ + + /* Advance the iterator for the current location within the indirect block */ if(hdr->next_block.curr) if(H5HF_man_iter_next(hdr, &hdr->next_block, nentries) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location") - /* Update the "allocated" size within the heap */ - hdr->man_alloc_size = new_alloc_size; + /* Increment the offset of the iterator in the heap */ + hdr->man_iter_off += adv_size; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_hdr_inc_iter() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_hdr_reverse_iter + * + * Purpose: Walk "next block" iterator backwards until the correct + * location to allocate next block from is found + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 31 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_hdr_reverse_iter(H5HF_hdr_t *hdr, hid_t dxpl_id) +{ + H5HF_indirect_t *iblock; /* Indirect block where iterator is located */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_hdr_reverse_iter) + + /* + * Check arguments. + */ + HDassert(hdr); + + /* Initialize block iterator, if necessary */ + if(!H5HF_man_iter_ready(&hdr->next_block)) + /* Start iterator with previous offset of iterator */ + if(H5HF_man_iter_start_offset(hdr, dxpl_id, &hdr->next_block, hdr->man_iter_off) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to set block iterator location") + + /* Get information about current iterator location */ + if(H5HF_man_iter_curr(&hdr->next_block, NULL, NULL, NULL, &iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator information") #ifdef QAK -HDfprintf(stderr, "%s: hdr->man_alloc_size = %Hu\n", FUNC, hdr->man_alloc_size); +HDfprintf(stderr, "%s: iblock->nchildren = %u\n", FUNC, iblock->nchildren); +HDfprintf(stderr, "%s: iblock->parent = %p\n", FUNC, iblock->parent); #endif /* QAK */ + /* Walk backwards through heap, looking for direct block to place iterator after */ + + /* Walk up the levels in the heap until we find an indirect block with children */ + while(iblock->nchildren == 0 && iblock->parent) { + /* Move iterator to parent of current block */ + if(H5HF_man_iter_up(&hdr->next_block) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location") + + /* Detach from parent indirect block */ + if(H5HF_man_iblock_detach(iblock->parent, dxpl_id, iblock->par_entry) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't detach from parent indirect block") + iblock->parent = NULL; + iblock->par_entry = 0; + } /* end while */ + + /* If there's children in this indirect block, walk backwards to find last child */ + if(iblock->nchildren) { + unsigned curr_entry; /* Current entry for iterator */ + unsigned row; /* Row for entry */ + hbool_t walked_down; /* Loop flag */ + + /* Get information about current iterator location */ + if(H5HF_man_iter_curr(&hdr->next_block, NULL, NULL, &curr_entry, NULL) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator information") +#ifdef QAK +HDfprintf(stderr, "%s: curr_entry = %u\n", FUNC, curr_entry); +#endif /* QAK */ + + /* Move current iterator position backwards once */ + curr_entry--; + + /* Search backwards for direct block to latch onto */ + do { + int tmp_entry; /* Temp. entry for iterator (use signed value to detect errors) */ + + /* Reset loop flag */ + walked_down = FALSE; + + /* Walk backwards through entries, until we find one that has a child */ + /* (Account for root indirect block shrinking) */ + tmp_entry = MIN(curr_entry, ((iblock->nrows * hdr->man_dtable.cparam.width) - 1)); +#ifdef QAK +HDfprintf(stderr, "%s: tmp_entry = %d\n", FUNC, tmp_entry); +HDfprintf(stderr, "%s: iblock->nrows = %u\n", FUNC, iblock->nrows); +#endif /* QAK */ + while(!H5F_addr_defined(iblock->ents[tmp_entry].addr)) { + tmp_entry--; + HDassert(tmp_entry >= 0); + } /* end while */ +#ifdef QAK +HDfprintf(stderr, "%s: check 2.0 - tmp_entry = %d\n", FUNC, tmp_entry); +#endif /* QAK */ + curr_entry = tmp_entry; + + /* Check if entry is for a direct block */ + row = curr_entry / hdr->man_dtable.cparam.width; + if(row < hdr->man_dtable.max_direct_rows) { + /* Increment entry to empty location */ + curr_entry++; + + /* Set the current location of the iterator to next entry after the existing direct block */ + if(H5HF_man_iter_set_entry(hdr, &hdr->next_block, curr_entry) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "unable to set current block iterator location") + + /* Update iterator offset */ + hdr->man_iter_off = iblock->block_off; + hdr->man_iter_off += hdr->man_dtable.row_block_off[curr_entry / hdr->man_dtable.cparam.width]; + hdr->man_iter_off += hdr->man_dtable.row_block_size[curr_entry / hdr->man_dtable.cparam.width] * (curr_entry % hdr->man_dtable.cparam.width); + } /* end if */ + else { + H5HF_indirect_t *child_iblock; /* Pointer to child indirect block */ + unsigned child_nrows; /* # of rows in child block */ + + /* Compute # of rows in next child indirect block to use */ + child_nrows = H5HF_dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[row]); + + /* Lock child indirect block */ + if(NULL == (child_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock->ents[curr_entry].addr, child_nrows, iblock, curr_entry, H5AC_WRITE))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") + + /* Set the current location of the iterator */ + if(H5HF_man_iter_set_entry(hdr, &hdr->next_block, curr_entry) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSET, FAIL, "unable to set current block iterator location") + + /* Walk down into child indirect block (pins child block) */ + if(H5HF_man_iter_down(&hdr->next_block, child_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, FAIL, "unable to advance current block iterator location") + + /* Update iterator location */ + iblock = child_iblock; + curr_entry = (child_iblock->nrows * hdr->man_dtable.cparam.width) - 1; + + /* Unprotect child indirect block */ + if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, child_iblock->addr, child_iblock, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") + + /* Note that we walked down */ + walked_down = TRUE; + } /* end else */ + } while(walked_down); + } /* end if */ + else { + /* 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 else */ + done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_hdr_inc_alloc() */ +} /* end H5HF_hdr_reverse_iter() */ /*------------------------------------------------------------------------- @@ -584,13 +1309,10 @@ HDfprintf(stderr, "%s: Reseting heap header to empty\n", FUNC); /* 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; + hdr->man_alloc_size = 0; /* Reset the free space in direct blocks */ hdr->total_man_free = 0; diff --git a/src/H5HFiblock.c b/src/H5HFiblock.c index f3d7029..652ae54 100644 --- a/src/H5HFiblock.c +++ b/src/H5HFiblock.c @@ -56,24 +56,9 @@ /********************/ /* Local Prototypes */ /********************/ +static herr_t H5HF_man_iblock_root_halve(H5HF_indirect_t *root_iblock, hid_t dxpl_id); +static herr_t H5HF_man_iblock_root_revert(H5HF_indirect_t *root_iblock, hid_t dxpl_id); -/* Free space section routines */ -static herr_t H5HF_man_iblock_skip_blocks(H5HF_hdr_t *hdr, hid_t dxpl_id, - H5HF_indirect_t *iblock, haddr_t iblock_addr, - unsigned start_entry, unsigned nentries); -static herr_t H5HF_man_iblock_skip_ranges(H5HF_hdr_t *hdr, hid_t dxpl_id, - H5HF_indirect_t *iblock, haddr_t iblock_addr, - unsigned start_entry, unsigned nentries); - -/* Root indirect block routines */ -static herr_t H5HF_man_iblock_root_create(H5HF_hdr_t *hdr, hid_t dxpl_id, - size_t min_dblock_size); -static herr_t H5HF_man_iblock_root_double(H5HF_hdr_t *hdr, hid_t dxpl_id, - size_t min_dblock_size); - -/* Misc. indirect block routines */ -static herr_t H5HF_man_iblock_create(H5HF_hdr_t *hdr, hid_t dxpl_id, - hsize_t block_off, unsigned nrows, unsigned max_rows, haddr_t *addr_p); /*********************/ /* Package Variables */ @@ -160,10 +145,40 @@ H5HF_iblock_decr(H5HF_indirect_t *iblock) iblock->rc--; /* Mark block as evictable again when no child blocks depend on it */ - if(iblock->rc == 0) + if(iblock->rc == 0) { + H5HF_indirect_t *tmp_iblock; /* Temporary pointer to indirect block */ + +#ifdef QAK +HDfprintf(stderr, "%s: indirect block ref. count at zero, iblock->addr = %a\n", FUNC, iblock->addr); +#endif /* QAK */ + /* Lock indirect block */ + if(iblock->nchildren == 0) { + if(NULL == (tmp_iblock = H5HF_man_iblock_protect(iblock->hdr, H5AC_dxpl_id, iblock->addr, iblock->nrows, NULL, 0, H5AC_WRITE))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") + HDassert(tmp_iblock == iblock); + } /* end if */ + if(H5AC_unpin_entry(iblock->hdr->f, iblock) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin fractal heap indirect block") +/* XXX: If the indirect block has no children, delete indirect block's entry + * from cache. + */ + if(iblock->nchildren == 0) { + /* Check for deleting root indirect block (and no root direct block) */ + if(iblock->block_off == 0 && iblock->hdr->man_dtable.curr_root_rows > 0) { + /* Reset root pointer information */ + iblock->hdr->man_dtable.curr_root_rows = 0; + iblock->hdr->man_dtable.table_addr = HADDR_UNDEF; + } /* end if */ + + /* Unlock indirect block with delete flag */ + if(H5AC_unprotect(iblock->hdr->f, H5AC_dxpl_id, H5AC_FHEAP_IBLOCK, iblock->addr, tmp_iblock, H5AC__DIRTIED_FLAG|H5AC__DELETED_FLAG) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") + tmp_iblock = NULL; + } /* end if */ + } /* end if */ + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF_iblock_decr() */ @@ -195,23 +210,9 @@ HDfprintf(stderr, "%s: Marking indirect block as dirty\n", FUNC); /* Sanity check */ HDassert(iblock); -/* XXX: Need to mark a protected block as dirty eventually also... */ -{ - unsigned entry_status; /* Indirect block entry status */ - - if(H5AC_get_entry_status(iblock->hdr->f, iblock->addr, &entry_status) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to query fractal heap indirect block status") - HDassert(entry_status & H5AC_ES__IN_CACHE); - - if(!(entry_status & H5AC_ES__IS_PROTECTED)) { - /* Mark indirect block as dirty in cache */ - if(H5AC_mark_pinned_entry_dirty(iblock->hdr->f, iblock, FALSE, 0) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark fractal heap indirect block as dirty") - } /* end if */ -} - - /* Set the dirty flag for the indirect block */ - iblock->dirty = TRUE; + /* Mark indirect block as dirty in cache */ + if(H5AC_mark_pinned_or_protected_entry_dirty(iblock->hdr->f, iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark fractal heap indirect block as dirty") done: FUNC_LEAVE_NOAPI(ret_value) @@ -219,245 +220,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5HF_man_iblock_skip_blocks - * - * Purpose: Add skipped direct blocks to free space for heap - * - * Return: SUCCEED/FAIL - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Apr 3 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5HF_man_iblock_skip_blocks(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_indirect_t *iblock, - haddr_t iblock_addr, unsigned start_entry, unsigned nentries) -{ - H5HF_free_section_t *sec_node; /* Pointer to free list section for range */ - hsize_t sect_off; /* Offset of free section in heap */ - unsigned curr_row; /* Current row in indirect block */ - unsigned curr_col; /* Current column in indirect block */ - unsigned u; /* Local index variables */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5HF_man_iblock_skip_blocks) -#ifdef QAK -HDfprintf(stderr, "%s: start_entry = %u, nentries = %u\n", FUNC, start_entry, nentries); -#endif /* QAK */ - - /* - * Check arguments. - */ - HDassert(hdr); - HDassert(iblock); - HDassert(H5F_addr_defined(iblock_addr)); - - /* Compute starting column & row */ - curr_row = start_entry / hdr->man_dtable.cparam.width; - curr_col = start_entry % hdr->man_dtable.cparam.width; - - /* Initialize information for rows skipped over */ - sect_off = iblock->block_off; - for(u = 0; u < curr_row; u++) - sect_off += hdr->man_dtable.row_block_size[u] * hdr->man_dtable.cparam.width; - sect_off += hdr->man_dtable.row_block_size[curr_row] * curr_col; -#ifdef QAK -HDfprintf(stderr, "%s: sect_off = %Zu\n", FUNC, sect_off); -#endif /* QAK */ - - /* Loop over the blocks to skip */ - for(u = start_entry; u < (start_entry + nentries); /* u is advanced in loop */) { - unsigned row_entries; /* Number of entries in a particular row */ - - /* Compute number of entries in (possible partial) current row */ - row_entries = MIN(hdr->man_dtable.cparam.width - curr_col, (start_entry + nentries) - u); -#ifdef QAK -HDfprintf(stderr, "%s: u = %u\n", FUNC, u); -HDfprintf(stderr, "%s: curr_col = %u, curr_row = %u\n", FUNC, curr_col, curr_row); -HDfprintf(stderr, "%s: row_entries = %u, hdr->man_dtable.row_dblock_free[%u] = %Hu\n", FUNC, row_entries, curr_row, hdr->man_dtable.row_dblock_free[curr_row]); -#endif /* QAK */ - - /* Add free space section for blocks in this row */ - - /* Create free list section node for blocks skipped over */ - 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 = sect_off; - sec_node->sect_info.size = hdr->man_dtable.row_dblock_free[curr_row]; - sec_node->sect_info.cls = &hdr->sect_cls[H5FS_SECT_FHEAP_RANGE]; - sec_node->sect_info.state = H5FS_SECT_LIVE; - sec_node->u.range.iblock = iblock; - if(H5HF_iblock_incr(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") - sec_node->u.range.row = curr_row; - sec_node->u.range.col = curr_col; - sec_node->u.range.num_entries = row_entries; - - /* Add new free space to the global list of space */ - if(H5HF_space_add(hdr, dxpl_id, sec_node) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add indirect block free space to global list") - - /* Advance row & column position */ - sect_off += row_entries * hdr->man_dtable.row_block_size[curr_row]; - curr_row++; - curr_col = 0; /* (first partial row aligns this) */ - - /* Increment index variable */ - 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) - HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_man_iblock_skip_blocks() */ - - -/*------------------------------------------------------------------------- - * Function: H5HF_man_iblock_skip_ranges - * - * Purpose: Add skipped indirect ranges to free space for heap - * - * Return: SUCCEED/FAIL - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Apr 4 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5HF_man_iblock_skip_ranges(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_indirect_t *iblock, - haddr_t iblock_addr, unsigned start_entry, unsigned nentries) -{ - H5HF_free_section_t *sec_node; /* Pointer to free list section for range */ - hsize_t sect_off; /* Offset of free section in heap */ - size_t row_dblock_free_space; /* Size of free space for row of direct blocks in a row */ - size_t acc_row_dblock_free_space; /* Accumulated size of free space for row of direct blocks in a row */ - unsigned curr_row; /* Current row in indirect block */ - unsigned curr_col; /* Current column in indirect block */ - unsigned u, w; /* Local index variables */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5HF_man_iblock_skip_ranges) -#ifdef QAK -HDfprintf(stderr, "%s: start_entry = %u, nentries = %u\n", FUNC, start_entry, nentries); -#endif /* QAK */ - - /* - * Check arguments. - */ - HDassert(hdr); - HDassert(iblock); - HDassert(H5F_addr_defined(iblock_addr)); - - /* Compute starting column & row */ - curr_row = start_entry / hdr->man_dtable.cparam.width; - curr_col = start_entry % hdr->man_dtable.cparam.width; -#ifdef QAK -HDfprintf(stderr, "%s: curr_col = %u, curr_row = %u\n", FUNC, curr_col, curr_row); -#endif /* QAK */ - - /* Initialize information for rows skipped over */ - sect_off = iblock->block_off; - for(u = 0; u < curr_row; u++) - sect_off += hdr->man_dtable.row_block_size[u] * hdr->man_dtable.cparam.width; - sect_off += hdr->man_dtable.row_block_size[curr_row] * curr_col; -#ifdef QAK -HDfprintf(stderr, "%s: sect_off = %Zu\n", FUNC, sect_off); -#endif /* QAK */ - - /* Loop over the blocks to skip */ - for(u = start_entry; u < (start_entry + nentries); /* u is advanced in loop */) { - unsigned row_entries; /* Number of entries in a particular row */ - unsigned num_rows; /* Number of rows in indirect blocks referenced */ - - /* Compute number of rows in indirect blocks covered by entry */ - num_rows = (H5V_log2_of2((uint32_t)hdr->man_dtable.row_block_size[curr_row]) - - H5V_log2_of2(hdr->man_dtable.cparam.start_block_size)) - 1; - - /* Compute number of entries in (possible partial) current row */ - row_entries = MIN(hdr->man_dtable.cparam.width - curr_col, (start_entry + nentries) - u); -#ifdef QAK -HDfprintf(stderr, "%s: u = %u\n", FUNC, u); -HDfprintf(stderr, "%s: curr_col = %u, curr_row = %u\n", FUNC, curr_col, curr_row); -HDfprintf(stderr, "%s: row_entries = %u, num_rows = %u\n", FUNC, row_entries, num_rows); -#endif /* QAK */ - - /* Loop over rows in indirect blocks covered */ - acc_row_dblock_free_space = 0; - for(w = 0; w < num_rows; w++) { - - /* Compute free space in direct blocks for this row */ - row_dblock_free_space = hdr->man_dtable.cparam.width * hdr->man_dtable.row_dblock_free[w]; - acc_row_dblock_free_space += row_dblock_free_space; -#ifdef QAK -HDfprintf(stderr, "%s: w = %u\n", FUNC, w); -HDfprintf(stderr, "%s: hdr->man_dtable.row_dblock_free[%u] = %Zu\n", FUNC, w, hdr->man_dtable.row_dblock_free[w]); -#endif /* QAK */ - - /* Add "indirect" free space section for blocks in this row */ - - /* Create free list section node for blocks skipped over */ - 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 = sect_off + hdr->man_dtable.row_block_off[w]; -#ifdef QAK -HDfprintf(stderr, "%s: sec_node->sect_info.addr = %a\n", FUNC, sec_node->sect_info.addr); -#endif /* QAK */ - sec_node->sect_info.size = hdr->man_dtable.row_dblock_free[w]; - sec_node->sect_info.cls = &hdr->sect_cls[H5FS_SECT_FHEAP_INDIRECT]; - sec_node->sect_info.state = H5FS_SECT_LIVE; - sec_node->u.indirect.iblock = iblock; - if(H5HF_iblock_incr(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") - sec_node->u.indirect.row = curr_row; - sec_node->u.indirect.col = curr_col; - sec_node->u.indirect.num_entries = row_entries; - sec_node->u.indirect.indir_row = w; - sec_node->u.indirect.indir_nrows = num_rows; - - /* Add new free space to the global list of space */ - if(H5HF_space_add(hdr, dxpl_id, sec_node) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add indirect block free space to global list") - } /* end for */ -#ifdef QAK -HDfprintf(stderr, "%s: acc_row_dblock_free_space = %Zu\n", FUNC, acc_row_dblock_free_space); -#endif /* QAK */ - - /* Advance row & column position */ - sect_off += row_entries * hdr->man_dtable.row_block_size[curr_row]; - curr_row++; - curr_col = 0; /* (first partial row aligns this) */ - - /* 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) - HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_man_iblock_skip_ranges() */ - - -/*------------------------------------------------------------------------- * Function: H5HF_man_iblock_root_create * * Purpose: Create root indirect block @@ -470,7 +232,7 @@ done: * *------------------------------------------------------------------------- */ -static herr_t +herr_t H5HF_man_iblock_root_create(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_size) { H5HF_indirect_t *iblock; /* Pointer to indirect block */ @@ -508,7 +270,7 @@ HDfprintf(stderr, "%s: nrows = %u\n", FUNC, nrows); #endif /* QAK */ /* Allocate root indirect block */ - if(H5HF_man_iblock_create(hdr, dxpl_id, (hsize_t)0, nrows, hdr->man_dtable.max_root_rows, &iblock_addr) < 0) + if(H5HF_man_iblock_create(hdr, dxpl_id, NULL, 0, nrows, hdr->man_dtable.max_root_rows, &iblock_addr) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap indirect block") #ifdef QAK HDfprintf(stderr, "%s: iblock_addr = %a\n", FUNC, iblock_addr); @@ -532,30 +294,27 @@ HDfprintf(stderr, "%s: have_direct_block = %u\n", FUNC, (unsigned)have_direct_bl if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, hdr->man_dtable.table_addr, hdr->man_dtable.cparam.start_block_size, iblock, 0, H5AC_WRITE))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block") - /* Point indirect block at direct block to add */ - iblock->ents[0].addr = hdr->man_dtable.table_addr; - - /* Make direct block share parent indirect block */ + /* Attach direct block to new root indirect block */ dblock->parent = iblock; dblock->par_entry = 0; - if(H5HF_iblock_incr(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") + if(H5HF_man_iblock_attach(iblock, 0, hdr->man_dtable.table_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't attach root direct block to parent indirect block") - /* Unlock first (root) direct block */ + /* Unlock first (previously the root) direct block */ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, dblock, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block") dblock = NULL; } /* end if */ - /* Set up iterator at correct location */ - if(H5HF_man_iter_start_entry(hdr, &hdr->next_block, iblock, have_direct_block) < 0) + /* Start iterator at correct location */ + if(H5HF_hdr_start_iter(hdr, iblock, (hsize_t)(have_direct_block ? hdr->man_dtable.cparam.start_block_size : 0), have_direct_block) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize block iterator") /* Check for skipping over direct blocks, in order to get to large enough block */ if(min_dblock_size > hdr->man_dtable.cparam.start_block_size) { /* Add skipped blocks to heap's free space */ - if(H5HF_man_iblock_skip_blocks(hdr, dxpl_id, iblock, iblock_addr, - have_direct_block, ((nrows - 1) * hdr->man_dtable.cparam.width) - have_direct_block) < 0) + if(H5HF_hdr_skip_blocks(hdr, dxpl_id, iblock, have_direct_block, + ((nrows - 1) * hdr->man_dtable.cparam.width) - have_direct_block) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space") } /* end if */ @@ -582,13 +341,9 @@ HDfprintf(stderr, "%s: have_direct_block = %u\n", FUNC, (unsigned)have_direct_bl acc_dblock_free -= hdr->man_dtable.row_dblock_free[0]; /* Extend heap to cover new root indirect block */ - if(H5HF_hdr_extend_heap(hdr, hdr->man_dtable.row_block_off[nrows], acc_dblock_free) < 0) + if(H5HF_hdr_adjust_heap(hdr, hdr->man_dtable.row_block_off[nrows], (hssize_t)acc_dblock_free) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block") - /* 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_man_iblock_root_create() */ @@ -607,7 +362,7 @@ done: * *------------------------------------------------------------------------- */ -static herr_t +herr_t H5HF_man_iblock_root_double(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_size) { H5HF_indirect_t *iblock; /* Pointer to root indirect block */ @@ -665,7 +420,7 @@ 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, -* so avoid data copy in H5MF_realloc() call by just free'ing the space and +* to 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 @@ -674,8 +429,8 @@ HDfprintf(stderr, "%s: new_next_entry = %u\n", FUNC, new_next_entry); * QAK - 3/14/2006 */ /* 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_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block") + if(H5MF_xfree(hdr->f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, iblock->addr, (hsize_t)iblock->size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block file space") /* Compute size of buffer needed for new indirect block */ iblock->nrows = new_nrows; @@ -695,8 +450,8 @@ HDfprintf(stderr, "%s: new_addr = %a\n", FUNC, new_addr); /* Check for skipping over rows and add free section for skipped rows */ if(skip_direct_rows) { /* Add skipped blocks to heap's free space */ - if(H5HF_man_iblock_skip_blocks(hdr, dxpl_id, iblock, new_addr, - next_entry, (new_next_entry - next_entry)) < 0) + if(H5HF_hdr_skip_blocks(hdr, dxpl_id, iblock, next_entry, + (new_next_entry - next_entry)) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't add skipped blocks to heap's free space") } /* end if */ @@ -714,9 +469,11 @@ HDfprintf(stderr, "%s: new_addr = %a\n", FUNC, new_addr); HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty") /* Move object in cache, if it actually was relocated */ - if(H5F_addr_ne(iblock->addr, new_addr)) + 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") + iblock->addr = new_addr; + } /* end if */ /* Update other shared header info */ hdr->man_dtable.curr_root_rows = new_nrows; @@ -728,363 +485,186 @@ HDfprintf(stderr, "%s: hdr->man_dtable.row_block_off[new_nrows - 1] = %Hu\n", FU HDfprintf(stderr, "%s: hdr->man_dtable.row_block_off[new_nrows] = %Hu\n", FUNC, hdr->man_dtable.row_block_off[new_nrows]); HDfprintf(stderr, "%s: acc_dblock_free = %Hu\n", FUNC, acc_dblock_free); #endif /* QAK */ - if(H5HF_hdr_extend_heap(hdr, 2 * hdr->man_dtable.row_block_off[new_nrows - 1], acc_dblock_free) < 0) + if(H5HF_hdr_adjust_heap(hdr, 2 * hdr->man_dtable.row_block_off[new_nrows - 1], (hssize_t)acc_dblock_free) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block") - /* Mark heap header as modified */ - 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) - HGOTO_ERROR(H5E_HEAP, H5E_CANTMODIFY, FAIL, "unable to update indirect block for block iterator") - - /* Release the indirect block (marked as dirty) */ - if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, iblock->addr, iblock, H5AC__DIRTIED_FLAG) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") - done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF_man_iblock_root_double() */ /*------------------------------------------------------------------------- - * Function: H5HF_man_iblock_place_dblock - * - * Purpose: Find indirect block with location for placing a direct block + * Function: H5HF_man_iblock_root_halve * - * Note: Creates necessary indirect blocks + * Purpose: Halve size of root indirect block * - * Return: Pointer to indirect block on success, NULL on failure + * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu - * Mar 14 2006 + * Jun 12 2006 * *------------------------------------------------------------------------- */ -H5HF_indirect_t * -H5HF_man_iblock_place_dblock(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_size, - size_t *entry_p, size_t *dblock_size) +static herr_t +H5HF_man_iblock_root_halve(H5HF_indirect_t *iblock, hid_t dxpl_id) { - H5HF_indirect_t *ret_value; /* Return value */ + H5HF_hdr_t *hdr = iblock->hdr; /* Pointer to heap header */ + haddr_t new_addr; /* New address of indirect block */ + hsize_t acc_dblock_free; /* Accumulated free space in direct blocks */ + unsigned max_child_row; /* Row for max. child entry */ + unsigned new_nrows; /* New # of rows */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5HF_man_iblock_place_dblock) -#ifdef QAK -HDfprintf(stderr, "%s: min_dblock_size = %Zu\n", FUNC, min_dblock_size); -#endif /* QAK */ + FUNC_ENTER_NOAPI_NOINIT(H5HF_man_iblock_root_halve) - /* - * Check arguments. - */ + /* Sanity check */ + HDassert(iblock); + HDassert(iblock->parent == NULL); HDassert(hdr); - HDassert(min_dblock_size > 0); - - /* Check for creating first indirect block */ - if(hdr->man_dtable.curr_root_rows == 0) { - if(H5HF_man_iblock_root_create(hdr, dxpl_id, min_dblock_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, NULL, "unable to create root indirect block") - } /* end if */ - else { - H5HF_indirect_t *iblock; /* Pointer to indirect block */ - hbool_t walked_up, walked_down; /* Condition variables for finding direct block location */ - unsigned next_row; /* Iterator's next block row */ - unsigned next_entry; /* Iterator's next block entry */ - unsigned min_dblock_row; /* Minimum row for direct block size request */ #ifdef QAK -HDfprintf(stderr, "%s: searching root indirect block\n", FUNC); +HDfprintf(stderr, "%s: Reducing root indirect block\n", FUNC); #endif /* QAK */ - /* Compute min. row for direct block requested */ - min_dblock_row = H5HF_dtable_size_to_row(&hdr->man_dtable, min_dblock_size); -#ifdef QAK -HDfprintf(stderr, "%s: min_dblock_size = %Zu, min_dblock_row = %u\n", FUNC, min_dblock_size, min_dblock_row); -#endif /* QAK */ - - /* Initialize block iterator, if necessary */ - if(!H5HF_man_iter_ready(&hdr->next_block)) { -#ifdef QAK -HDfprintf(stderr, "%s: hdr->man_alloc_size = %Hu\n", FUNC, hdr->man_alloc_size); -#endif /* QAK */ - /* Start iterator with offset of allocated space */ - if(H5HF_man_iter_start_offset(hdr, dxpl_id, &hdr->next_block, hdr->man_alloc_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "unable to set block iterator location") - } /* end if */ - /* Get information about current iterator location */ - if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, - &next_entry, &iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, NULL, "unable to retrieve current block iterator location") + /* Compute maximum row used by child of indirect block */ + max_child_row = iblock->max_child / hdr->man_dtable.cparam.width; + /* Compute new # of rows in root indirect block */ + new_nrows = 1 << (1 + H5V_log2_gen((hsize_t)max_child_row)); #ifdef QAK -HDfprintf(stderr, "%s: Check 1.0\n", FUNC); -HDfprintf(stderr, "%s: iblock = %p\n", FUNC, iblock); +HDfprintf(stderr, "%s: new_nrows = %u\n", FUNC, new_nrows); HDfprintf(stderr, "%s: iblock->nrows = %u\n", FUNC, iblock->nrows); -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 && 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 */ - - /* Compute the number of entries to skip in the current block */ - min_entry = min_dblock_row * hdr->man_dtable.cparam.width; - if(min_dblock_row >= iblock->nrows) - skip_entries = (iblock->nrows * hdr->man_dtable.cparam.width) - next_entry; - else - skip_entries = min_entry - next_entry; -#ifdef QAK -HDfprintf(stderr, "%s: min_entry = %u, skip_entries = %u\n", FUNC, min_entry, skip_entries); -#endif /* QAK */ - - /* Add skipped direct blocks to heap's free space */ - if(H5HF_man_iblock_skip_blocks(hdr, dxpl_id, iblock, iblock->addr, next_entry, skip_entries) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, NULL, "can't add skipped blocks to heap's free space") - /* Get information about new iterator location */ - if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, - &next_entry, &iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, NULL, "unable to retrieve current block iterator location") - } /* end if */ +/* Currently, the old block data is "thrown away" after the space is reallocated, +* to 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 - 6/12/2006 +*/ + /* 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_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block file space") - do { - /* Reset conditions for leaving loop */ - walked_up = walked_down = FALSE; + /* Compute free space in rows to delete */ + acc_dblock_free = 0; + for(u = new_nrows; u < iblock->nrows; u++) + acc_dblock_free += hdr->man_dtable.row_dblock_free[u] * hdr->man_dtable.cparam.width; -#ifdef QAK -HDfprintf(stderr, "%s: Check 2.0\n", FUNC); -HDfprintf(stderr, "%s: iblock = %p\n", FUNC, iblock); -HDfprintf(stderr, "%s: iblock->nrows = %u\n", FUNC, iblock->nrows); -HDfprintf(stderr, "%s: next_row = %u\n", FUNC, next_row); -HDfprintf(stderr, "%s: next_entry = %u\n", FUNC, next_entry); -#endif /* QAK */ + /* Compute size of buffer needed for new indirect block */ + iblock->nrows = new_nrows; + iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock); - /* Check for walking off end of indirect block */ - /* (walk up iterator) */ - while(next_row >= iblock->nrows) { -#ifdef QAK -HDfprintf(stderr, "%s: Off the end of a block\n", FUNC); -#endif /* QAK */ - /* Check for needing to expand root indirect block */ - if(iblock->parent == NULL) { -#ifdef QAK -HDfprintf(stderr, "%s: Doubling root block\n", FUNC); -#endif /* QAK */ - if(H5HF_man_iblock_root_double(hdr, dxpl_id, min_dblock_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, NULL, "unable to double root indirect block") - } /* end if */ - else { -#ifdef QAK -HDfprintf(stderr, "%s: Walking up a level\n", FUNC); -#endif /* QAK */ - /* Move iterator up one level */ - if(H5HF_man_iter_up(&hdr->next_block) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, NULL, "unable to advance current block iterator location") - - /* Increment location of next block at this level */ - if(H5HF_man_iter_next(hdr, &hdr->next_block, 1) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't advance fractal heap block location") - } /* end else */ - - /* Get information about new iterator location */ - if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, - &next_entry, &iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, NULL, "unable to retrieve current block iterator location") - - /* Indicate that we walked up */ - walked_up = TRUE; - } /* end while */ + /* 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_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block") #ifdef QAK -HDfprintf(stderr, "%s: Check 3.0\n", FUNC); -HDfprintf(stderr, "%s: iblock = %p\n", FUNC, iblock); -HDfprintf(stderr, "%s: iblock->nrows = %u\n", FUNC, iblock->nrows); -HDfprintf(stderr, "%s: next_row = %u\n", FUNC, next_row); -HDfprintf(stderr, "%s: next_entry = %u\n", FUNC, next_entry); +HDfprintf(stderr, "%s: new_addr = %a\n", FUNC, new_addr); #endif /* QAK */ - /* Check for walking into child indirect block */ - /* (walk down iterator) */ - if(next_row >= hdr->man_dtable.max_direct_rows) { - hsize_t next_size; /* Size of next direct block to create */ - unsigned child_nrows; /* Number of rows in new indirect block */ + /* Re-allocate direct block entry table */ + if(NULL == (iblock->ents = H5FL_SEQ_REALLOC(H5HF_indirect_ent_t, iblock->ents, (iblock->nrows * hdr->man_dtable.cparam.width)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct entries") -#ifdef QAK -HDfprintf(stderr, "%s: Walking down into child indirect block\n", FUNC); -#endif /* QAK */ -#ifdef QAK -HDfprintf(stderr, "%s: Check 3.1\n", FUNC); -HDfprintf(stderr, "%s: iblock = %p\n", FUNC, iblock); -HDfprintf(stderr, "%s: iblock->nrows = %u\n", FUNC, iblock->nrows); -HDfprintf(stderr, "%s: next_row = %u\n", FUNC, next_row); -HDfprintf(stderr, "%s: next_entry = %u\n", FUNC, next_entry); -#endif /* QAK */ - HDassert(!H5F_addr_defined(iblock->ents[next_entry].addr)); + /* 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") + iblock->addr = new_addr; + } /* end if */ - /* Compute # of rows in next child indirect block to use */ - next_size = hdr->man_dtable.row_block_size[next_row]; - child_nrows = (H5V_log2_gen(next_size) - hdr->man_dtable.first_row_bits) + 1; -#ifdef QAK -HDfprintf(stderr, "%s: child_nrows = %u\n", FUNC, child_nrows); -#endif /* QAK */ + /* Mark indirect block as dirty */ + if(H5HF_iblock_dirty(iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty") - /* Check for skipping over indirect blocks */ - /* (that don't have direct blocks large enough to hold direct block size requested) */ - if(hdr->man_dtable.row_block_size[child_nrows - 1] < min_dblock_size) { - unsigned child_rows_needed; /* Number of rows needed to hold direct block */ - unsigned child_entry; /* Entry of child indirect block */ + /* Update other shared header info */ + hdr->man_dtable.curr_root_rows = new_nrows; + hdr->man_dtable.table_addr = new_addr; + /* Shrink heap to only cover new root indirect block */ #ifdef QAK -HDfprintf(stderr, "%s: Skipping indirect block row that is too small\n", FUNC); -#endif /* QAK */ - /* Compute # of rows needed in child indirect block */ - 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); +HDfprintf(stderr, "%s: hdr->man_dtable.row_block_off[new_nrows - 1] = %Hu\n", FUNC, hdr->man_dtable.row_block_off[new_nrows - 1]); +HDfprintf(stderr, "%s: hdr->man_dtable.row_block_off[new_nrows] = %Hu\n", FUNC, hdr->man_dtable.row_block_off[new_nrows]); +HDfprintf(stderr, "%s: acc_dblock_free = %Hu\n", FUNC, acc_dblock_free); #endif /* QAK */ + if(H5HF_hdr_adjust_heap(hdr, 2 * hdr->man_dtable.row_block_off[new_nrows - 1], -(hssize_t)acc_dblock_free) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce space to cover root direct block") - /* Add skipped indirect ranges to heap's free space */ - if(H5HF_man_iblock_skip_ranges(hdr, dxpl_id, iblock, iblock->addr, next_entry, (child_entry - next_entry)) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, NULL, "can't add skipped blocks to heap's free space") - } /* end if */ - else { - H5HF_indirect_t *new_iblock; /* Pointer to new indirect block */ - hsize_t new_iblock_off; /* Direct block offset in heap address space */ - haddr_t new_iblock_addr; /* New indirect block's address */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_man_iblock_root_halve() */ -#ifdef QAK -HDfprintf(stderr, "%s: Allocating new child indirect block\n", FUNC); -#endif /* QAK */ - /* Compute the direct block's offset in the heap's address space */ - new_iblock_off = iblock->block_off; - new_iblock_off += hdr->man_dtable.row_block_off[next_entry / hdr->man_dtable.cparam.width]; - new_iblock_off += hdr->man_dtable.row_block_size[next_entry / hdr->man_dtable.cparam.width] * (next_entry % hdr->man_dtable.cparam.width); - - /* Allocate new indirect block */ - if(H5HF_man_iblock_create(hdr, dxpl_id, new_iblock_off, child_nrows, child_nrows, &new_iblock_addr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "can't allocate fractal heap indirect block") - - /* Lock new indirect block */ - if(NULL == (new_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, new_iblock_addr, child_nrows, iblock, next_entry, H5AC_WRITE))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap indirect block") - - /* Set parent information */ - HDassert(new_iblock->parent == NULL); - new_iblock->parent = iblock; - new_iblock->par_entry = next_entry; - if(H5HF_iblock_incr(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared indirect block") - - /* Point current indirect block at new indirect block */ - iblock->ents[next_entry].addr = new_iblock_addr; - - /* Move iterator down one level */ - if(H5HF_man_iter_down(&hdr->next_block, new_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTNEXT, NULL, "unable to advance current block iterator location") - - /* Get information about new iterator location */ - if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, - &next_entry, NULL) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, NULL, "unable to retrieve current block iterator location") - next_size = hdr->man_dtable.row_block_size[next_row]; -#ifdef QAK -HDfprintf(stderr, "%s: next_row = %u\n", FUNC, next_row); -HDfprintf(stderr, "%s: next_entry = %u\n", FUNC, next_entry); -#endif /* QAK */ + +/*------------------------------------------------------------------------- + * Function: H5HF_man_iblock_root_revert + * + * Purpose: Revert root indirect block back to root direct block + * + * Note: Any sections left pointing to the old root indirect block + * will be cleaned up by the free space manager + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 31 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF_man_iblock_root_revert(H5HF_indirect_t *root_iblock, hid_t dxpl_id) +{ + H5HF_hdr_t *hdr; /* Pointer to heap's header */ + H5HF_direct_t *dblock = NULL; /* Pointer to new root indirect block */ + haddr_t dblock_addr; /* Direct block's address in the file */ + size_t dblock_size; /* Direct block's size */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_man_iblock_root_revert) - /* Check for skipping over rows and add free section for skipped rows */ - if(min_dblock_size > next_size) { - unsigned new_entry; /* Entry of direct block which is large enough */ + /* + * Check arguments. + */ + HDassert(root_iblock); - /* Compute entry for direct block size requested */ - new_entry = hdr->man_dtable.cparam.width * min_dblock_row; #ifdef QAK -HDfprintf(stderr, "%s: Skipping rows in new child indirect block - new_entry = %u\n", FUNC, new_entry); +HDfprintf(stderr, "%s: Reverting root indirect block\n", FUNC); #endif /* QAK */ - /* Add skipped blocks to heap's free space */ - if(H5HF_man_iblock_skip_blocks(hdr, dxpl_id, new_iblock, new_iblock->addr, 0, new_entry) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, NULL, "can't add skipped blocks to heap's free space") - } /* end if */ - - /* Mark new indirect block as modified */ - if(H5HF_iblock_dirty(new_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, NULL, "can't mark indirect block as dirty") + /* Set up local convenience variables */ + hdr = root_iblock->hdr; + dblock_addr = root_iblock->ents[0].addr; + dblock_size = hdr->man_dtable.cparam.start_block_size; - /* Mark current indirect block as modified */ - if(H5HF_iblock_dirty(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, NULL, "can't mark indirect block as dirty") + /* Get pointer to last direct block */ + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, root_iblock, 0, H5AC_WRITE))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block") - /* Unprotect child indirect block */ - if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, new_iblock->addr, new_iblock, H5AC__DIRTIED_FLAG) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release fractal heap indirect block") - } /* end else */ + /* Detach direct block from parent */ + if(H5HF_man_iblock_detach(dblock->parent, dxpl_id, dblock->par_entry) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't detach direct block from parent indirect block") + dblock->parent = NULL; + dblock->par_entry = 0; - /* Get information about new iterator location */ - if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, - &next_entry, &iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, NULL, "unable to retrieve current block iterator location") + /* Point root at direct block */ + hdr->man_dtable.curr_root_rows = 0; + hdr->man_dtable.table_addr = dblock_addr; - /* Indicate that we walked down */ - walked_down = TRUE; - } /* end if */ - } while(walked_down || walked_up); - } /* end else */ - - /* Get information about iterator location */ -{ - H5HF_indirect_t *iblock; /* Pointer to indirect block */ - unsigned next_row; /* Iterator's next block row */ - unsigned next_entry; /* Iterator's next block entry */ - size_t next_size; /* Size of next direct block to create */ - - if(H5HF_man_iter_curr(&hdr->next_block, &next_row, NULL, - &next_entry, &iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, NULL, "unable to retrieve current block iterator location") - HDassert(next_row < iblock->nrows); - next_size = hdr->man_dtable.row_block_size[next_row]; - - /* Check for skipping over blocks */ - if(min_dblock_size > next_size) { -HDfprintf(stderr, "%s: Skipping direct block sizes not supported, min_dblock_size = %Zu, next_size = %Zu\n", FUNC, min_dblock_size, next_size); -HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, NULL, "skipping direct block sizes not supported yet") - } /* end if */ - - /* Set entry for new direct block to use */ - *entry_p = next_entry; - - /* Set size of direct block to create */ - *dblock_size = next_size; - - /* Set return value */ - ret_value = iblock; -} + /* Reset 'next block' iterator */ + if(H5HF_hdr_reset_iter(hdr, (hsize_t)dblock_size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator") done: + if(dblock && H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block") + FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_man_iblock_place_dblock() */ +} /* end H5HF_man_iblock_root_revert() */ /*------------------------------------------------------------------------- @@ -1132,12 +712,6 @@ H5HF_man_iblock_alloc_range(H5HF_hdr_t *hdr, hid_t dxpl_id, /* Compute info about range */ cur_entry = (old_sec_node->u.range.row * hdr->man_dtable.cparam.width) + old_sec_node->u.range.col; - /* Check for range covering indirect blocks */ - if(old_sec_node->u.range.row >= hdr->man_dtable.max_direct_rows) { -HDfprintf(stderr, "%s: Can't handle range sections over indirect blocks yet\n", FUNC); -HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "'range' free space sections over indirect blocks not supported yet") - } /* end if */ - /* Get a pointer to the indirect block covering the range */ iblock = old_sec_node->u.range.iblock; HDassert(iblock); @@ -1146,42 +720,13 @@ HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "'range' free space sections over i HDfprintf(stderr, "%s: cur_entry = %u\n", FUNC, cur_entry); HDfprintf(stderr, "%s: old_sec_node->u.range.num_entries = %u\n", FUNC, old_sec_node->u.range.num_entries); #endif /* QAK */ -#ifdef QAK -HDfprintf(stderr, "%s: hdr->man_dtable.row_block_size[old_sec_node->u.range.row] = %Hu\n", FUNC, hdr->man_dtable.row_block_size[old_sec_node->u.range.row]); -HDfprintf(stderr, "%s: old_sec_node->sect_addr = %a\n", FUNC, old_sec_node->sect_addr); -#endif /* QAK */ /* Create direct block of appropriate size */ - if(H5HF_man_dblock_create(dxpl_id, hdr, iblock, cur_entry, (size_t)hdr->man_dtable.row_block_size[old_sec_node->u.range.row], (hsize_t)old_sec_node->sect_info.addr, &dblock_addr, &dblock_sec_node) < 0) + if(H5HF_man_dblock_create(dxpl_id, hdr, iblock, cur_entry, &dblock_addr, &dblock_sec_node) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block") - /* Hook direct block up to indirect block */ - iblock->ents[cur_entry].addr = dblock_addr; - - /* Mark indirect block as dirty */ - if(H5HF_iblock_dirty(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty") - - /* Check for only single block covered in range section */ - if(old_sec_node->u.range.num_entries == 1) { - /* Drop reference count on indirect block that free section is in */ - if(H5HF_iblock_decr(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") - - /* Free section structure */ - H5FL_FREE(H5HF_free_section_t, old_sec_node); - } /* end if */ - else { - /* Adjust section information */ - old_sec_node->sect_info.addr += hdr->man_dtable.row_block_size[old_sec_node->u.range.row]; - - /* Adjust range information */ - old_sec_node->u.range.col++; - old_sec_node->u.range.num_entries--; - - /* Add section back to free space list */ - if(H5HF_space_add(hdr, dxpl_id, old_sec_node) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add indirect block free space to global list") - } /* end else */ + /* Reduce (& possibly re-add) 'range' section */ + if(H5HF_sect_range_reduce(hdr, dxpl_id, old_sec_node) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce indirect section node") /* Point 'sec_node' at new direct block section node */ *sec_node = dblock_sec_node; @@ -1217,7 +762,6 @@ H5HF_man_iblock_alloc_indirect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t child_iblock_addr; /* Address of child indirect block */ haddr_t dblock_addr; /* New direct block's address */ H5HF_free_section_t *dblock_sec_node = NULL; /* Pointer to direct block's section node */ - H5HF_free_section_t *range_sec_node = NULL; /* Pointer to new range section node */ H5HF_free_section_t *old_sec_node = *sec_node; /* Pointer to old indirect section node */ unsigned curr_entry; /* Current entry in indirect block */ unsigned dblock_entry; /* Entry of direct block in child indirect block */ @@ -1246,8 +790,10 @@ H5HF_man_iblock_alloc_indirect(H5HF_hdr_t *hdr, hid_t dxpl_id, #ifdef QAK HDfprintf(stderr, "%s: curr_entry = %u\n", FUNC, curr_entry); +HDfprintf(stderr, "%s: iblock->addr = %a\n", FUNC, iblock->addr); +HDfprintf(stderr, "%s: iblock->block_off = %Hu\n", FUNC, iblock->block_off); +HDfprintf(stderr, "%s: iblock->parent = %p\n", FUNC, iblock->parent); HDfprintf(stderr, "%s: iblock->ents[curr_entry].addr = %a\n", FUNC, iblock->ents[curr_entry].addr); -HDfprintf(stderr, "%s: iblock->ents[curr_entry].free_space = %Hu\n", FUNC, iblock->ents[curr_entry].free_space); HDfprintf(stderr, "%s: old_sec_node->u.indirect.indir_nrows = %u\n", FUNC, old_sec_node->u.indirect.indir_nrows); HDfprintf(stderr, "%s: old_sec_node->u.indirect.num_entries = %u\n", FUNC, old_sec_node->u.indirect.num_entries); #endif /* QAK */ @@ -1260,42 +806,16 @@ HDfprintf(stderr, "%s: old_sec_node->u.indirect.num_entries = %u\n", FUNC, old_s HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") } /* end if */ else { - hsize_t new_iblock_off; /* Offset of new indirect block */ - - /* Compute heap offset of new indirect block */ - new_iblock_off = iblock->block_off + - hdr->man_dtable.row_block_off[old_sec_node->u.indirect.row] + - (old_sec_node->u.indirect.col * - hdr->man_dtable.row_block_size[old_sec_node->u.indirect.row]); -#ifdef QAK -HDfprintf(stderr, "%s: iblock->block_off = %Hu\n", FUNC, iblock->block_off); -HDfprintf(stderr, "%s: new_iblock_off = %Hu\n", FUNC, new_iblock_off); -#endif /* QAK */ - /* Create child indirect block */ - if(H5HF_man_iblock_create(hdr, dxpl_id, new_iblock_off, old_sec_node->u.indirect.indir_nrows, old_sec_node->u.indirect.indir_nrows, &child_iblock_addr) < 0) + if(H5HF_man_iblock_create(hdr, dxpl_id, iblock, curr_entry, old_sec_node->u.indirect.indir_nrows, old_sec_node->u.indirect.indir_nrows, &child_iblock_addr) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap indirect block") /* Lock new child indirect block */ if(NULL == (child_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, child_iblock_addr, old_sec_node->u.indirect.indir_nrows, iblock, curr_entry, H5AC_WRITE))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") - - /* Set parent information */ - HDassert(child_iblock->parent == NULL); - child_iblock->parent = iblock; - child_iblock->par_entry = curr_entry; - if(H5HF_iblock_incr(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") #ifdef QAK HDfprintf(stderr, "%s: child_iblock->child_free_space = %Hu\n", FUNC, child_iblock->child_free_space); #endif /* QAK */ - - /* Hook child up to parent indirect block */ - iblock->ents[curr_entry].addr = child_iblock_addr; - - /* Mark parent indirect block as modified */ - if(H5HF_iblock_dirty(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty") } /* end else */ /* Compute entry for new direct block in child indirect block */ @@ -1308,64 +828,19 @@ HDfprintf(stderr, "%s: old_sec_node->u.indirect.indir_row = %u\n", FUNC, old_sec HDfprintf(stderr, "%s: hdr->man_dtable.row_block_size[old_sec_node->u.indirect.indir_row] = %Hu\n", FUNC, hdr->man_dtable.row_block_size[old_sec_node->u.indirect.indir_row]); HDfprintf(stderr, "%s: old_sec_node->sect_addr = %a\n", FUNC, old_sec_node->sect_addr); #endif /* QAK */ - if(H5HF_man_dblock_create(dxpl_id, hdr, child_iblock, dblock_entry, (size_t)hdr->man_dtable.row_block_size[old_sec_node->u.indirect.indir_row], (hsize_t)old_sec_node->sect_info.addr, &dblock_addr, &dblock_sec_node) < 0) + if(H5HF_man_dblock_create(dxpl_id, hdr, child_iblock, dblock_entry, &dblock_addr, &dblock_sec_node) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block") - /* Hook direct block up to child indirect block */ - child_iblock->ents[dblock_entry].addr = dblock_addr; - - /* Mark child indirect block as modified */ - if(H5HF_iblock_dirty(child_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty") - - /* Create "range" section for other direct blocks in row of child indirect block */ + if(H5HF_sect_range_add(hdr, dxpl_id, (child_iblock->block_off + hdr->man_dtable.row_block_off[old_sec_node->u.indirect.indir_row] + + hdr->man_dtable.row_block_size[old_sec_node->u.indirect.indir_row]), + old_sec_node->sect_info.size, child_iblock, old_sec_node->u.indirect.indir_row, + 1, hdr->man_dtable.cparam.width - 1) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create range section for indirect block's free space") - /* Create free list section node for blocks skipped over */ - if(NULL == (range_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 */ - range_sec_node->sect_info.addr = child_iblock->block_off + hdr->man_dtable.row_block_off[old_sec_node->u.indirect.indir_row] - + hdr->man_dtable.row_block_size[old_sec_node->u.indirect.indir_row]; - range_sec_node->sect_info.size = old_sec_node->sect_info.size; - range_sec_node->sect_info.cls = &hdr->sect_cls[H5FS_SECT_FHEAP_RANGE]; - range_sec_node->sect_info.state = H5FS_SECT_LIVE; - range_sec_node->u.range.iblock = child_iblock; - if(H5HF_iblock_incr(child_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") - range_sec_node->u.range.row = old_sec_node->u.indirect.indir_row; - range_sec_node->u.range.col = 1; - range_sec_node->u.range.num_entries = hdr->man_dtable.cparam.width - 1; - - /* Add new free space to the global list of space */ - if(H5HF_space_add(hdr, dxpl_id, range_sec_node) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add indirect block free space to global list") - - - /* Reduce "indirect" section */ - - /* Check for only single block covered in range section */ - if(old_sec_node->u.indirect.num_entries == 1) { - /* Drop reference count on indirect block that free section is in */ - if(H5HF_iblock_decr(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") - - /* Free section structure */ - H5FL_FREE(H5HF_free_section_t, old_sec_node); - } /* end if */ - else { - /* Adjust section information */ - old_sec_node->sect_info.addr += hdr->man_dtable.row_block_size[old_sec_node->u.indirect.row]; - - /* Adjust range information */ - old_sec_node->u.indirect.col++; - old_sec_node->u.indirect.num_entries--; - - /* Add section back to free space list */ - if(H5HF_space_add(hdr, dxpl_id, old_sec_node) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add indirect block free space to global list") - } /* end else */ + /* Reduce (& possibly re-add) 'indirect' section */ + if(H5HF_sect_indirect_reduce(hdr, dxpl_id, old_sec_node) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce indirect section node") /* Release the child indirect block (marked as dirty) */ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, child_iblock_addr, child_iblock, H5AC__DIRTIED_FLAG) < 0) @@ -1392,9 +867,9 @@ done: * *------------------------------------------------------------------------- */ -static herr_t -H5HF_man_iblock_create(H5HF_hdr_t *hdr, hid_t dxpl_id, - hsize_t block_off, unsigned nrows, unsigned max_rows, haddr_t *addr_p) +herr_t +H5HF_man_iblock_create(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_indirect_t *par_iblock, + unsigned par_entry, unsigned nrows, unsigned max_rows, haddr_t *addr_p) { H5HF_indirect_t *iblock = NULL; /* Pointer to indirect block */ size_t u; /* Local index variable */ @@ -1424,16 +899,12 @@ H5HF_man_iblock_create(H5HF_hdr_t *hdr, hid_t dxpl_id, HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared heap header") #ifdef QAK -HDfprintf(stderr, "%s: nrows = %u, max_nrows = %u\n", FUNC, nrows, max_nrows); +HDfprintf(stderr, "%s: nrows = %u, max_rows = %u\n", FUNC, nrows, max_rows); #endif /* QAK */ /* Set info for direct block */ iblock->rc = 0; - iblock->parent = NULL; /* Temporary, except for root indirect block */ - iblock->par_entry = 0; - iblock->block_off = block_off; iblock->nrows = nrows; iblock->max_rows = max_rows; - iblock->dirty = TRUE; /* Compute size of buffer needed for indirect block */ iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock); @@ -1451,7 +922,26 @@ HDfprintf(stderr, "%s: nrows = %u, max_nrows = %u\n", FUNC, nrows, max_nrows); HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block") iblock->addr = *addr_p; -/* XXX: Update indirect statistics when they are added */ + /* Attach to parent indirect block, if there is one */ + iblock->parent = par_iblock; + iblock->par_entry = par_entry; + if(iblock->parent) { + /* Attach new block to parent */ + if(H5HF_man_iblock_attach(iblock->parent, par_entry, *addr_p) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't attach indirect block to parent indirect block") + + /* Compute the indirect block's offset in the heap's address space */ + /* (based on parent's block offset) */ + iblock->block_off = par_iblock->block_off; + iblock->block_off += hdr->man_dtable.row_block_off[par_entry / hdr->man_dtable.cparam.width]; + iblock->block_off += hdr->man_dtable.row_block_size[par_entry / hdr->man_dtable.cparam.width] * (par_entry % hdr->man_dtable.cparam.width); + } /* end if */ + else + iblock->block_off = 0; /* Must be the root indirect block... */ + + /* Update indirect block's statistics */ + iblock->nchildren = 0; + iblock->max_child = 0; /* Cache the new fractal heap header */ if(H5AC_set(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, *addr_p, iblock, H5AC__NO_FLAGS_SET) < 0) @@ -1517,3 +1007,156 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF_man_iblock_protect() */ + +/*------------------------------------------------------------------------- + * Function: H5HF_man_iblock_attach + * + * Purpose: Attach a block to an indirect block + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 30 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_man_iblock_attach(H5HF_indirect_t *iblock, unsigned entry, haddr_t child_addr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_man_iblock_attach) +#ifdef QAK +HDfprintf(stderr, "%s: iblock = %p, entry = %u, child_addr = %a, iblock_nrows = %u\n", FUNC, iblock, entry, child_addr); +#endif /* QAK */ + + /* + * Check arguments. + */ + HDassert(iblock); + HDassert(H5F_addr_defined(child_addr)); + + /* Increment the reference count on this indirect block */ + if(H5HF_iblock_incr(iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") + + /* Point at the direct block */ + iblock->ents[entry].addr = child_addr; + + /* Check for max. entry used */ + if(entry > iblock->max_child) + iblock->max_child = entry; + + /* Increment the # of child blocks */ + iblock->nchildren++; + + /* Mark indirect block as modified */ + if(H5HF_iblock_dirty(iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_man_iblock_attach() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_man_iblock_detach + * + * Purpose: Detach a block from an indirect block + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 31 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_man_iblock_detach(H5HF_indirect_t *iblock, hid_t dxpl_id, unsigned entry) +{ + unsigned start_children; /* # of children of iblock when routine was entered */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_man_iblock_detach) +#ifdef QAK +HDfprintf(stderr, "%s: iblock = %p, entry = %u, dblock_addr = %a, iblock_nrows = %u\n", FUNC, iblock, entry, dblock_addr); +#endif /* QAK */ + + /* + * Check arguments. + */ + HDassert(iblock); + HDassert(iblock->nchildren); + + /* Reset address of entry */ + iblock->ents[entry].addr = HADDR_UNDEF; + + /* Decrement the # of child blocks */ + /* (If the number of children drop to 0, the indirect block will be + * removed from the heap when it's ref. count drops to zero and the + * metadata cache calls the indirect block destructor) + */ + /* (Track the initial # of children before the block gets modified, because + * this routine is called recursively) + */ + start_children = iblock->nchildren; + iblock->nchildren--; + + /* Reduce the max. entry used, if necessary */ + if(entry == iblock->max_child) { + if(iblock->nchildren > 0) + while(!H5F_addr_defined(iblock->ents[iblock->max_child].addr)) + iblock->max_child--; + else + iblock->max_child = 0; + } /* end if */ + + /* If this is the root indirect block handle some special cases */ + if(iblock->block_off == 0) { + /* If the number of children drops to 1, and that child is the first + * direct block in the heap, convert the heap back to using a root + * direct block + */ + if(iblock->nchildren == 1 && H5F_addr_defined(iblock->ents[0].addr)) + if(H5HF_man_iblock_root_revert(iblock, dxpl_id) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't convert root indirect block back to root direct block") + + /* Check for reducing size of root indirect block */ + if(iblock->nchildren > 0 && iblock->hdr->man_dtable.cparam.start_root_rows != 0 + && entry > iblock->max_child) { + unsigned max_child_row; /* Row for max. child entry */ + + /* Compute information needed for determining whether to reduce size of root indirect block */ + max_child_row = iblock->max_child / iblock->hdr->man_dtable.cparam.width; + + /* Check if the root indirect block should be reduced */ + if(iblock->nrows > 1 && max_child_row <= (iblock->nrows / 2)) + if(H5HF_man_iblock_root_halve(iblock, dxpl_id) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce size of root indirect block") + } /* end if */ + } /* end if */ + + /* Free indirect block disk space, if it has no children (i.e. it's been deleted) */ + if(start_children == 1) { + HDassert(iblock->nchildren == 0); + if(H5MF_xfree(iblock->hdr->f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, iblock->addr, (hsize_t)iblock->size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block disk space") + } /* end if */ + + /* Mark indirect block as modified */ + if(H5HF_iblock_dirty(iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty") + + /* Decrement the reference count on this indirect block */ + /* (should be last, so that potential 'unpin' on this indirect block + * doesn't invalidate the 'iblock' variable) + */ + if(H5HF_iblock_decr(iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't decrement reference count on shared indirect block") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_man_iblock_detach() */ + diff --git a/src/H5HFint.c b/src/H5HFint.c index 149eacc..c374098 100644 --- a/src/H5HFint.c +++ b/src/H5HFint.c @@ -231,25 +231,17 @@ HDfprintf(stderr, "%s: request = %Zu\n", FUNC, request); if((node_found = H5HF_space_find(hdr, dxpl_id, (hsize_t)request, sec_node)) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't locate free space in fractal heap") - /* If we didn't find a node, go make one big enough to hold the requested block */ - if(!node_found) { -#ifdef QAK -HDfprintf(stderr, "%s: Allocate new direct block\n", FUNC); -#endif /* QAK */ + /* If we didn't find a node, go create a direct block big enough to hold the requested block */ + if(!node_found) /* Allocate direct block big enough to hold requested size */ - if(H5HF_man_dblock_new(hdr, dxpl_id, request) < 0) + if(H5HF_man_dblock_new(hdr, dxpl_id, request, sec_node) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTCREATE, FAIL, "can't create fractal heap direct block") - /* Request space from the free space */ - /* (Ought to be able to be filled, now) */ - if(H5HF_space_find(hdr, dxpl_id, (hsize_t)request, sec_node) <= 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't locate free space in fractal heap") - } /* end if */ HDassert(*sec_node); #ifdef QAK -HDfprintf(stderr, "%s: (*sec_node)->sect_addr = %a\n", FUNC, (*sec_node)->sect_addr); -HDfprintf(stderr, "%s: (*sec_node)->sect_size = %Zu\n", FUNC, (*sec_node)->sect_size); -HDfprintf(stderr, "%s: (*sec_node)->type = %u\n", FUNC, (unsigned)(*sec_node)->type); +HDfprintf(stderr, "%s: (*sec_node)->sect_info.addr = %a\n", FUNC, (*sec_node)->sect_info.addr); +HDfprintf(stderr, "%s: (*sec_node)->sect_info.size = %Hu\n", FUNC, (*sec_node)->sect_info.size); +HDfprintf(stderr, "%s: (*sec_node)->sect_info.type = %u\n", FUNC, (*sec_node)->sect_info.type); #endif /* QAK */ done: @@ -279,6 +271,9 @@ H5HF_man_insert(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sec_node, herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5HF_man_insert) +#ifdef QAK +HDfprintf(stderr, "%s: obj_size = %Zu\n", FUNC, obj_size); +#endif /* QAK */ /* * Check arguments. @@ -289,7 +284,7 @@ H5HF_man_insert(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sec_node, HDassert(id); /* Check for indirect section */ - if(sec_node->sect_info.cls->type == H5FS_SECT_FHEAP_INDIRECT) { + if(sec_node->sect_info.type == H5HF_FSPACE_SECT_INDIRECT) { #ifdef QAK HDfprintf(stderr, "%s: sec_node->sect_info.addr = %a\n", FUNC, sec_node->sect_info.addr); HDfprintf(stderr, "%s: sec_node->sect_info.size = %Zu\n", FUNC, sec_node->sect_info.size); @@ -308,7 +303,7 @@ HDfprintf(stderr, "%s: sec_node->u.indirect.indir_nrows = %u\n", FUNC, sec_node- HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't break up indirect free section") } /* end if */ /* Check for range section */ - else if(sec_node->sect_info.cls->type == H5FS_SECT_FHEAP_RANGE) { + else if(sec_node->sect_info.type == H5HF_FSPACE_SECT_RANGE) { #ifdef QAK HDfprintf(stderr, "%s: sec_node->sect_info.addr = %a\n", FUNC, sec_node->sect_info.addr); HDfprintf(stderr, "%s: sec_node->sect_info.size = %Zu\n", FUNC, sec_node->sect_info.size); @@ -323,7 +318,7 @@ HDfprintf(stderr, "%s: sec_node->u.range.num_entries = %u\n", FUNC, sec_node->u. if(H5HF_man_iblock_alloc_range(hdr, dxpl_id, &sec_node) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't break up range free section") } /* end if */ - HDassert(sec_node->sect_info.cls->type == H5FS_SECT_FHEAP_SINGLE); + HDassert(sec_node->sect_info.type == H5HF_FSPACE_SECT_SINGLE); /* Check for serialized 'single' section */ if(sec_node->sect_info.state == H5FS_SECT_SERIALIZED) { @@ -334,8 +329,8 @@ HDfprintf(stderr, "%s: sec_node->u.range.num_entries = %u\n", FUNC, sec_node->u. /* Lock direct block */ #ifdef QAK -HDfprintf(stderr, "%s: sec_node->sect_addr = %a\n", FUNC, sec_node->sect_addr); -HDfprintf(stderr, "%s: sec_node->sect_size = %Zu\n", FUNC, sec_node->sect_size); +HDfprintf(stderr, "%s: sec_node->sect_info.addr = %a\n", FUNC, sec_node->sect_info.addr); +HDfprintf(stderr, "%s: sec_node->sect_info.size = %Hu\n", FUNC, sec_node->sect_info.size); HDfprintf(stderr, "%s: sec_node->u.single.parent = %p\n", FUNC, sec_node->u.single.parent); if(sec_node->u.single.parent) HDfprintf(stderr, "%s: sec_node->u.single.parent->addr = %a\n", FUNC, sec_node->u.single.parent->addr); @@ -365,29 +360,11 @@ HDfprintf(stderr, "%s: dblock->block_off = %Hu\n", FUNC, dblock->block_off); HDassert(sec_node->sect_info.size >= obj_size); #ifdef QAK -HDfprintf(stderr, "%s: sec_node->sect_info.size = %Zu\n", FUNC, sec_node->sect_info.size); +HDfprintf(stderr, "%s: sec_node->sect_info.size = %Hu\n", FUNC, sec_node->sect_info.size); #endif /* QAK */ - if(sec_node->sect_info.size == obj_size) { - /* Drop reference count on parent indirect block of direct block that free section is in */ - HDassert(dblock->parent == NULL || - sec_node->u.single.parent == NULL || - dblock->parent == sec_node->u.single.parent); - if(sec_node->u.single.parent) - if(H5HF_iblock_decr(sec_node->u.single.parent) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") - - /* Release the memory for the free space section */ - H5FL_FREE(H5HF_free_section_t, sec_node); - } /* end if */ - else { - /* Adjust information for section node */ - sec_node->sect_info.addr += obj_size; - sec_node->sect_info.size -= obj_size; - - /* Re-insert section node into heap's free 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") - } /* end else */ + /* Reduce (& possibly re-add) single section */ + if(H5HF_sect_single_reduce(hdr, dxpl_id, sec_node, obj_size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't reduce single section node") #ifdef QAK HDfprintf(stderr, "%s: blk_off = %Zu\n", FUNC, blk_off); @@ -564,9 +541,9 @@ HDfprintf(stderr, "%s: obj_off = %Hu, obj_len = %Zu\n", FUNC, obj_off, obj_len); HDassert(obj_len > 0); /* Check for bad offset or length */ - if(obj_off > hdr->man_alloc_size) + if(obj_off > hdr->man_size) HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "fractal heap object offset too large") - if(obj_len > hdr->man_dtable.cparam.start_block_size) + if(obj_len > hdr->man_dtable.cparam.max_direct_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") @@ -623,22 +600,9 @@ 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; + if(NULL == (sec_node = H5HF_sect_single_new(obj_off, obj_len, + dblock->parent, dblock->par_entry, dblock_addr, dblock_size))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create section for direct block's free space") /* Unlock direct block */ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0) @@ -647,16 +611,15 @@ HDfprintf(stderr, "%s: blk_off = %Zu\n", FUNC, blk_off); /* Update statistics about heap */ hdr->nobjs--; - hdr->total_man_free += obj_len; + + /* Reduce space available in heap */ + if(H5HF_hdr_adj_free(hdr, (ssize_t)obj_len) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't adjust free space for heap") /* 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") - /* 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 abc592a..ef926e8 100644 --- a/src/H5HFiter.c +++ b/src/H5HFiter.c @@ -138,6 +138,9 @@ H5HF_man_iter_start_offset(H5HF_hdr_t *hdr, hid_t dxpl_id, herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5HF_man_iter_start_offset) +#ifdef QAK +HDfprintf(stderr, "%s: offset = %Hu\n", FUNC, offset); +#endif /* QAK */ /* * Check arguments. @@ -270,7 +273,39 @@ done: /*------------------------------------------------------------------------- - * Function: H5HF_man_iter_start + * Function: H5HF_man_iter_set_entry + * + * Purpose: Set the current entry for the iterator + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 31 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_man_iter_set_entry(const H5HF_hdr_t *hdr, H5HF_block_iter_t *biter, unsigned entry) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_man_iter_set_entry) + + /* + * Check arguments. + */ + HDassert(biter); + + /* Set location context */ + biter->curr->entry = entry; + biter->curr->row = entry / hdr->man_dtable.cparam.width; + biter->curr->col = entry % hdr->man_dtable.cparam.width; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HF_man_iter_set_entry() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_man_iter_start_entry * * Purpose: Initialize a block iterator to a particular location within * an indirect block @@ -411,32 +446,18 @@ H5HF_man_iter_next(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter, unsigned nentries) HDassert(biter); HDassert(biter->curr); HDassert(biter->curr->context); - - /* Advance to next entry in current block */ HDassert(biter->curr->row < biter->curr->context->nrows); - if(nentries == 1) { - /* Increment block entry */ - biter->curr->entry++; - /* Increment column */ - biter->curr->col++; - - /* Check for walking off end of column */ - if(biter->curr->col == hdr->man_dtable.cparam.width) { - /* Reset column */ - biter->curr->col = 0; - - /* Increment row & block size */ - biter->curr->row++; - } /* end if */ - } /* end if */ - /* Advance multiple entries */ - else { - biter->curr->entry += 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 */ + /* Advance entry in current block */ + biter->curr->entry += nentries; + biter->curr->row = biter->curr->entry / hdr->man_dtable.cparam.width; + biter->curr->col = biter->curr->entry % hdr->man_dtable.cparam.width; /* HDassert(biter->curr->row <= biter->curr->context->nrows); */ +#ifdef QAK +HDfprintf(stderr, "%s: biter->curr->entry = %u\n", "H5HF_man_iter_next", biter->curr->entry); +HDfprintf(stderr, "%s: biter->curr->row = %u\n", "H5HF_man_iter_next", biter->curr->row); +HDfprintf(stderr, "%s: biter->curr->col = %u\n", "H5HF_man_iter_next", biter->curr->col); +#endif /* QAK */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5HF_man_iter_next() */ @@ -543,50 +564,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5HF_man_iter_update_iblock - * - * Purpose: Update indirect block for current iterator location - * - * Return: SUCCEED/FAIL - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Apr 24 2006 - * - *------------------------------------------------------------------------- - */ -herr_t -H5HF_man_iter_update_iblock(H5HF_block_iter_t *biter, H5HF_indirect_t *iblock) -{ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5HF_man_iter_update_iblock) - - /* - * Check arguments. - */ - HDassert(biter); - HDassert(biter->ready); - HDassert(biter->curr); - HDassert(biter->curr->context); - - /* Release hold on current location's indirect block */ - if(H5HF_iblock_decr(biter->curr->context) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") - - /* Update current location's indirect block */ - biter->curr->context = iblock; - - /* Add hold to current location's indirect block */ - if(H5HF_iblock_incr(biter->curr->context) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_man_iter_update_iblock() */ - - -/*------------------------------------------------------------------------- * Function: H5HF_man_iter_curr * * Purpose: Retrieve information about the current block iterator location diff --git a/src/H5HFpkg.h b/src/H5HFpkg.h index 1927445..f2bcfc4 100644 --- a/src/H5HFpkg.h +++ b/src/H5HFpkg.h @@ -80,6 +80,7 @@ + (h)->sizeof_addr /* File address of free section header */ \ + (h)->sizeof_size /* Total size of heap */ \ + (h)->sizeof_size /* Size of man. space in heap */ \ + + (h)->sizeof_size /* Size of man. space iterator offset in heap */ \ + (h)->sizeof_size /* Size of alloacted man. space in heap */ \ + (h)->sizeof_size /* Size of std. space in heap */ \ + (h)->sizeof_size /* Number of objects in heap */ \ @@ -125,9 +126,9 @@ /* 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 */ -#define H5FS_SECT_FHEAP_RANGE 1 /* Section is a range of direct blocks */ -#define H5FS_SECT_FHEAP_INDIRECT 2 /* Section is a range of _indirect_ blocks in an indirect block row */ +#define H5HF_FSPACE_SECT_SINGLE 0 /* Section is actual bytes in a direct block */ +#define H5HF_FSPACE_SECT_RANGE 1 /* Section is a range of direct blocks */ +#define H5HF_FSPACE_SECT_INDIRECT 2 /* Section is a range of _indirect_ blocks in an indirect block row */ /****************************/ /* Package Private Typedefs */ @@ -148,8 +149,10 @@ typedef struct H5HF_dtable_t { */ /* Computed information (not stored) */ - unsigned max_root_rows; /* Maximum # of rows in root indirect block */ - unsigned max_direct_rows; /* Maximum # of direct rows in any indirect block */ + unsigned max_root_rows; /* Maximum # of rows in root indirect block */ + unsigned max_direct_rows; /* Maximum # of direct rows in any indirect block */ + unsigned start_bits; /* # of bits for starting block size (i.e. log2(start_block_size)) */ + unsigned max_direct_bits; /* # of bits for max. direct block size (i.e. log2(max_direct_size)) */ unsigned max_dir_blk_off_size; /* Max. size of offsets in direct blocks */ unsigned first_row_bits; /* # of bits in address of first row */ hsize_t num_id_first_row; /* Number of IDs in first row of table */ @@ -199,7 +202,7 @@ typedef struct H5HF_free_section_t { haddr_t dblock_addr; /* Address of direct block for free section */ size_t dblock_size; /* Size of direct block */ - /* (Needed to retrieve direct block) */ + /* (Needed to retrieve root direct block) */ } single; struct { H5HF_indirect_t *iblock; /* Indirect block for free section */ @@ -235,6 +238,7 @@ typedef struct H5HF_hdr_t { hsize_t total_size; /* Total amount of space used by heap (managed & standalone) */ hsize_t man_size; /* Total amount of managed space in heap */ hsize_t man_alloc_size; /* Total amount of allocated managed space in heap */ + hsize_t man_iter_off; /* Offset of iterator in managed heap space */ hsize_t std_size; /* Total amount of standalone space in heap */ hsize_t nobjs; /* Number of objects in heap */ @@ -247,16 +251,12 @@ typedef struct H5HF_hdr_t { size_t sizeof_size; /* Size of file sizes */ size_t sizeof_addr; /* Size of file addresses */ 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 */ - hbool_t fspace_open; /* Whether free space is ready */ H5HF_block_iter_t next_block; /* Block iterator for searching for next block with space */ /* Doubling table information */ /* (Partially set by user, partially derived/updated internally) */ H5HF_dtable_t man_dtable; /* Doubling-table info for managed objects */ - H5HF_dtable_t std_dtable; /* Doubling-table info for standalone objects */ /* Information set by user */ H5HF_addrmap_t addrmap; /* Type of address mapping */ @@ -283,13 +283,14 @@ struct H5HF_indirect_t { /* Internal heap information (not stored) */ size_t rc; /* Reference count of child blocks */ - hbool_t dirty; /* Info is modified */ H5HF_hdr_t *hdr; /* Shared heap header info */ struct H5HF_indirect_t *parent; /* Shared parent indirect block info */ unsigned par_entry; /* Entry in parent's table */ haddr_t addr; /* Address of this indirect block on disk */ unsigned nrows; /* Total # of rows in indirect block */ unsigned max_rows; /* Max. # of rows in indirect block */ + unsigned nchildren; /* Number of child blocks */ + unsigned max_child; /* Max. offset used in child entries */ size_t size; /* Size of indirect block on disk */ /* Stored values */ @@ -320,15 +321,6 @@ struct H5HF_t { unsigned fo_count; /* Open object count for file */ }; -/* Fractal heap metadata statistics info */ -typedef struct H5HF_stat_t { - hsize_t total_size; /* Total size of heap allocated (man & std) */ - hsize_t man_size; /* Total size of managed space in heap */ - hsize_t std_size; /* Total size of standalone space in heap */ - hsize_t man_free_space; /* Free space within heap */ - hsize_t nobjs; /* Number of objects in heap */ -} H5HF_stat_t; - /* Fractal heap "parent info" (for loading a block) */ typedef struct H5HF_parent_t { H5HF_hdr_t *hdr; /* Pointer to heap header info */ @@ -357,13 +349,13 @@ H5_DLLVAR const H5AC_class_t H5AC_FHEAP_DBLOCK[1]; H5_DLLVAR const H5AC_class_t H5AC_FHEAP_IBLOCK[1]; /* H5HF single section inherits serializable properties from H5FS_section_class_t */ -H5_DLLVAR H5FS_section_class_t H5FS_SECT_CLS_FHEAP_SINGLE[1]; +H5_DLLVAR H5FS_section_class_t H5HF_FSPACE_SECT_CLS_SINGLE[1]; /* H5HF range section inherits serializable properties from H5FS_section_class_t */ -H5_DLLVAR H5FS_section_class_t H5FS_SECT_CLS_FHEAP_RANGE[1]; +H5_DLLVAR H5FS_section_class_t H5HF_FSPACE_SECT_CLS_RANGE[1]; /* H5HF indirect section inherits serializable properties from H5FS_section_class_t */ -H5_DLLVAR H5FS_section_class_t H5FS_SECT_CLS_FHEAP_INDIRECT[1]; +H5_DLLVAR H5FS_section_class_t H5HF_FSPACE_SECT_CLS_INDIRECT[1]; /* Declare a free list to manage the H5HF_hdr_t struct */ H5FL_EXTERN(H5HF_hdr_t); @@ -380,9 +372,6 @@ H5FL_EXTERN(H5HF_indirect_t); /* Declare a free list to manage the H5HF_indirect_ent_t sequence information */ H5FL_SEQ_EXTERN(H5HF_indirect_ent_t); -/* Declare a free list to manage the H5HF_free_section_t struct */ -H5FL_EXTERN(H5HF_free_section_t); - /******************************/ /* Package Private Prototypes */ @@ -399,37 +388,53 @@ H5_DLL herr_t H5HF_dtable_dest(H5HF_dtable_t *dtable); H5_DLL herr_t H5HF_dtable_lookup(const H5HF_dtable_t *dtable, hsize_t off, unsigned *row, unsigned *col); H5_DLL unsigned H5HF_dtable_size_to_row(H5HF_dtable_t *dtable, size_t block_size); +H5_DLL unsigned H5HF_dtable_size_to_rows(H5HF_dtable_t *dtable, hsize_t size); /* Heap header routines */ H5_DLL herr_t H5HF_hdr_incr(H5HF_hdr_t *hdr); H5_DLL herr_t H5HF_hdr_decr(H5HF_hdr_t *hdr); H5_DLL herr_t H5HF_hdr_dirty(H5HF_hdr_t *hdr); 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_adjust_heap(H5HF_hdr_t *hdr, hsize_t new_size, hssize_t extra_free); +H5_DLL herr_t H5HF_hdr_inc_alloc(H5HF_hdr_t *hdr, size_t alloc_size); +H5_DLL herr_t H5HF_hdr_start_iter(H5HF_hdr_t *hdr, H5HF_indirect_t *iblock, hsize_t curr_off, unsigned curr_entry); +H5_DLL herr_t H5HF_hdr_skip_blocks(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_indirect_t *iblock, unsigned start_entry, unsigned nentries); +H5_DLL herr_t H5HF_hdr_update_iter(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_size); +H5_DLL herr_t H5HF_hdr_inc_iter(H5HF_hdr_t *hdr, hsize_t adv_size, unsigned nentries); +H5_DLL herr_t H5HF_hdr_reverse_iter(H5HF_hdr_t *hdr, hid_t dxpl_id); +H5_DLL herr_t H5HF_hdr_reset_iter(H5HF_hdr_t *hdr, hsize_t curr_off); 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); 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_root_create(H5HF_hdr_t *hdr, hid_t dxpl_id, + size_t min_dblock_size); +H5_DLL herr_t H5HF_man_iblock_root_double(H5HF_hdr_t *hdr, hid_t dxpl_id, + size_t min_dblock_size); 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, H5HF_free_section_t **sec_node); +H5_DLL herr_t H5HF_man_iblock_create(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_indirect_t *par_iblock, unsigned par_entry, unsigned nrows, + unsigned max_rows, haddr_t *addr_p); H5_DLL H5HF_indirect_t *H5HF_man_iblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t iblock_addr, unsigned iblock_nrows, H5HF_indirect_t *par_iblock, unsigned par_entry, H5AC_protect_t rw); +H5_DLL herr_t H5HF_man_iblock_attach(H5HF_indirect_t *iblock, unsigned entry, + haddr_t dblock_addr); +H5_DLL herr_t H5HF_man_iblock_detach(H5HF_indirect_t *iblock, hid_t dxpl_id, unsigned entry); /* Direct block routines */ -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_new(H5HF_hdr_t *fh, hid_t dxpl_id, size_t request, + H5HF_free_section_t **ret_sec_node); 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); + H5HF_indirect_t *par_iblock, unsigned par_entry, 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, @@ -464,21 +469,19 @@ H5_DLL herr_t H5HF_dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, H5_DLL herr_t H5HF_iblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth, haddr_t hdr_addr, unsigned nrows); -/* Statistics routines */ -H5_DLL herr_t H5HF_stat_info(H5HF_t *fh, H5HF_stat_t *stats); - /* Block iteration routines */ H5_DLL herr_t H5HF_man_iter_init(H5HF_block_iter_t *biter); H5_DLL herr_t H5HF_man_iter_start_offset(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_block_iter_t *biter, hsize_t offset); H5_DLL herr_t H5HF_man_iter_start_entry(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter, H5HF_indirect_t *iblock, unsigned start_entry); +H5_DLL herr_t H5HF_man_iter_set_entry(const H5HF_hdr_t *hdr, + H5HF_block_iter_t *biter, unsigned entry); H5_DLL herr_t H5HF_man_iter_next(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter, unsigned nentries); H5_DLL herr_t H5HF_man_iter_up(H5HF_block_iter_t *biter); H5_DLL herr_t H5HF_man_iter_down(H5HF_block_iter_t *biter, H5HF_indirect_t *iblock); H5_DLL herr_t H5HF_man_iter_reset(H5HF_block_iter_t *biter); -H5_DLL herr_t H5HF_man_iter_update_iblock(H5HF_block_iter_t *biter, H5HF_indirect_t *iblock); H5_DLL herr_t H5HF_man_iter_curr(H5HF_block_iter_t *biter, unsigned *row, unsigned *col, unsigned *entry, H5HF_indirect_t **block); H5_DLL herr_t H5HF_man_iter_offset(H5HF_hdr_t *hdr, H5HF_block_iter_t *biter, @@ -494,19 +497,39 @@ H5_DLL herr_t H5HF_space_add(H5HF_hdr_t *hdr, hid_t dxpl_id, 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); +H5_DLL herr_t H5HF_space_delete(H5HF_hdr_t *hdr, hid_t dxpl_id); /* Free space section routines */ +H5_DLL H5HF_free_section_t *H5HF_sect_single_new(hsize_t sect_off, + size_t sect_size, H5HF_indirect_t *parent, unsigned par_entry, + haddr_t dblock_addr, size_t dblock_size); 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_single_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect, size_t amt); +H5_DLL herr_t H5HF_sect_range_add(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t sect_off, + hsize_t sect_size, H5HF_indirect_t *iblock, + unsigned row, unsigned col, unsigned nentries); 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_range_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect); +H5_DLL herr_t H5HF_sect_indirect_add(H5HF_hdr_t *hdr, hid_t dxpl_id, + hsize_t sect_off, hsize_t sect_size, H5HF_indirect_t *iblock, + unsigned row, unsigned col, unsigned nentries, + unsigned indir_row, unsigned indir_nrows); H5_DLL herr_t H5HF_sect_indirect_revive(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sect); +H5_DLL herr_t H5HF_sect_indirect_reduce(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(const H5HF_t *fh, H5HF_create_t *cparam); -H5_DLL size_t H5HF_get_dblock_overhead(const H5HF_t *fh); +H5_DLL unsigned H5HF_get_max_root_rows(const H5HF_t *fh); +H5_DLL unsigned H5HF_get_dtable_width_test(const H5HF_t *fh); +H5_DLL unsigned H5HF_get_dtable_max_drows_test(const H5HF_t *fh); +H5_DLL unsigned H5HF_get_iblock_max_drows_test(const H5HF_t *fh, unsigned pos); 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); diff --git a/src/H5HFprivate.h b/src/H5HFprivate.h index bb562de..b9ae0f4 100644 --- a/src/H5HFprivate.h +++ b/src/H5HFprivate.h @@ -67,6 +67,17 @@ typedef struct H5HF_create_t { /* (i.e. max. size of object to manage) */ } H5HF_create_t; +/* Fractal heap metadata statistics info */ +typedef struct H5HF_stat_t { + hsize_t total_size; /* Total size of heap allocated (man & std) */ + hsize_t nobjs; /* Number of objects in heap */ + hsize_t man_size; /* Total size of managed space in heap */ + hsize_t man_alloc_size; /* Total size of managed space allocated in heap */ + hsize_t man_iter_off; /* Offset of "new block" iterator in managed heap space */ + hsize_t man_free_space; /* Free space within managed heap */ + hsize_t std_size; /* Total size of standalone space in heap */ +} H5HF_stat_t; + /* Fractal heap info (forward decl - defined in H5HFpkg.h) */ typedef struct H5HF_t H5HF_t; @@ -90,6 +101,9 @@ H5_DLL herr_t H5HF_read(H5HF_t *fh, hid_t dxpl_id, const void *id, 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); +/* Statistics routines */ +H5_DLL herr_t H5HF_stat_info(const H5HF_t *fh, H5HF_stat_t *stats); + /* Debugging routines */ #ifdef H5HF_DEBUGGING H5_DLL herr_t H5HF_sects_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, diff --git a/src/H5HFsection.c b/src/H5HFsection.c index f164cdb..48e2ddb 100644 --- a/src/H5HFsection.c +++ b/src/H5HFsection.c @@ -52,30 +52,41 @@ /********************/ /* 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 H5HF_free_section_t *H5HF_sect_node_new(unsigned sect_type, + haddr_t sect_addr, hsize_t sect_size, H5FS_section_state_t state); static herr_t H5HF_sect_node_free(H5HF_free_section_t *sect, H5HF_indirect_t *parent); +static herr_t H5HF_sect_revive(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect); /* '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 htri_t H5HF_sect_single_can_merge(const H5FS_section_info_t *sect1, - const H5FS_section_info_t *sect2, void *udata); +static H5FS_section_info_t *H5HF_sect_single_deserialize(const uint8_t *buf, + haddr_t sect_addr, hsize_t sect_size); +static htri_t H5HF_sect_single_can_merge(H5FS_section_info_t *sect1, + 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 htri_t H5HF_sect_single_can_shrink(H5FS_section_info_t *sect, + void *udata); static herr_t H5HF_sect_single_free(H5FS_section_info_t *sect); +/* 'range' section routines */ +static herr_t H5HF_sect_range_from_single(H5HF_hdr_t *hdr, + H5HF_free_section_t *sect, H5HF_direct_t *dblock); + /* '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 H5FS_section_info_t *H5HF_sect_range_deserialize(const uint8_t *buf, + haddr_t sect_addr, hsize_t sect_size); +static htri_t H5HF_sect_range_can_merge(H5FS_section_info_t *sect1, + H5FS_section_info_t *sect2, void *udata); +static herr_t H5HF_sect_range_merge(H5FS_section_info_t *sect1, + H5FS_section_info_t *sect2, void *udata); +static htri_t H5HF_sect_range_can_shrink(H5FS_section_info_t *sect, + void *udata); +static herr_t H5HF_sect_range_shrink(H5FS_section_info_t **sect, + void *udata); 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); @@ -83,9 +94,8 @@ static herr_t H5HF_sect_range_debug(const H5FS_section_info_t *sect, /* '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 H5FS_section_info_t *H5HF_sect_indirect_deserialize(const uint8_t *buf, + haddr_t sect_addr, hsize_t sect_size); 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); @@ -97,8 +107,8 @@ 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, /* Section type */ +H5FS_section_class_t H5HF_FSPACE_SECT_CLS_SINGLE[1] = {{ + H5HF_FSPACE_SECT_SINGLE, /* Section type */ 0, /* Extra serialized size */ NULL, /* Initialize section class */ NULL, /* Serialize section */ @@ -106,29 +116,29 @@ H5FS_section_class_t H5FS_SECT_CLS_FHEAP_SINGLE[1] = {{ 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 */ + NULL, /* 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, /* Section type */ +H5FS_section_class_t H5HF_FSPACE_SECT_CLS_RANGE[1] = {{ + H5HF_FSPACE_SECT_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_can_merge, /* Can sections merge? */ + H5HF_sect_range_merge, /* Merge sections */ + H5HF_sect_range_can_shrink, /* Can section shrink container?*/ + H5HF_sect_range_shrink, /* 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, /* Section type */ +H5FS_section_class_t H5HF_FSPACE_SECT_CLS_INDIRECT[1] = {{ + H5HF_FSPACE_SECT_INDIRECT, /* Section type */ 0, /* Extra serialized size */ H5HF_sect_indirect_init_cls, /* Initialize section class */ H5HF_sect_indirect_serialize, /* Serialize section */ @@ -157,7 +167,7 @@ H5FL_DEFINE(H5HF_free_section_t); /*------------------------------------------------------------------------- - * Function: H5HF_sect_node_alloc + * Function: H5HF_sect_node_new * * Purpose: Allocate a free space section node of a particular type * @@ -170,38 +180,37 @@ H5FL_DEFINE(H5HF_free_section_t); * *------------------------------------------------------------------------- */ -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 H5HF_free_section_t * +H5HF_sect_node_new(unsigned sect_type, haddr_t sect_addr, hsize_t sect_size, + H5FS_section_state_t sect_state) { H5HF_free_section_t *new_sect; /* New section */ - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_free_section_t *ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_node_alloc) + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_node_new) /* Check arguments. */ HDassert(H5F_addr_defined(sect_addr)); HDassert(sect_size); - HDassert(sect); /* Create free list section node */ if(NULL == (new_sect = H5FL_MALLOC(H5HF_free_section_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list section") + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for direct block free list section") /* Set the information passed in */ new_sect->sect_info.addr = sect_addr; new_sect->sect_info.size = sect_size; /* Set the section's class & state */ - new_sect->sect_info.cls = §_cls[sect_type]; - new_sect->sect_info.state = H5FS_SECT_SERIALIZED; + new_sect->sect_info.type = sect_type; + new_sect->sect_info.state = sect_state; - /* Update the return parameter */ - *sect = (H5FS_section_info_t *)new_sect; + /* Set return value */ + ret_value = new_sect; done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_sect_node_alloc() */ +} /* H5HF_sect_node_new() */ /*------------------------------------------------------------------------- @@ -241,6 +250,121 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_sect_revive + * + * Purpose: Revive a section node + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Monday, June 5, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF_sect_revive(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *sect) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_revive) + + /* Sanity check */ + HDassert(hdr); + HDassert(sect); + + /* Call appropriate 'revive' routine */ + switch(sect->sect_info.type) { + case H5HF_FSPACE_SECT_INDIRECT: + if(H5HF_sect_indirect_revive(hdr, dxpl_id, sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive range free section") + break; + + case H5HF_FSPACE_SECT_RANGE: + if(H5HF_sect_range_revive(hdr, dxpl_id, sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive range free section") + break; + + case H5HF_FSPACE_SECT_SINGLE: + if(H5HF_sect_single_revive(hdr, dxpl_id, sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section") + break; + + default: + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "unknown section type") + } /* end switch */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_revive() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_single_new + * + * Purpose: Create a new 'single' section and return it to the caller + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 30 2006 + * + *------------------------------------------------------------------------- + */ +H5HF_free_section_t * +H5HF_sect_single_new(hsize_t sect_off, size_t sect_size, + H5HF_indirect_t *parent, unsigned par_entry, + haddr_t dblock_addr, size_t dblock_size) +{ + H5HF_free_section_t *sect = NULL; /* 'Single' free space section to add */ + hbool_t par_incr = FALSE; /* Indicate that parent iblock has been incremented */ + H5HF_free_section_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_single_new) + + /* + * Check arguments. + */ + HDassert(sect_size); + + /* Create free space section node */ + if(NULL == (sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_SINGLE, sect_off, (hsize_t)sect_size, H5FS_SECT_LIVE))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for single section") + + /* Set the 'single' specific fields */ + sect->u.single.parent = parent; + if(sect->u.single.parent) { + if(H5HF_iblock_incr(sect->u.single.parent) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared indirect block") + par_incr = TRUE; + } /* end if */ + sect->u.single.par_entry = par_entry; + sect->u.single.dblock_addr = dblock_addr; + sect->u.single.dblock_size = dblock_size; + + /* Set return value */ + ret_value = sect; + +done: + if(!ret_value && sect) { + /* Check if we should decrement parent ref. count */ + if(par_incr) { + HDassert(sect->u.single.parent); + if(H5HF_iblock_decr(sect->u.single.parent) < 0) + HDONE_ERROR(H5E_HEAP, H5E_CANTDEC, NULL, "can't decrement reference count on parent indirect block") + } /* end if */ + + /* Release the section */ + H5FL_FREE(H5HF_free_section_t, sect); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_sect_single_new() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_sect_single_revive * * Purpose: Update the memory information for a 'single' free section @@ -313,6 +437,58 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_sect_single_reduce + * + * Purpose: Reduce the size of a single section (possibly freeing it) + * and re-add it back to the free space manager for the heap + * (if it hasn't been freed) + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 31 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_single_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect, size_t amt) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_single_reduce) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(sect); + HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_SINGLE); + HDassert(sect->sect_info.state == H5FS_SECT_LIVE); + + /* Check for eliminating the section */ + if(sect->sect_info.size == amt) { + /* Free single section */ + if(H5HF_sect_single_free((H5FS_section_info_t *)sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free single section node") + } /* end if */ + else { + /* Adjust information for section */ + sect->sect_info.addr += amt; + sect->sect_info.size -= amt; + + /* Re-insert section node into heap's free space */ + if(H5HF_space_add(hdr, dxpl_id, sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't re-add single section to free space manager") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_sect_single_reduce() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_sect_single_deserialize * * Purpose: Deserialize a buffer into a "live" single section @@ -326,12 +502,12 @@ done: * *------------------------------------------------------------------------- */ -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 H5FS_section_info_t * +H5HF_sect_single_deserialize(const uint8_t *buf, haddr_t sect_addr, + hsize_t sect_size) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_free_section_t *new_sect; /* New section */ + H5FS_section_info_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_single_deserialize) @@ -339,11 +515,13 @@ H5HF_sect_single_deserialize(H5FS_section_class_t *sect_cls, HDassert(buf); HDassert(H5F_addr_defined(sect_addr)); HDassert(sect_size); - HDassert(sect); /* Create free list section node */ - if(H5HF_sect_node_alloc(sect_cls, H5FS_SECT_FHEAP_SINGLE, sect_addr, sect_size, sect) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "allocation failed for direct block free list section") + if(NULL == (new_sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_SINGLE, sect_addr, sect_size, H5FS_SECT_SERIALIZED))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "allocation failed for direct block free list section") + + /* Set return value */ + ret_value = (H5FS_section_info_t *)new_sect; done: FUNC_LEAVE_NOAPI(ret_value) @@ -367,32 +545,87 @@ done: *------------------------------------------------------------------------- */ static htri_t -H5HF_sect_single_can_merge(const H5FS_section_info_t *sect1, - const H5FS_section_info_t *sect2, void UNUSED *udata) +H5HF_sect_single_can_merge(H5FS_section_info_t *_sect1, + H5FS_section_info_t *_sect2, void *_udata) { + H5HF_free_section_t *sect1 = (H5HF_free_section_t *)_sect1; /* Fractal heap free section */ + H5HF_free_section_t *sect2 = (H5HF_free_section_t *)_sect2; /* Fractal heap free section */ + H5HF_add_ud1_t *udata = (H5HF_add_ud1_t *)_udata; /* User callback data */ + H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */ + size_t dblock_size; /* Section's direct block's size */ + size_t dblock_overhead; /* Direct block's overhead */ + hid_t dxpl_id = udata->dxpl_id; /* DXPL ID for operation */ htri_t ret_value = FALSE; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_sect_single_can_merge) + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_single_can_merge) /* Check arguments. */ HDassert(sect1); HDassert(sect2); - HDassert(H5F_addr_lt(sect1->addr, sect2->addr)); + HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr)); + +#ifdef QAK +HDfprintf(stderr, "%s: sect1->sect_info = {%a, %Hu, %u, %s}\n", FUNC, sect1->sect_info.addr, sect1->sect_info.size, sect1->sect_info.type, (sect1->sect_info.state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED")); +HDfprintf(stderr, "%s: sect2->sect_info = {%a, %Hu, %u, %s}\n", FUNC, sect2->sect_info.addr, sect2->sect_info.size, sect2->sect_info.type, (sect2->sect_info.state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED")); +#endif /* QAK */ + + /* Check to see if we should revive either section */ + if(sect1->sect_info.state != H5FS_SECT_LIVE) + if(H5HF_sect_single_revive(hdr, dxpl_id, sect1) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section") + if(sect2->sect_info.state != H5FS_SECT_LIVE) + if(H5HF_sect_revive(hdr, dxpl_id, sect2) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive free section") + /* Check for section occupying entire direct block */ + dblock_size = sect1->u.single.dblock_size; + dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr); #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); +HDfprintf(stderr, "%s: dblock_size = %u\n", FUNC, dblock_size); #endif /* QAK */ + if((dblock_size - dblock_overhead) == sect1->sect_info.size) { + H5HF_direct_t *dblock; /* Pointer to direct block for section */ + haddr_t dblock_addr; /* Section's direct block's address */ + + /* Protect the direct block for the section */ + dblock_addr = sect1->u.single.dblock_addr; +#ifdef QAK +HDfprintf(stderr, "%s: dblock_addr = %a\n", FUNC, dblock_addr); +#endif /* QAK */ + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, sect1->u.single.parent, sect1->u.single.par_entry, H5AC_READ))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block") + HDassert(H5F_addr_eq(dblock->block_off + dblock_overhead, sect1->sect_info.addr)); + + /* Convert 'single' section into 'range' section */ + if(H5HF_sect_range_from_single(hdr, sect1, dblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTCONVERT, FAIL, "can't convert single section into range section") + + /* Destroy direct block */ + if(H5HF_man_dblock_destroy(hdr, dxpl_id, dblock, dblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release direct block") + dblock = NULL; + + /* Check if second section is a range section */ + if(sect2->sect_info.type == H5HF_FSPACE_SECT_RANGE) { + htri_t status; /* Status from range 'can merge' call */ + + /* Check if two sections can merge now */ + /* (i.e. assumes responsibility for passing along 'can merge' callback) */ + if((status = H5HF_sect_range_can_merge((H5FS_section_info_t *)sect1, (H5FS_section_info_t *)sect2, udata)) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTMERGE, FAIL, "can't check for merging sections") + HGOTO_DONE(status) + } /* end if */ + } /* end if */ /* Single section can only merge with other single sections */ - if(sect1->cls->type != sect2->cls->type) + if(sect1->sect_info.type != sect2->sect_info.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)) + if(H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr)) HGOTO_DONE(TRUE) done: @@ -417,30 +650,40 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5HF_sect_single_merge(H5FS_section_info_t *sect1, H5FS_section_info_t *sect2, +H5HF_sect_single_merge(H5FS_section_info_t *_sect1, H5FS_section_info_t *_sect2, void UNUSED *udata) { + H5HF_free_section_t *sect1 = (H5HF_free_section_t *)_sect1; /* Fractal heap free section */ + H5HF_free_section_t *sect2 = (H5HF_free_section_t *)_sect2; /* Fractal heap free section */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_single_merge) /* Check arguments. */ HDassert(sect1); + HDassert(sect1->sect_info.state == H5FS_SECT_LIVE); HDassert(sect2); - HDassert(H5F_addr_eq(sect1->addr + sect1->size, sect2->addr)); + HDassert(sect2->sect_info.state == H5FS_SECT_LIVE); + HDassert(H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.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); +HDfprintf(stderr, "%s: sect1->sect_info.size = %Hu, sect1->sect_info.addr = %a\n", FUNC, sect1->sect_info.size, sect1->sect_info.addr); +HDfprintf(stderr, "%s: sect2->sect_info.size = %Hu, sect2->sect_info.addr = %a\n", FUNC, sect2->sect_info.size, sect2->sect_info.addr); #endif /* QAK */ /* Add second section's size to first section */ - sect1->size += sect2->size; + sect1->sect_info.size += sect2->sect_info.size; /* Get rid of second section */ - if(H5HF_sect_single_free(sect2) < 0) + if(H5HF_sect_single_free((H5FS_section_info_t *)sect2) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node") + /* Defer checking if 'single' section should be converted into 'range' section + * until next pass through the "can merge" callback, to make certain that + * removing a direct block in the root indirect block gives neighboring + * "range" sections a chance to deserialize. *ick* -QAK + */ + done: FUNC_LEAVE_NOAPI(ret_value) } /* H5HF_sect_single_merge() */ @@ -449,14 +692,18 @@ done: /*------------------------------------------------------------------------- * Function: H5HF_sect_single_can_shrink * - * Purpose: Can this section shrink the heap? + * Purpose: Can this section shrink the container? + * + * Note: This isn't actually shrinking the heap (since that's already + * been done) as much as it's cleaning up _after_ the heap + * shrink. * * Return: Success: non-negative (TRUE/FALSE) * * Failure: negative * * Programmer: Quincey Koziol - * Wednesday, May 17, 2006 + * Monday, June 5, 2006 * *------------------------------------------------------------------------- */ @@ -465,117 +712,66 @@ 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 */ + H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */ 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 */ + hid_t dxpl_id = udata->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); + HDassert(sect->sect_info.state == H5FS_SECT_LIVE); #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); +HDfprintf(stderr, "%s: sect->sect_info = {%a, %Hu, %u, %s}\n", FUNC, sect->sect_info.addr, sect->sect_info.size, sect->sect_info.type, (sect->sect_info.state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED")); #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) { + /* Check to see if we should revive section */ + 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; + /* Check for section occupying entire direct block */ dblock_size = sect->u.single.dblock_size; + dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr); #ifdef QAK -HDfprintf(stderr, "%s: dblock_size = %u, dblock_addr = %a\n", FUNC, dblock_size, dblock_addr); +HDfprintf(stderr, "%s: dblock_size = %u\n", FUNC, dblock_size); #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); + if((dblock_size - dblock_overhead) == sect->sect_info.size) { + H5HF_direct_t *dblock; /* Pointer to direct block for section */ + haddr_t dblock_addr; /* Section's direct block's address */ + htri_t status; /* Status from range 'can shrink' call */ + /* Protect the direct block for the section */ + dblock_addr = sect->u.single.dblock_addr; #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); +HDfprintf(stderr, "%s: dblock_addr = %a\n", FUNC, dblock_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; + 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") + HDassert(H5F_addr_eq(dblock->block_off + dblock_overhead, sect->sect_info.addr)); + + /* Convert 'single' section into 'range' section */ + if(H5HF_sect_range_from_single(hdr, sect, dblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTCONVERT, FAIL, "can't convert single section into range section") + + /* Destroy direct block */ + if(H5HF_man_dblock_destroy(hdr, dxpl_id, dblock, dblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release direct block") + dblock = NULL; + + /* Check if section can shrink container now */ + /* (i.e. assumes responsibility for passing along 'can shrink' callback) */ + if((status = H5HF_sect_range_can_shrink((H5FS_section_info_t *)sect, udata)) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't check for shrinking container") + HGOTO_DONE(status) + } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_sect_single_shrink() */ +} /* H5HF_sect_single_can_shrink() */ /*------------------------------------------------------------------------- @@ -592,7 +788,7 @@ done: * *------------------------------------------------------------------------- */ -herr_t +static 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 */ @@ -651,6 +847,72 @@ H5HF_sect_range_init_cls(H5FS_section_class_t *cls, const void UNUSED *udata) /*------------------------------------------------------------------------- + * Function: H5HF_sect_range_add + * + * Purpose: Add a new 'range' section to the free space manager for this + * heap + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 30 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_range_add(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t sect_off, + hsize_t sect_size, H5HF_indirect_t *iblock, + unsigned row, unsigned col, unsigned nentries) +{ + H5HF_free_section_t *sect = NULL; /* 'Range' free space section to add */ + hbool_t iblock_incr = FALSE; /* Indicate that parent iblock has been incremented */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_range_add) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(iblock); + HDassert(sect_size); + HDassert(nentries); + HDassert(row < hdr->man_dtable.max_direct_rows); /* Can't handle ranges on indirect blocks */ + + /* Create free space section node */ + if(NULL == (sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_RANGE, sect_off, sect_size, H5FS_SECT_LIVE))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for range section") + + /* Set the 'range' specific fields */ + sect->u.range.iblock = iblock; + if(H5HF_iblock_incr(sect->u.range.iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") + iblock_incr = TRUE; + sect->u.range.row = row; + sect->u.range.col = col; + sect->u.range.num_entries = nentries; + + /* Add new free space to the free space manager for this heap */ + if(H5HF_space_add(hdr, dxpl_id, sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add range section to free space manager") + +done: + if(ret_value < 0 && sect) { + /* Check if we should decrement parent ref. count */ + if(iblock_incr) + if(H5HF_iblock_decr(sect->u.range.iblock) < 0) + HDONE_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") + + /* Release the section */ + H5FL_FREE(H5HF_free_section_t, sect); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_sect_range_add() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_sect_range_revive * * Purpose: Update the memory information for a 'range' free section @@ -705,6 +967,104 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_sect_range_reduce + * + * Purpose: Reduce the size of a range section (possibly freeing it) + * and re-add it back to the free space manager for the heap + * (if it hasn't been freed) + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 31 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_range_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_range_reduce) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(sect); + HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_RANGE); + HDassert(sect->sect_info.state == H5FS_SECT_LIVE); + + /* Check for eliminating the section */ + if(sect->u.range.num_entries == 1) { + /* Free range section */ + if(H5HF_sect_range_free((H5FS_section_info_t *)sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free range section node") + } /* end if */ + else { + /* Adjust section information */ + sect->sect_info.addr += hdr->man_dtable.row_block_size[sect->u.range.row]; + + /* Adjust range information */ + sect->u.range.col++; + sect->u.range.num_entries--; + + /* Add section back to free space list */ + if(H5HF_space_add(hdr, dxpl_id, sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't re-add range section to free space manager") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_sect_range_reduce() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_range_from_single + * + * Purpose: Convert a 'single' section into a 'range' section + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 31 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF_sect_range_from_single(H5HF_hdr_t *hdr, H5HF_free_section_t *sect, + H5HF_direct_t *dblock) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_sect_range_from_single) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(sect); + HDassert(dblock); +#ifdef QAK +HDfprintf(stderr, "%s: sect.sect_info = {%a, %Hu, %u, %s}\n", "H5HF_sect_range_from_single", sect->sect_info.addr, sect->sect_info.size, sect->sect_info.type, (sect->sect_info.state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED")); +HDfprintf(stderr, "%s: dblock->parent = %p\n", "H5HF_sect_range_from_single", dblock->parent); +HDfprintf(stderr, "%s: hdr->man_dtable.curr_root_rows = %u\n", "H5HF_sect_range_from_single", hdr->man_dtable.curr_root_rows); +#endif /* QAK */ + + /* Update information for range block */ + sect->sect_info.addr = dblock->block_off; + sect->sect_info.type = H5HF_FSPACE_SECT_RANGE; + sect->u.range.iblock = dblock->parent; + sect->u.range.row = dblock->par_entry / hdr->man_dtable.cparam.width; + sect->u.range.col = dblock->par_entry % hdr->man_dtable.cparam.width; + sect->u.range.num_entries = 1; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HF_sect_range_from_single() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_sect_range_serialize * * Purpose: Serialize a "live" range section into a buffer @@ -756,12 +1116,12 @@ 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 H5FS_section_info_t * +H5HF_sect_range_deserialize(const uint8_t *buf, haddr_t sect_addr, + hsize_t sect_size) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_free_section_t *new_sect; /* New section */ + H5FS_section_info_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_range_deserialize) @@ -769,20 +1129,22 @@ H5HF_sect_range_deserialize(H5FS_section_class_t *sect_cls, HDassert(buf); HDassert(H5F_addr_defined(sect_addr)); HDassert(sect_size); - HDassert(sect); /* Create free list section node */ - if(H5HF_sect_node_alloc(sect_cls, H5FS_SECT_FHEAP_RANGE, sect_addr, sect_size, sect) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "allocation failed for direct block free list section") + if(NULL == (new_sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_RANGE, sect_addr, sect_size, H5FS_SECT_SERIALIZED))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "allocation failed for direct block free list section") /* Range's row */ - UINT16DECODE(buf, ((H5HF_free_section_t *)*sect)->u.range.row); + UINT16DECODE(buf, new_sect->u.range.row); /* Range's column */ - UINT16DECODE(buf, ((H5HF_free_section_t *)*sect)->u.range.col); + UINT16DECODE(buf, new_sect->u.range.col); /* Range's # of entries */ - UINT16DECODE(buf, ((H5HF_free_section_t *)*sect)->u.range.num_entries); + UINT16DECODE(buf, new_sect->u.range.num_entries); + + /* Set return value */ + ret_value = (H5FS_section_info_t *)new_sect; done: FUNC_LEAVE_NOAPI(ret_value) @@ -790,6 +1152,289 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_sect_range_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 + * Monday, June 5, 2006 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF_sect_range_can_merge(H5FS_section_info_t *_sect1, + H5FS_section_info_t *_sect2, void *_udata) +{ + H5HF_free_section_t *sect1 = (H5HF_free_section_t *)_sect1; /* Fractal heap free section */ + H5HF_free_section_t *sect2 = (H5HF_free_section_t *)_sect2; /* Fractal heap free section */ + H5HF_add_ud1_t *udata = (H5HF_add_ud1_t *)_udata; /* User callback data */ + H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */ + hid_t dxpl_id = udata->dxpl_id; /* DXPL ID for operation */ + hsize_t sect2_off; /* Offset of second section in heap */ + size_t dblock_overhead = H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr); /* Direct block's overhead */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_range_can_merge) + + /* Check arguments. */ + HDassert(sect1); + HDassert(sect2); + HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr)); + +#ifdef QAK +HDfprintf(stderr, "%s: sect1->sect_info = {%a, %Hu, %u, %s}\n", FUNC, sect1->sect_info.addr, sect1->sect_info.size, sect1->sect_info.type, (sect1->sect_info.state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED")); +HDfprintf(stderr, "%s: sect2->sect_info = {%a, %Hu, %u, %s}\n", FUNC, sect2->sect_info.addr, sect2->sect_info.size, sect2->sect_info.type, (sect2->sect_info.state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED")); +#endif /* QAK */ + /* Check to see if we should revive either section */ + if(sect1->sect_info.state != H5FS_SECT_LIVE) + if(H5HF_sect_range_revive(hdr, dxpl_id, sect1) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive single free section") + if(sect2->sect_info.state != H5FS_SECT_LIVE) + if(H5HF_sect_revive(hdr, dxpl_id, sect2) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't revive free section") + + /* Check for special case of delayed conversion of 2nd section from + * single -> range section + */ + if(sect2->sect_info.type == H5HF_FSPACE_SECT_SINGLE) { + size_t dblock_size; /* Section's direct block's size */ + + /* Check for section occupying entire direct block */ + dblock_size = sect2->u.single.dblock_size; + if((dblock_size - dblock_overhead) == sect2->sect_info.size) { + H5HF_direct_t *dblock; /* Pointer to direct block for section */ + haddr_t dblock_addr; /* Section's direct block's address */ + + /* Protect the direct block for the section */ + dblock_addr = sect2->u.single.dblock_addr; +#ifdef QAK +HDfprintf(stderr, "%s: dblock_addr = %a\n", FUNC, dblock_addr); +#endif /* QAK */ + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, sect2->u.single.parent, sect2->u.single.par_entry, H5AC_READ))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block") + HDassert(H5F_addr_eq(dblock->block_off + dblock_overhead, sect2->sect_info.addr)); + + /* Convert 'single' section into 'range' section */ + if(H5HF_sect_range_from_single(hdr, sect2, dblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTCONVERT, FAIL, "can't convert single section into range section") + + /* Destroy direct block */ + if(H5HF_man_dblock_destroy(hdr, dxpl_id, dblock, dblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release direct block") + dblock = NULL; +#ifdef QAK +HDfprintf(stderr, "%s: hdr->man_iter_off = %Hu\n", FUNC, hdr->man_iter_off); +#endif /* QAK */ + } /* end if */ + } /* end if */ + +#ifdef QAK +HDfprintf(stderr, "%s: sect1.u.range = {%p, %u, %u, %u}\n", FUNC, sect1->u.range.iblock, sect1->u.range.row, sect1->u.range.col, sect1->u.range.num_entries); +#endif /* QAK */ + + /* Range section can only merge with other range sections */ + if(sect1->sect_info.type != sect2->sect_info.type) + HGOTO_DONE(FALSE) + +#ifdef QAK +HDfprintf(stderr, "%s: sect2.u.range = {%p, %u, %u, %u}\n", FUNC, sect2->u.range.iblock, sect2->u.range.row, sect2->u.range.col, sect2->u.range.num_entries); +HDfprintf(stderr, "%s: sect2.u.range.iblock->nchildren = %u\n", FUNC, sect2->u.range.iblock->nchildren); +#endif /* QAK */ + + /* Check if second section is in indirect block that's being deleted */ + if(sect2->u.range.iblock->nchildren == 0) + HGOTO_DONE(TRUE) + + /* Check if second section is past end of "next block" iterator */ + sect2_off = sect2->u.range.iblock->block_off; + sect2_off += hdr->man_dtable.row_block_off[sect2->u.range.row]; + sect2_off += hdr->man_dtable.row_block_size[sect2->u.range.row] * sect2->u.range.col; +#ifdef QAK +HDfprintf(stderr, "%s: hdr->man_iter_off = %Hu\n", FUNC, hdr->man_iter_off); +HDfprintf(stderr, "%s: sect2.u.range.iblock->block_off = %Hu\n", FUNC, sect2->u.range.iblock->block_off); +HDfprintf(stderr, "%s: hdr->man_dtable.row_block_off[%u] = %Hu\n", FUNC, sect2->u.range.row, hdr->man_dtable.row_block_off[sect2->u.range.row]); +HDfprintf(stderr, "%s: sect2_off = %Hu\n", FUNC, sect2_off); +#endif /* QAK */ + if(sect2_off > hdr->man_iter_off) + HGOTO_DONE(TRUE) + + /* Check if second section adjoins first section & is in the same row */ + if(H5F_addr_eq(sect1->sect_info.addr + (sect1->u.range.num_entries * (sect1->sect_info.size + dblock_overhead)), sect2->sect_info.addr) && + sect1->u.range.row == sect2->u.range.row) + HGOTO_DONE(TRUE) + +done: +#ifdef QAK +HDfprintf(stderr, "%s: ret_value = %t\n", FUNC, ret_value); +#endif /* QAK */ + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_range_can_merge() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_range_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 + * Monday, June 5, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF_sect_range_merge(H5FS_section_info_t *_sect1, H5FS_section_info_t *_sect2, + void *_udata) +{ + H5HF_free_section_t *sect1 = (H5HF_free_section_t *)_sect1; /* Fractal heap free section */ + H5HF_free_section_t *sect2 = (H5HF_free_section_t *)_sect2; /* Fractal heap free section */ + H5HF_add_ud1_t *udata = (H5HF_add_ud1_t *)_udata; /* User callback data */ + H5HF_hdr_t *hdr = udata->hdr; /* Fractal heap header */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_range_merge) + + /* Check arguments. */ + HDassert(sect1); + HDassert(sect1->sect_info.state == H5FS_SECT_LIVE); + HDassert(sect1->sect_info.type == H5HF_FSPACE_SECT_RANGE); + HDassert(sect2); + HDassert(sect2->sect_info.state == H5FS_SECT_LIVE); + HDassert(sect2->sect_info.type == H5HF_FSPACE_SECT_RANGE); + +#ifdef QAK +HDfprintf(stderr, "%s: sect1.sect_info = {%a, %Hu, %u, %s}\n", FUNC, sect1->sect_info.addr, sect1->sect_info.size, sect1->sect_info.type, (sect1->sect_info.state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED")); +HDfprintf(stderr, "%s: sect1.u.range = {%p, %u, %u, %u}\n", FUNC, sect1->u.range.iblock, sect1->u.range.row, sect1->u.range.col, sect1->u.range.num_entries); +HDfprintf(stderr, "%s: sect2.sect_info = {%a, %Hu, %u, %s}\n", FUNC, sect2->sect_info.addr, sect2->sect_info.size, sect2->sect_info.type, (sect2->sect_info.state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED")); +HDfprintf(stderr, "%s: sect2.u.range = {%p, %u, %u, %u}\n", FUNC, sect2->u.range.iblock, sect2->u.range.row, sect2->u.range.col, sect2->u.range.num_entries); +#endif /* QAK */ + + /* Add second section's size to first section, if it's in the same row */ + if(sect1->u.range.row == sect2->u.range.row) + sect1->u.range.num_entries += sect2->u.range.num_entries; + + /* Get rid of second section */ + if(H5HF_sect_range_free((H5FS_section_info_t *)sect2) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node") + + /* Check if 'range' section should be converted into 'indirect' section (?) */ + if(sect1->u.range.num_entries == hdr->man_dtable.cparam.width && + sect1->u.range.row >= hdr->man_dtable.max_direct_rows) { +HDfprintf(stderr, "%s: converting range section to indirect section not supported yet!\n", FUNC); +HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "converting range section to indirect section not supported yet") + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_range_merge() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_range_can_shrink + * + * Purpose: Can this section shrink the container? + * + * Note: This isn't actually shrinking the heap (since that's already + * been done) as much as it's cleaning up _after_ the heap + * shrink. + * + * Return: Success: non-negative (TRUE/FALSE) + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Monday, June 5, 2006 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF_sect_range_can_shrink(H5FS_section_info_t *_sect, void UNUSED *_udata) +{ + const H5HF_free_section_t *sect = (const H5HF_free_section_t *)_sect; /* Fractal heap free section */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_sect_range_can_shrink) + + /* Check arguments. */ + HDassert(sect); + HDassert(sect->sect_info.state == H5FS_SECT_LIVE); + +#ifdef QAK +HDfprintf(stderr, "%s: sect->sect_info = {%a, %Hu, %u, %s}\n", "H5HF_sect_range_can_shrink", sect->sect_info.addr, sect->sect_info.size, sect->sect_info.type, (sect->sect_info.state == H5FS_SECT_LIVE ? "H5FS_SECT_LIVE" : "H5FS_SECT_SERIALIZED")); +HDfprintf(stderr, "%s: sect->u.range = {%p, %u, %u, %u}\n", "H5HF_sect_range_can_shrink", sect->u.range.iblock, sect->u.range.row, sect->u.range.col, sect->u.range.num_entries); +if(sect->u.range.iblock != NULL) + HDfprintf(stderr, "%s: sect->u.range.iblock->nchildren = %u\n", "H5HF_sect_range_can_shrink", sect->u.range.iblock->nchildren); +#endif /* QAK */ + + /* If section has no parent, it should go away */ + if(sect->u.range.iblock == NULL) + HGOTO_DONE(TRUE) + + /* If section is in an indirect block with no children, it should go away */ + if(sect->u.range.iblock->nchildren == 0) + HGOTO_DONE(TRUE) + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_range_can_shrink() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_sect_range_shrink + * + * Purpose: Shrink container with section + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Monday, June 5, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF_sect_range_shrink(H5FS_section_info_t **_sect, void UNUSED *_udata) +{ + H5HF_free_section_t **sect = (H5HF_free_section_t **)_sect; /* Fractal heap free section */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_range_shrink) + + /* Check arguments. */ + HDassert(sect); + HDassert(*sect); + HDassert((*sect)->sect_info.state == H5FS_SECT_LIVE); + +#ifdef QAK +HDfprintf(stderr, "%s: (*sect).sect_info = {%a, %Hu, %u}\n", FUNC, (*sect)->sect_info.addr, (*sect)->sect_info.size, (*sect)->sect_info.type); +HDfprintf(stderr, "%s: (*sect).u.range = {%p, %u, %u, %u}\n", FUNC, (*sect)->u.range.iblock, (*sect)->u.range.row, (*sect)->u.range.col, (*sect)->u.range.num_entries); +#endif /* QAK */ + + /* Get rid of section */ + if(H5HF_sect_range_free((H5FS_section_info_t *)*sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free section node") + + /* Indicate that the section has been released */ + *sect = NULL; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_sect_range_shrink() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_sect_range_free * * Purpose: Free a 'range' section node @@ -803,7 +1448,7 @@ done: * *------------------------------------------------------------------------- */ -herr_t +static 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 */ @@ -904,6 +1549,74 @@ H5HF_sect_indirect_init_cls(H5FS_section_class_t *cls, const void UNUSED *udata) /*------------------------------------------------------------------------- + * Function: H5HF_sect_indirect_add + * + * Purpose: Add a new 'indirect' section to the free space manager for this + * heap + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 30 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_indirect_add(H5HF_hdr_t *hdr, hid_t dxpl_id, + hsize_t sect_off, hsize_t sect_size, H5HF_indirect_t *iblock, + unsigned row, unsigned col, unsigned nentries, + unsigned indir_row, unsigned indir_nrows) +{ + H5HF_free_section_t *sect = NULL; /* 'Indirect' free space section to add */ + hbool_t iblock_incr = FALSE; /* Indicate that parent iblock has been incremented */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_indirect_add) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(iblock); + HDassert(sect_size); + HDassert(nentries); + + /* Create free space section node */ + if(NULL == (sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_INDIRECT, sect_off, sect_size, H5FS_SECT_LIVE))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for indirect section") + + /* Set the 'indirect' specific fields */ + sect->u.indirect.iblock = iblock; + if(H5HF_iblock_incr(sect->u.indirect.iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block") + iblock_incr = TRUE; + sect->u.indirect.row = row; + sect->u.indirect.col = col; + sect->u.indirect.num_entries = nentries; + sect->u.indirect.indir_row = indir_row; + sect->u.indirect.indir_nrows = indir_nrows; + + /* Add new free space to the free space manager for the heap */ + if(H5HF_space_add(hdr, dxpl_id, sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add indirect section to free space") + +done: + if(ret_value < 0 && sect) { + /* Check if we should decrement parent ref. count */ + if(iblock_incr) + if(H5HF_iblock_decr(sect->u.indirect.iblock) < 0) + HDONE_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared indirect block") + + /* Release the section */ + H5FL_FREE(H5HF_free_section_t, sect); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_sect_indirect_add() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_sect_indirect_revive * * Purpose: Update the memory information for a 'indirect' free section @@ -958,6 +1671,61 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_sect_indirect_reduce + * + * Purpose: Reduce the size of a indirect section (possibly freeing it) + * and re-add it back to the free space manager for the heap + * (if it hasn't been freed) + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 31 2006 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_sect_indirect_reduce(H5HF_hdr_t *hdr, hid_t dxpl_id, + H5HF_free_section_t *sect) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_indirect_reduce) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(sect); + HDassert(sect->sect_info.type == H5HF_FSPACE_SECT_INDIRECT); + HDassert(sect->sect_info.state == H5FS_SECT_LIVE); + + /* Check for eliminating the section */ + if(sect->u.indirect.num_entries == 1) { + /* Free indirect section */ + if(H5HF_sect_indirect_free((H5FS_section_info_t *)sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't free indirect section node") + } /* end if */ + else { + /* Adjust section information */ + sect->sect_info.addr += hdr->man_dtable.row_block_size[sect->u.indirect.row]; + + /* Adjust range information */ + sect->u.indirect.col++; + sect->u.indirect.num_entries--; + + /* Add 'indirect' section back to free space list */ + if(H5HF_space_add(hdr, dxpl_id, sect) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't re-add indirect section to free space manager") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_sect_indirect_reduce() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_sect_indirect_serialize * * Purpose: Serialize a "live" indirect section into a buffer @@ -1015,12 +1783,12 @@ 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 H5FS_section_info_t * +H5HF_sect_indirect_deserialize(const uint8_t *buf, haddr_t sect_addr, + hsize_t sect_size) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_free_section_t *new_sect; /* New section */ + H5FS_section_info_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5HF_sect_indirect_deserialize) @@ -1028,26 +1796,28 @@ H5HF_sect_indirect_deserialize(H5FS_section_class_t *sect_cls, HDassert(buf); HDassert(H5F_addr_defined(sect_addr)); HDassert(sect_size); - HDassert(sect); /* Create free list section node */ - if(H5HF_sect_node_alloc(sect_cls, H5FS_SECT_FHEAP_INDIRECT, sect_addr, sect_size, sect) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "allocation failed for direct block free list section") + if(NULL == (new_sect = H5HF_sect_node_new(H5HF_FSPACE_SECT_INDIRECT, sect_addr, sect_size, H5FS_SECT_SERIALIZED))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "allocation failed for direct block free list section") /* Range's row */ - UINT16DECODE(buf, ((H5HF_free_section_t *)*sect)->u.indirect.row); + UINT16DECODE(buf, new_sect->u.indirect.row); /* Range's column */ - UINT16DECODE(buf, ((H5HF_free_section_t *)*sect)->u.indirect.col); + UINT16DECODE(buf, new_sect->u.indirect.col); /* Range's # of entries */ - UINT16DECODE(buf, ((H5HF_free_section_t *)*sect)->u.indirect.num_entries); + UINT16DECODE(buf, new_sect->u.indirect.num_entries); /* Range's indirect row */ - UINT16DECODE(buf, ((H5HF_free_section_t *)*sect)->u.indirect.indir_row); + UINT16DECODE(buf, new_sect->u.indirect.indir_row); /* Range's indirect # of rows */ - UINT16DECODE(buf, ((H5HF_free_section_t *)*sect)->u.indirect.indir_nrows); + UINT16DECODE(buf, new_sect->u.indirect.indir_nrows); + + /* Set return value */ + ret_value = (H5FS_section_info_t *)new_sect; done: FUNC_LEAVE_NOAPI(ret_value) @@ -1068,7 +1838,7 @@ done: * *------------------------------------------------------------------------- */ -herr_t +static 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 */ diff --git a/src/H5HFspace.c b/src/H5HFspace.c index 91cc742..3519e91 100644 --- a/src/H5HFspace.c +++ b/src/H5HFspace.c @@ -96,10 +96,9 @@ herr_t H5HF_space_start(H5HF_hdr_t *hdr, hid_t dxpl_id) { const H5FS_section_class_t *classes[] = { /* Free space section classes implemented for fractal heap */ - H5FS_SECT_CLS_FHEAP_SINGLE, - H5FS_SECT_CLS_FHEAP_RANGE, - H5FS_SECT_CLS_FHEAP_INDIRECT}; - unsigned u; /* Local index variable */ + H5HF_FSPACE_SECT_CLS_SINGLE, + H5HF_FSPACE_SECT_CLS_RANGE, + H5HF_FSPACE_SECT_CLS_INDIRECT}; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5HF_space_start) @@ -109,25 +108,11 @@ H5HF_space_start(H5HF_hdr_t *hdr, hid_t dxpl_id) */ HDassert(hdr); - /* Allocate space for the section classes for the free list management code to use */ - hdr->nsect_classes = NELMTS(classes); - if(NULL == (hdr->sect_cls = H5FL_SEQ_MALLOC(H5FS_section_class_t, hdr->nsect_classes))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for free space section class array ") - - /* Copy the section classes for this heap */ - /* (Initialization calls will be performed by the free list code) */ - for(u = 0; u < hdr->nsect_classes; u++) { - /* Make certain that section class type can be used as an array index into this array */ - HDassert(u == classes[u]->type); - - HDmemcpy(&hdr->sect_cls[u], classes[u], sizeof(H5FS_section_class_t)); - } /* end for */ - /* Check for creating free space info for the heap */ 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, - hdr->nsect_classes, hdr->sect_cls, hdr))) + NELMTS(classes), classes, hdr))) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize free space info") } /* end if */ else { @@ -142,13 +127,10 @@ 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, hdr->nsect_classes, hdr->sect_cls, hdr))) + &fs_create, NELMTS(classes), classes, hdr))) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize free space info") } /* end else */ - /* Free space for heap is now open */ - hdr->fspace_open = TRUE; - done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF_space_start() */ @@ -185,7 +167,7 @@ H5HF_space_find(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t request, H5HF_free_secti HDassert(node); /* Check if the free space for the heap has been initialized */ - if(!hdr->fspace_open) + if(!hdr->fspace) if(H5HF_space_start(hdr, dxpl_id) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space") @@ -228,7 +210,6 @@ H5HF_space_add(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *node) */ HDassert(hdr); HDassert(node); - HDassert(hdr->fspace_open); HDassert(hdr->fspace); /* Add to the free space for the heap */ @@ -270,7 +251,7 @@ H5HF_space_return(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_t *node) HDassert(node); /* Check if the free space for the heap has been initialized */ - if(!hdr->fspace_open) + if(!hdr->fspace) if(H5HF_space_start(hdr, dxpl_id) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't initialize heap free space") @@ -316,20 +297,27 @@ H5HF_space_close(H5HF_hdr_t *hdr, hid_t dxpl_id) HDassert(hdr); /* Check if the free space was ever opened */ - if(hdr->fspace_open) { - /* Sanity check */ - HDassert(hdr->fspace); + if(hdr->fspace) { + hsize_t nsects; /* Number of sections for this heap */ + + /* Retrieve the number of sections for this heap */ + if(H5FS_get_sect_count(hdr->fspace, &nsects) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTCOUNT, FAIL, "can't query free space section count") +#ifdef QAK +HDfprintf(stderr, "%s: nsects = %Hu\n", FUNC, nsects); +#endif /* QAK */ /* Close the free space for the heap */ if(H5FS_close(hdr->f, dxpl_id, hdr->fspace) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info") hdr->fspace = NULL; - /* Release the memory for the free space section classes */ - H5FL_SEQ_FREE(H5FS_section_class_t, hdr->sect_cls); - - /* Free space is now closed */ - hdr->fspace_open = FALSE; + /* Check if we can delete the free space manager for this heap */ + if(!nsects) { + if(H5FS_delete(hdr->f, dxpl_id, hdr->fs_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "can't delete free space info") + hdr->fs_addr = HADDR_UNDEF; + } /* end if */ } /* end if */ done: diff --git a/src/H5HFstat.c b/src/H5HFstat.c index 693a6fa..e0e762f 100644 --- a/src/H5HFstat.c +++ b/src/H5HFstat.c @@ -83,7 +83,7 @@ *------------------------------------------------------------------------- */ herr_t -H5HF_stat_info(H5HF_t *fh, H5HF_stat_t *stats) +H5HF_stat_info(const H5HF_t *fh, H5HF_stat_t *stats) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_stat_info) @@ -94,6 +94,8 @@ H5HF_stat_info(H5HF_t *fh, H5HF_stat_t *stats) /* Report statistics for fractal heap */ stats->total_size = fh->hdr->total_size; stats->man_size = fh->hdr->man_size; + stats->man_alloc_size = fh->hdr->man_alloc_size; + stats->man_iter_off = fh->hdr->man_iter_off; stats->std_size = fh->hdr->std_size; stats->man_free_space = fh->hdr->total_man_free; stats->nobjs = fh->hdr->nobjs; diff --git a/src/H5HFtest.c b/src/H5HFtest.c index a171acd..5e57af3 100644 --- a/src/H5HFtest.c +++ b/src/H5HFtest.c @@ -102,34 +102,133 @@ H5HF_get_cparam_test(const H5HF_t *fh, H5HF_create_t *cparam) /*------------------------------------------------------------------------- - * Function: H5HF_get_dblock_overhead + * Function: H5HF_get_max_root_rows * - * Purpose: Retrieve the size of direct block overhead + * Purpose: Retrieve the max. # of rows in the root indirect block * - * Return: Success: Size of direct block overhead + * Return: Success: Max. # of rows in root indirect block * * Failure: 0 * * Programmer: Quincey Koziol - * Tuesday, May 9, 2006 + * Monday, May 22, 2006 * *------------------------------------------------------------------------- */ -size_t -H5HF_get_dblock_overhead(const H5HF_t *fh) +unsigned +H5HF_get_max_root_rows(const H5HF_t *fh) { - size_t ret_value; /* Return value */ + unsigned ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_get_dblock_overhead) + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_get_max_root_rows) /* Check arguments. */ HDassert(fh); - /* Return direct block overhead */ - ret_value = H5HF_MAN_ABS_DIRECT_OVERHEAD(fh->hdr); + /* Return max. # of rows in root indirect block */ + ret_value = fh->hdr->man_dtable.max_root_rows; FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_get_dblock_overhead() */ +} /* H5HF_get_max_root_rows() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_get_dtable_width_test + * + * Purpose: Retrieve the width of the doubling table for a heap + * + * Return: Success: Width of the doubling table + * + * Failure: 0 + * + * Programmer: Quincey Koziol + * Monday, May 22, 2006 + * + *------------------------------------------------------------------------- + */ +unsigned +H5HF_get_dtable_width_test(const H5HF_t *fh) +{ + unsigned ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_get_dtable_width_test) + + /* Check arguments. */ + HDassert(fh); + + /* Return width of doubling table */ + ret_value = fh->hdr->man_dtable.cparam.width; + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_get_dtable_width_test() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_get_dtable_max_drows_test + * + * Purpose: Retrieve the max. # of direct block rows in any indirect block + * + * Return: Success: Max. # of direct block rows + * + * Failure: 0 + * + * Programmer: Quincey Koziol + * Monday, May 22, 2006 + * + *------------------------------------------------------------------------- + */ +unsigned +H5HF_get_dtable_max_drows_test(const H5HF_t *fh) +{ + unsigned ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_get_dtable_max_drows_test) + + /* Check arguments. */ + HDassert(fh); + + /* Return max. # of direct blocks in any indirect block */ + ret_value = fh->hdr->man_dtable.max_direct_rows; + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_get_dtable_max_drows_test() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF_get_iblock_max_drows_test + * + * Purpose: Retrieve the max. # of direct block rows in an indirect block + * + * Note: POS is indexed from 1 and is only really working for the + * 2nd-level indirect blocks (i.e. indirect blocks with + * only direct block children) + * + * Return: Success: Max. # of direct block rows + * + * Failure: 0 + * + * Programmer: Quincey Koziol + * Monday, May 22, 2006 + * + *------------------------------------------------------------------------- + */ +unsigned +H5HF_get_iblock_max_drows_test(const H5HF_t *fh, unsigned pos) +{ + unsigned ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HF_get_iblock_max_drows_test) + + /* Check arguments. */ + HDassert(fh); + HDassert(pos); + + /* Return max. # of direct blocks in this indirect block row */ + ret_value = pos + (fh->hdr->man_dtable.max_direct_bits - + fh->hdr->man_dtable.first_row_bits) + 1; + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5HF_get_iblock_max_drows_test() */ /*------------------------------------------------------------------------- diff --git a/src/H5err.txt b/src/H5err.txt index ca8f515..51807f8 100644 --- a/src/H5err.txt +++ b/src/H5err.txt @@ -218,6 +218,8 @@ MINOR, MPI, H5E_CANTRECV, Can't receive data 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 +MINOR, HEAP, H5E_CANTATTACH, Can't attach object +MINOR, HEAP, H5E_CANTUPDATE, Can't update object # Free space manager errors MINOR, FSPACE, H5E_CANTMERGE, Can't merge objects |