From 1f9f510ad41b569bfc8f463a2aa7edf50a94b484 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sun, 13 Apr 2003 23:51:53 -0500 Subject: [svn-r6655] Purpose: New feature. Description: Added ability to release space used for storing symbol table entries and nodes when a group is deleted in a file. Platforms tested: FreeBSD 4.8 (sleipnir) w/C++ Linux 2.4 (burrwhite) w/FORTRAN Solaris 2.7 (arabica) w/FORTRAN IRIX64 6.5 (modi4) w/parallel & FORTRAN (h5committest not run due to my ongoing difficulties with C++ on burrwhite). --- src/H5Gnode.c | 286 ++++++++++++++++++++++++++++++++++++------------------- src/H5Gprivate.h | 8 ++ src/H5Gstab.c | 45 +++++++++ 3 files changed, 239 insertions(+), 100 deletions(-) diff --git a/src/H5Gnode.c b/src/H5Gnode.c index 0a42bcb..d141b28 100644 --- a/src/H5Gnode.c +++ b/src/H5Gnode.c @@ -48,19 +48,18 @@ #define PABLO_MASK H5G_node_mask /* PRIVATE PROTOTYPES */ -static herr_t H5G_node_decode_key(H5F_t *f, H5B_t *bt, uint8_t *raw, - void *_key); -static herr_t H5G_node_encode_key(H5F_t *f, H5B_t *bt, uint8_t *raw, - void *_key); -static herr_t H5G_node_debug_key(FILE *stream, H5F_t *f, hid_t dxpl_id, - int indent, int fwidth, const void *key, - const void *udata); static size_t H5G_node_size(H5F_t *f); + +/* Metadata cache callbacks */ static H5G_node_t *H5G_node_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_udata1, void *_udata2); static herr_t H5G_node_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5G_node_t *sym); static herr_t H5G_node_dest(H5F_t *f, H5G_node_t *sym); +static herr_t H5G_node_clear(H5G_node_t *sym); + +/* B-tree callbacks */ +static size_t H5G_node_sizeof_rkey(H5F_t *f, const void *_udata); static herr_t H5G_node_create(H5F_t *f, hid_t dxpl_id, H5B_ins_t op, void *_lt_key, void *_udata, void *_rt_key, haddr_t *addr_p/*out*/); @@ -78,7 +77,13 @@ static H5B_ins_t H5G_node_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_l static H5B_ins_t H5G_node_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *lt_key, hbool_t *lt_key_changed, void *udata, void *rt_key, hbool_t *rt_key_changed); -static size_t H5G_node_sizeof_rkey(H5F_t *f, const void *_udata); +static herr_t H5G_node_decode_key(H5F_t *f, H5B_t *bt, uint8_t *raw, + void *_key); +static herr_t H5G_node_encode_key(H5F_t *f, H5B_t *bt, uint8_t *raw, + void *_key); +static herr_t H5G_node_debug_key(FILE *stream, H5F_t *f, hid_t dxpl_id, + int indent, int fwidth, const void *key, + const void *udata); /* H5G inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_SNODE[1] = {{ @@ -86,6 +91,7 @@ const H5AC_class_t H5AC_SNODE[1] = {{ (H5AC_load_func_t)H5G_node_load, (H5AC_flush_func_t)H5G_node_flush, (H5AC_dest_func_t)H5G_node_dest, + (H5AC_clear_func_t)H5G_node_clear, }}; /* H5G inherits B-tree like properties from H5B */ @@ -515,6 +521,43 @@ H5G_node_dest(H5F_t UNUSED *f, H5G_node_t *sym) /*------------------------------------------------------------------------- + * Function: H5G_node_clear + * + * Purpose: Mark a symbol table node in memory as non-dirty. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Mar 20 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5G_node_clear(H5G_node_t *sym) +{ + int i; /* Local index variable */ + + FUNC_ENTER_NOINIT(H5G_node_clear); + + /* + * Check arguments. + */ + assert(sym); + + + /* Look for dirty entries and reset the dirty flag. */ + for (i=0; insyms; i++) + sym->entry[i].dirty=FALSE; + sym->cache_info.dirty = FALSE; + + FUNC_LEAVE_NOAPI(SUCCEED); +} /* end H5G_node_clear() */ + + +/*------------------------------------------------------------------------- * Function: H5G_node_create * * Purpose: Creates a new empty symbol table node. This function is @@ -788,7 +831,7 @@ H5G_node_found(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED *_lt_key HGOTO_ERROR(H5E_SYM, H5E_UNSUPPORTED, FAIL, "internal erorr (unknown symbol find operation)"); done: - if (sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn) < 0 && ret_value>=0) + if (sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, FALSE) < 0 && ret_value>=0) HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to release symbol table node"); FUNC_LEAVE_NOAPI(ret_value); @@ -960,7 +1003,7 @@ H5G_node_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr, void UNUSED *_lt_key, insert_into->nsyms += 1; done: - if (sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn) < 0 && ret_value!=H5B_INS_ERROR) + if (sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, FALSE) < 0 && ret_value!=H5B_INS_ERROR) HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5B_INS_ERROR, "unable to release symbol table node"); FUNC_LEAVE_NOAPI(ret_value); @@ -976,6 +1019,14 @@ done: * decrements the link count on the object to which the name * points. * + * If the udata->name parameter is set to NULL, then remove + * all entries in this symbol table node. This only occurs + * during the deletion of the entire group, so don't bother + * freeing individual name entries in the local heap, the group's + * symbol table removal code will just free the entire local + * heap eventually. Do reduce the link counts for each object + * however. + * * Return: Success: If all names are removed from the symbol * table node then H5B_INS_REMOVE is returned; * otherwise H5B_INS_NOOP is returned. @@ -992,6 +1043,9 @@ done: * Pedro Vicente, 18 Sep 2002 * Added `id to name' support. * + * Quincey Koziol, 2003-03-22 + * Added support for deleting all the entries at once. + * *------------------------------------------------------------------------- */ static H5B_ins_t @@ -1026,98 +1080,130 @@ H5G_node_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key/*in,out*/, if (NULL == (base = H5HL_peek(f, dxpl_id, bt_udata->heap_addr, 0))) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5B_INS_ERROR, "unable to read symbol name"); - /* Find the name with a binary search */ - rt = sn->nsyms; - while (ltentry[idx].name_off; - cmp = HDstrcmp(bt_udata->name, s); - if (cmp<0) { - rt = idx; - } else { - lt = idx+1; - } - } - if (cmp) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5B_INS_ERROR, "not found"); - - if (H5G_CACHED_SLINK==sn->entry[idx].type) { - /* Remove the symbolic link value */ - if ((s=H5HL_peek(f, dxpl_id, bt_udata->heap_addr, sn->entry[idx].cache.slink.lval_offset))) - H5HL_remove(f, dxpl_id, bt_udata->heap_addr, sn->entry[idx].cache.slink.lval_offset, HDstrlen(s)+1); - H5E_clear(); /*no big deal*/ - } else { - /* Decrement the reference count */ - assert(H5F_addr_defined(sn->entry[idx].header)); - if (H5O_link(sn->entry+idx, -1, dxpl_id)<0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5B_INS_ERROR, "unable to decrement object link count"); - } - - /* Remove the name from the local heap */ - if ((s=H5HL_peek(f, dxpl_id, bt_udata->heap_addr, sn->entry[idx].name_off))) - H5HL_remove(f, dxpl_id, bt_udata->heap_addr, sn->entry[idx].name_off, HDstrlen(s)+1); - H5E_clear(); /*no big deal*/ + /* "Normal" removal of a single entry from the symbol table node */ + if(bt_udata->name!=NULL) { + /* Find the name with a binary search */ + rt = sn->nsyms; + while (ltentry[idx].name_off; + cmp = HDstrcmp(bt_udata->name, s); + if (cmp<0) { + rt = idx; + } else { + lt = idx+1; + } + } + if (cmp) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5B_INS_ERROR, "not found"); + + if (H5G_CACHED_SLINK==sn->entry[idx].type) { + /* Remove the symbolic link value */ + if ((s=H5HL_peek(f, dxpl_id, bt_udata->heap_addr, sn->entry[idx].cache.slink.lval_offset))) + H5HL_remove(f, dxpl_id, bt_udata->heap_addr, sn->entry[idx].cache.slink.lval_offset, HDstrlen(s)+1); + H5E_clear(); /*no big deal*/ + } else { + /* Decrement the reference count */ + assert(H5F_addr_defined(sn->entry[idx].header)); + if (H5O_link(sn->entry+idx, -1, dxpl_id)<0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5B_INS_ERROR, "unable to decrement object link count"); + } + + /* Remove the name from the local heap */ + if ((s=H5HL_peek(f, dxpl_id, bt_udata->heap_addr, sn->entry[idx].name_off))) + H5HL_remove(f, dxpl_id, bt_udata->heap_addr, sn->entry[idx].name_off, HDstrlen(s)+1); + H5E_clear(); /*no big deal*/ + + /* Remove the entry from the symbol table node */ + if (1==sn->nsyms) { + /* + * We are about to remove the only symbol in this node. Copy the left + * key to the right key and mark the right key as dirty. Free this + * node and indicate that the pointer to this node in the B-tree + * should be removed also. + */ + assert(0==idx); + *rt_key = *lt_key; + *rt_key_changed = TRUE; + sn->nsyms = 0; + sn->cache_info.dirty = TRUE; + if (H5MF_xfree(f, H5FD_MEM_BTREE, dxpl_id, addr, (hsize_t)H5G_node_size(f))<0 + || H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, TRUE)<0) { + sn = NULL; + HGOTO_ERROR(H5E_SYM, H5E_PROTECT, H5B_INS_ERROR, "unable to free symbol table node"); + } + sn = NULL; + ret_value = H5B_INS_REMOVE; + + } else if (0==idx) { + /* + * We are about to remove the left-most entry from the symbol table + * node but there are other entries to the right. No key values + * change. + */ + sn->nsyms -= 1; + sn->cache_info.dirty = TRUE; + HDmemmove(sn->entry+idx, sn->entry+idx+1, + (sn->nsyms-idx)*sizeof(H5G_entry_t)); + ret_value = H5B_INS_NOOP; + + } else if (idx+1==sn->nsyms) { + /* + * We are about to remove the right-most entry from the symbol table + * node but there are other entries to the left. The right key + * should be changed to reflect the new right-most entry. + */ + sn->nsyms -= 1; + sn->cache_info.dirty = TRUE; + rt_key->offset = sn->entry[sn->nsyms-1].name_off; + *rt_key_changed = TRUE; + ret_value = H5B_INS_NOOP; + + } else { + /* + * We are about to remove an entry from the middle of a symbol table + * node. + */ + sn->nsyms -= 1; + sn->cache_info.dirty = TRUE; + HDmemmove(sn->entry+idx, sn->entry+idx+1, + (sn->nsyms-idx)*sizeof(H5G_entry_t)); + ret_value = H5B_INS_NOOP; + } + } /* end if */ + /* Remove all entries from node, during B-tree deletion */ + else { + /* Reduce the link count for all entries in this node */ + for(idx=0; idxnsyms; idx++) { + if (H5G_CACHED_SLINK!=sn->entry[idx].type) { + /* Decrement the reference count */ + assert(H5F_addr_defined(sn->entry[idx].header)); + if (H5O_link(sn->entry+idx, -1, dxpl_id)<0) + HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, H5B_INS_ERROR, "unable to decrement object link count"); + } /* end if */ + } /* end for */ - /* Remove the entry from the symbol table node */ - if (1==sn->nsyms) { - /* - * We are about to remove the only symbol in this node. Copy the left - * key to the right key and mark the right key as dirty. Free this - * node and indicate that the pointer to this node in the B-tree - * should be removed also. - */ - assert(0==idx); - *rt_key = *lt_key; - *rt_key_changed = TRUE; - sn->nsyms = 0; - sn->cache_info.dirty = TRUE; - if (H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn)<0 || - H5AC_flush(f, dxpl_id, H5AC_SNODE, addr, H5F_FLUSH_INVALIDATE)<0 || - H5MF_xfree(f, H5FD_MEM_BTREE, dxpl_id, addr, (hsize_t)H5G_node_size(f))<0) { - sn = NULL; - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, H5B_INS_ERROR, "unable to free symbol table node"); - } - sn = NULL; - ret_value = H5B_INS_REMOVE; - - } else if (0==idx) { - /* - * We are about to remove the left-most entry from the symbol table - * node but there are other entries to the right. No key values - * change. - */ - sn->nsyms -= 1; - sn->cache_info.dirty = TRUE; - HDmemmove(sn->entry+idx, sn->entry+idx+1, - (sn->nsyms-idx)*sizeof(H5G_entry_t)); - ret_value = H5B_INS_NOOP; - - } else if (idx+1==sn->nsyms) { - /* - * We are about to remove the right-most entry from the symbol table - * node but there are other entries to the left. The right key - * should be changed to reflect the new right-most entry. - */ - sn->nsyms -= 1; - sn->cache_info.dirty = TRUE; - rt_key->offset = sn->entry[sn->nsyms-1].name_off; - *rt_key_changed = TRUE; - ret_value = H5B_INS_NOOP; - - } else { - /* - * We are about to remove an entry from the middle of a symbol table - * node. - */ - sn->nsyms -= 1; - sn->cache_info.dirty = TRUE; - HDmemmove(sn->entry+idx, sn->entry+idx+1, - (sn->nsyms-idx)*sizeof(H5G_entry_t)); - ret_value = H5B_INS_NOOP; - } + /* + * We are about to remove all the symbols in this node. Copy the left + * key to the right key and mark the right key as dirty. Free this + * node and indicate that the pointer to this node in the B-tree + * should be removed also. + */ + *rt_key = *lt_key; + *rt_key_changed = TRUE; + sn->nsyms = 0; + sn->cache_info.dirty = TRUE; + if (H5MF_xfree(f, H5FD_MEM_BTREE, dxpl_id, addr, (hsize_t)H5G_node_size(f))<0 + || H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, TRUE)<0) { + sn = NULL; + HGOTO_ERROR(H5E_SYM, H5E_PROTECT, H5B_INS_ERROR, "unable to free symbol table node"); + } + sn = NULL; + ret_value = H5B_INS_REMOVE; + } /* end else */ done: - if (sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn)<0 && ret_value!=H5B_INS_ERROR) + if (sn && H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, FALSE)<0 && ret_value!=H5B_INS_ERROR) HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5B_INS_ERROR, "unable to release symbol table node"); FUNC_LEAVE_NOAPI(ret_value); @@ -1433,7 +1519,7 @@ H5G_node_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent, H5G_ent_debug(f, dxpl_id, sn->entry + i, stream, indent, fwidth, heap); } - H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn); + H5AC_unprotect(f, dxpl_id, H5AC_SNODE, addr, sn, FALSE); done: FUNC_LEAVE_NOAPI(ret_value); diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h index 87dfc68..80d8ded 100644 --- a/src/H5Gprivate.h +++ b/src/H5Gprivate.h @@ -141,6 +141,9 @@ typedef enum { H5G_COPY_DEEP /* Deep copy from source to destination, including duplicating name & old name fields */ } H5G_ent_copy_depth_t; +/* Forward declarations for prototype arguments */ +struct H5O_stab_t; + /* * Library prototypes... These are the ones that other packages routinely * call. @@ -170,6 +173,11 @@ H5_DLL herr_t H5G_replace_name(int type, H5G_entry_t *loc, H5_DLL herr_t H5G_free_grp_name(H5G_t *grp); /* + * These functions operate on symbol tables themselves. + */ +H5_DLL herr_t H5G_stab_delete(H5F_t *f, hid_t dxpl_id, haddr_t btree_addr, haddr_t heap_addr); + +/* * These functions operate on symbol table nodes. */ H5_DLL herr_t H5G_node_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, diff --git a/src/H5Gstab.c b/src/H5Gstab.c index ff5e735..b5591b8 100644 --- a/src/H5Gstab.c +++ b/src/H5Gstab.c @@ -408,3 +408,48 @@ done: FUNC_LEAVE_NOAPI(ret_value); } + +/*------------------------------------------------------------------------- + * Function: H5G_stab_delete + * + * Purpose: Delete entire symbol table information from file + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, March 20, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_stab_delete(H5F_t *f, hid_t dxpl_id, haddr_t btree_addr, haddr_t heap_addr) +{ + H5G_bt_ud1_t udata; /*data to pass through B-tree */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5G_stab_delete, FAIL); + + assert(f); + assert(H5F_addr_defined(btree_addr)); + assert(H5F_addr_defined(heap_addr)); + + /* Set up user data for B-tree deletion */ + HDmemset(&udata, 0, sizeof udata); + udata.operation = H5G_OPER_REMOVE; + udata.name = NULL; + udata.heap_addr = heap_addr; + + /* Delete entire B-tree */ + if(H5B_delete(f, dxpl_id, H5B_SNODE, btree_addr, &udata)<0) + HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete symbol table B-tree"); + + /* Delete local heap for names */ + if(H5HL_delete(f, dxpl_id, heap_addr)<0) + HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete symbol table heap"); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5G_stab_delete() */ + -- cgit v0.12