diff options
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | src/H5AC.c | 8 | ||||
-rw-r--r-- | src/H5B.c | 224 | ||||
-rw-r--r-- | src/H5Bprivate.h | 2 | ||||
-rw-r--r-- | src/H5Distore.c | 92 | ||||
-rw-r--r-- | src/H5F.c | 35 | ||||
-rw-r--r-- | src/H5Fistore.c | 92 | ||||
-rw-r--r-- | src/H5Fprivate.h | 2 | ||||
-rw-r--r-- | src/H5G.c | 60 | ||||
-rw-r--r-- | src/H5Gnode.c | 177 | ||||
-rw-r--r-- | src/H5Gprivate.h | 5 | ||||
-rw-r--r-- | src/H5HL.c | 5 | ||||
-rw-r--r-- | src/H5MF.c | 1 | ||||
-rw-r--r-- | src/H5V.c | 2 | ||||
-rw-r--r-- | test/Makefile.in | 9 |
15 files changed, 546 insertions, 169 deletions
@@ -306,6 +306,7 @@ ./test/tohdr.c ./test/tselect.c ./test/tstab.c +./test/unlink.c ./testpar/Makefile.ascired ./testpar/Makefile.ibmsp @@ -396,12 +396,10 @@ H5AC_flush(H5F_t *f, const H5AC_class_t *type, const haddr_t *addr, for (i = 0; i < nslots; i++) { #ifdef H5AC_SORT_BY_ADDR slot = cache->slot + map[i]; - if (NULL == slot->type) - break; /*the rest are empty */ + if (NULL == slot->type) break; /*the rest are empty */ #else slot = cache->slot + i; - if (NULL == slot->type) - continue; + if (NULL == slot->type) continue; #endif if (!type || type == slot->type) { flush = slot->type->flush; @@ -639,7 +637,7 @@ H5AC_rename(H5F_t *f, const H5AC_class_t *type, * *------------------------------------------------------------------------- */ -void * +void * H5AC_protect(H5F_t *f, const H5AC_class_t *type, const haddr_t *addr, const void *udata1, void *udata2) { @@ -426,7 +426,7 @@ H5B_flush(H5F_t *f, hbool_t destroy, const haddr_t *addr, H5B_t *bt) H5F_addr_encode(f, &p, &(bt->right)); /* child keys and pointers */ - for (i = 0; i <= bt->nchildren; i++) { + for (i=0; i<=bt->nchildren; i++) { /* encode the key */ assert(bt->key[i].rkey == p); @@ -456,7 +456,7 @@ H5B_flush(H5F_t *f, hbool_t destroy, const haddr_t *addr, H5B_t *bt) * for the final unchanged children. */ #ifdef HAVE_PARALLEL - H5F_mpio_tas_allsame( f->shared->lf, TRUE ); /* only p0 will write */ + H5F_mpio_tas_allsame(f->shared->lf, TRUE); /* only p0 will write */ #endif /* HAVE_PARALLEL */ if (H5F_block_write(f, addr, (hsize_t)size, H5D_XFER_DFLT, bt->page) < 0) { @@ -475,6 +475,7 @@ H5B_flush(H5F_t *f, hbool_t destroy, const haddr_t *addr, H5B_t *bt) } FUNC_LEAVE(SUCCEED); } + /*------------------------------------------------------------------------- * Function: H5B_find @@ -981,7 +982,7 @@ H5B_insert_child(H5F_t *f, const H5B_class_t *type, H5B_t *bt, bt->native + idx * type->sizeof_nkey, ((bt->nchildren - idx) + 1) * type->sizeof_nkey); - for (i = bt->nchildren; i >= idx; --i) { + for (i=bt->nchildren; i>=idx; --i) { bt->key[i+1].dirty = bt->key[i].dirty; if (bt->key[i].nkey) { bt->key[i+1].nkey = bt->native + (i+1) * type->sizeof_nkey; @@ -1524,13 +1525,14 @@ H5B_iterate (H5F_t *f, const H5B_class_t *type, const haddr_t *addr, */ static H5B_ins_t H5B_remove_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type, - uint8 *lt_key/*out*/, hbool_t *lt_key_changed/*out*/, - uint8 *md_key/*out*/, void *udata, uint8 *rt_key/*out*/, - hbool_t *rt_key_changed/*out*/) + intn level, uint8 *lt_key/*out*/, + hbool_t *lt_key_changed/*out*/, void *udata, + uint8 *rt_key/*out*/, hbool_t *rt_key_changed/*out*/) { - H5B_t *bt = NULL; + H5B_t *bt = NULL, *sibling = NULL; H5B_ins_t ret_value = H5B_INS_ERROR; - intn idx=-1, lt=0, rt, cmp=1; + intn idx=-1, lt=0, rt, cmp=1, i; + size_t sizeof_rkey, sizeof_node, sizeof_rec; FUNC_ENTER(H5B_remove_helper, FAIL); assert(f); @@ -1540,7 +1542,6 @@ H5B_remove_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type, assert(type->cmp3); assert(type->found); assert(lt_key && lt_key_changed); - assert(md_key); assert(udata); assert(rt_key && rt_key_changed); @@ -1576,12 +1577,13 @@ H5B_remove_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type, */ assert(idx>=0 && idx<bt->nchildren); if (bt->level>0) { + /* We're at an internal node -- call recursively */ if ((ret_value=H5B_remove_helper(f, bt->child+idx, type, + level+1, bt->key[idx].nkey/*out*/, lt_key_changed/*out*/, - md_key/*out*/, udata, bt->key[idx+1].nkey/*out*/, rt_key_changed/*out*/))<0) { @@ -1589,17 +1591,30 @@ H5B_remove_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type, "key not found in subtree"); } } else if (type->remove) { + /* + * We're at a leave node but the leave node points to an object that + * has a removal method. Pass the removal request to the pointed-to + * object and let it decide how to progress. + */ if ((ret_value=(type->remove)(f, bt->child+idx, bt->key[idx].nkey, lt_key_changed, - md_key, udata, bt->key[idx+1].nkey, rt_key_changed))<0) { HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "key not found in leaf node"); } + } else { + /* + * We're at a leaf node which points to an object that has no removal + * method. The best we can do is to leave the object alone but + * remove the B-tree reference to the object. + */ + *lt_key_changed = FALSE; + *rt_key_changed = FALSE; + ret_value = H5B_INS_REMOVE; } /* @@ -1621,6 +1636,7 @@ H5B_remove_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type, } if (*rt_key_changed) { bt->dirty = TRUE; + bt->key[idx+1].dirty = TRUE; if (idx+1<bt->nchildren) { *rt_key_changed = FALSE; } else { @@ -1631,42 +1647,135 @@ H5B_remove_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type, /* * If the subtree returned H5B_INS_REMOVE then we should remove the * subtree entry from the current node. There are four cases: - * - * 1: If the subtree is the only child of this node then remove both - * keys and the subtree and return H5B_INS_REMOVE. - * - * 2: If the subtree is the left-most child of this node then we - * discard the left-most key and the left-most child (the child has - * already been freed) and shift everything down by one. We copy - * the new left-most key into lt_key and notify the caller that the - * left key has changed. Return H5B_INS_NOOP. - * - * 3: If the subtree is the right-most child of this node then we - * discard the right-most key and the right-most child (the child - * has already been freed). We copy the new right-most key into - * rt_key and notify the caller that the right key has changed. - * Return H5B_INS_NOOP. - * - * 4: There are subtrees out of this node to both the left and right of - * the subtree being removed. The key to the left of the subtree - * and the subtree are removed from this node and all keys and nodes - * to the right are shifted left by one place. The subtree has - * already been freed). Return H5B_INS_NOOP. */ - if (1==bt->nchildren) { - HGOTO_ERROR(H5E_BTREE, H5E_UNSUPPORTED, FAIL, - "not implemented yet (all node removal)"); - } else if (0==idx) { - HGOTO_ERROR(H5E_BTREE, H5E_UNSUPPORTED, FAIL, - "not implemented yet (first node removal)"); - } else if (idx+1==bt->nchildren) { - HGOTO_ERROR(H5E_BTREE, H5E_UNSUPPORTED, FAIL, - "not implemented yet (last node removal)"); + sizeof_rec = bt->sizeof_rkey + H5F_SIZEOF_ADDR(f); + if (H5B_INS_REMOVE==ret_value && 1==bt->nchildren) { + /* + * The subtree is the only child of this node. Discard both + * keys and the subtree pointer. Free this node (unless it's the + * root node) and return H5B_INS_REMOVE. + */ + bt->dirty = TRUE; + bt->nchildren = 0; + bt->ndirty = 0; + if (level>0) { + if (H5F_addr_defined(&(bt->left))) { + if (NULL==(sibling=H5AC_find(f, H5AC_BT, &(bt->left), type, + udata))) { + HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, + "unable to unlink node from tree"); + } + sibling->right = bt->right; + sibling->dirty = TRUE; + } + if (H5F_addr_defined(&(bt->right))) { + if (NULL==(sibling=H5AC_find(f, H5AC_BT, &(bt->right), type, + udata))) { + HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, + "unable to unlink node from tree"); + } + sibling->left = bt->left; + sibling->dirty = TRUE; + } + H5F_addr_undef(&(bt->left)); + H5F_addr_undef(&(bt->right)); + sizeof_rkey = (type->get_sizeof_rkey)(f, udata); + sizeof_node = H5B_nodesize(f, type, NULL, sizeof_rkey); + if (H5AC_unprotect(f, H5AC_BT, addr, bt)<0 || + H5AC_flush(f, H5AC_BT, addr, TRUE)<0 || + H5MF_xfree(f, addr, sizeof_node)<0) { + bt = NULL; + HGOTO_ERROR(H5E_BTREE, H5E_PROTECT, FAIL, + "unable to free B-tree node"); + } + bt = NULL; + } + + } else if (H5B_INS_REMOVE==ret_value && 0==idx) { + /* + * The subtree is the left-most child of this node. We discard the + * left-most key and the left-most child (the child has already been + * freed) and shift everything down by one. We copy the new left-most + * key into lt_key and notify the caller that the left key has + * changed. Return H5B_INS_NOOP. + */ + bt->dirty = TRUE; + bt->nchildren -= 1; + bt->ndirty = bt->nchildren; + + HDmemmove(bt->page+H5B_SIZEOF_HDR(f), + bt->page+H5B_SIZEOF_HDR(f)+sizeof_rec, + bt->nchildren*sizeof_rec + bt->sizeof_rkey); + HDmemmove(bt->native, + bt->native + type->sizeof_nkey, + (bt->nchildren+1) * type->sizeof_nkey); + HDmemmove(bt->child, + bt->child+1, + bt->nchildren * sizeof(haddr_t)); + for (i=0; i<bt->nchildren; i++) { + bt->key[i].dirty = bt->key[i+1].dirty; + if (bt->key[i+1].nkey) { + bt->key[i].nkey = bt->native + i*type->sizeof_nkey; + } else { + bt->key[i].nkey = NULL; + } + } + assert(bt->key[0].nkey); + HDmemcpy(lt_key, bt->key[0].nkey, type->sizeof_nkey); + *lt_key_changed = TRUE; + ret_value = H5B_INS_NOOP; + + } else if (H5B_INS_REMOVE==ret_value && idx+1==bt->nchildren) { + /* + * The subtree is the right-most child of this node. We discard the + * right-most key and the right-most child (the child has already been + * freed). We copy the new right-most key into rt_key and notify the + * caller that the right key has changed. Return H5B_INS_NOOP. + */ + bt->dirty = TRUE; + bt->nchildren -= 1; + bt->ndirty = MIN(bt->ndirty, bt->nchildren); + assert(bt->key[bt->nchildren].nkey); + HDmemcpy(rt_key, bt->key[bt->nchildren].nkey, type->sizeof_nkey); + *rt_key_changed = TRUE; + ret_value = H5B_INS_NOOP; + + } else if (H5B_INS_REMOVE==ret_value) { + /* + * There are subtrees out of this node to both the left and right of + * the subtree being removed. The key to the left of the subtree and + * the subtree are removed from this node and all keys and nodes to + * the right are shifted left by one place. The subtree has already + * been freed). Return H5B_INS_NOOP. + */ + bt->dirty = TRUE; + bt->nchildren -= 1; + bt->ndirty = bt->nchildren; + + HDmemmove(bt->page+H5B_SIZEOF_HDR(f)+idx*sizeof_rec, + bt->page+H5B_SIZEOF_HDR(f)+(idx+1)*sizeof_rec, + (bt->nchildren-idx)*sizeof_rec + bt->sizeof_rkey); + HDmemmove(bt->native + idx * type->sizeof_nkey, + bt->native + (idx+1) * type->sizeof_nkey, + (bt->nchildren+1-idx) * type->sizeof_nkey); + HDmemmove(bt->child+idx, + bt->child+idx+1, + (bt->nchildren-idx) * sizeof(haddr_t)); + for (i=idx; i<bt->nchildren; i++) { + bt->key[i].dirty = bt->key[i+1].dirty; + if (bt->key[i+1].nkey) { + bt->key[i].nkey = bt->native + i*type->sizeof_nkey; + } else { + bt->key[i].nkey = NULL; + } + } + ret_value = H5B_INS_NOOP; + } else { - HGOTO_ERROR(H5E_BTREE, H5E_UNSUPPORTED, FAIL, - "not implemented yet (middle node removal)"); + ret_value = H5B_INS_NOOP; } + done: if (bt && H5AC_unprotect(f, H5AC_BT, addr, bt)<0) { HRETURN_ERROR(H5E_BTREE, H5E_PROTECT, FAIL, @@ -1701,25 +1810,46 @@ H5B_remove(H5F_t *f, const H5B_class_t *type, const haddr_t *addr, void *udata) { /* These are defined this way to satisfy alignment constraints */ - uint64 _lt_key[128], _md_key[128], _rt_key[128]; + uint64 _lt_key[128], _rt_key[128]; uint8 *lt_key = (uint8*)_lt_key; /*left key*/ - uint8 *md_key = (uint8*)_md_key; /*middle key*/ uint8 *rt_key = (uint8*)_rt_key; /*right key*/ hbool_t lt_key_changed = FALSE; /*left key changed?*/ hbool_t rt_key_changed = FALSE; /*right key changed?*/ + H5B_t *bt = NULL; /*btree node */ + FUNC_ENTER(H5B_remove, FAIL); + + /* Check args */ assert(f); assert(type); assert(type->sizeof_nkey <= sizeof _lt_key); assert(addr && H5F_addr_defined(addr)); - if (H5B_remove_helper(f, addr, type, lt_key, <_key_changed, md_key, + /* The actual removal */ + if (H5B_remove_helper(f, addr, type, 0, lt_key, <_key_changed, udata, rt_key, &rt_key_changed)<0) { HRETURN_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to remove entry from B-tree"); } + /* + * If the B-tree is now empty then make sure we mark the root node as + * being at level zero + */ + if (NULL==(bt=H5AC_find(f, H5AC_BT, addr, type, udata))) { + HRETURN_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, + "unable to load B-tree root node"); + } + if (0==bt->nchildren && 0!=bt->level) { + bt->level = 0; + bt->dirty = TRUE; + } + + +#ifdef H5B_DEBUG + H5B_assert(f, addr, type, udata); +#endif FUNC_LEAVE(SUCCEED); } @@ -1749,7 +1879,7 @@ H5B_remove(H5F_t *f, const H5B_class_t *type, const haddr_t *addr, */ static size_t H5B_nodesize(H5F_t *f, const H5B_class_t *type, - size_t *total_nkey_size, size_t sizeof_rkey) + size_t *total_nkey_size/*out*/, size_t sizeof_rkey) { size_t size; diff --git a/src/H5Bprivate.h b/src/H5Bprivate.h index 33a9d99..c20135e 100644 --- a/src/H5Bprivate.h +++ b/src/H5Bprivate.h @@ -86,7 +86,7 @@ typedef struct H5B_class_t { /* remove existing data */ H5B_ins_t (*remove)(H5F_t*, const haddr_t*, void*, hbool_t*, - void*, void*, void*, hbool_t*); + void*, void*, hbool_t*); herr_t (*list)(H5F_t*, const haddr_t*, void*); /*walk leaf nodes*/ herr_t (*decode)(H5F_t*, struct H5B_t*, uint8*, void*); diff --git a/src/H5Distore.c b/src/H5Distore.c index 278bca9..31f1ec8 100644 --- a/src/H5Distore.c +++ b/src/H5Distore.c @@ -188,7 +188,7 @@ H5F_istore_sizeof_rkey(H5F_t __unused__ *f, const void *_udata) nbytes = 4 + /*storage size */ 4 + /*filter mask */ - udata->mesg.ndims * 4; /*dimension indices */ + udata->mesg.ndims*8; /*dimension indices */ return nbytes; } @@ -230,7 +230,7 @@ H5F_istore_decode_key(H5F_t __unused__ *f, H5B_t *bt, uint8 *raw, void *_key) UINT32DECODE(raw, key->nbytes); UINT32DECODE(raw, key->filter_mask); for (i = 0; i < ndims; i++) { - UINT32DECODE(raw, key->offset[i]); + UINT64DECODE(raw, key->offset[i]); } FUNC_LEAVE(SUCCEED); @@ -273,7 +273,7 @@ H5F_istore_encode_key(H5F_t __unused__ *f, H5B_t *bt, uint8 *raw, void *_key) UINT32ENCODE(raw, key->nbytes); UINT32ENCODE(raw, key->filter_mask); for (i = 0; i < ndims; i++) { - UINT32ENCODE(raw, key->offset[i]); + UINT64ENCODE(raw, key->offset[i]); } FUNC_LEAVE(SUCCEED); @@ -870,45 +870,6 @@ H5F_istore_flush_entry (H5F_t *f, H5F_rdcc_ent_t *ent, hbool_t reset) FUNC_LEAVE (ret_value); } - -/*------------------------------------------------------------------------- - * Function: H5F_istore_flush - * - * Purpose: Writes all dirty chunks to disk but does not remove them from - * the cache. - * - * Return: Success: SUCCEED - * - * Failure: FAIL - * - * Programmer: Robb Matzke - * Thursday, May 21, 1998 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5F_istore_flush (H5F_t *f) -{ - H5F_rdcc_t *rdcc = &(f->shared->rdcc); - intn nerrors=0; - H5F_rdcc_ent_t *ent=NULL; - - FUNC_ENTER (H5F_istore_flush, FAIL); - - for (ent=rdcc->head; ent; ent=ent->next) { - if (H5F_istore_flush_entry(f, ent, FALSE)<0) { - nerrors++; - } - } - if (nerrors) { - HRETURN_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL, - "unable to flush one or more raw data chunks"); - } - FUNC_LEAVE (SUCCEED); -} - /*------------------------------------------------------------------------- * Function: H5F_istore_preempt * @@ -968,6 +929,53 @@ H5F_istore_preempt (H5F_t *f, H5F_rdcc_ent_t *ent) /*------------------------------------------------------------------------- + * Function: H5F_istore_flush + * + * Purpose: Writes all dirty chunks to disk and optionally preempts them + * from the cache. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Thursday, May 21, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_istore_flush (H5F_t *f, hbool_t preempt) +{ + H5F_rdcc_t *rdcc = &(f->shared->rdcc); + intn nerrors=0; + H5F_rdcc_ent_t *ent=NULL, *next=NULL; + + FUNC_ENTER (H5F_istore_flush, FAIL); + + for (ent=rdcc->head; ent; ent=next) { + next = ent->next; + if (preempt) { + if (H5F_istore_preempt(f, ent)<0) { + nerrors++; + } + } else { + if (H5F_istore_flush_entry(f, ent, FALSE)<0) { + nerrors++; + } + } + } + + if (nerrors) { + HRETURN_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL, + "unable to flush one or more raw data chunks"); + } + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- * Function: H5F_istore_dest * * Purpose: Destroy the entire chunk cache by flushing dirty entries, @@ -1449,7 +1449,7 @@ H5F_flush(H5F_t *f, hbool_t invalidate) } /* flush the entire raw data cache */ - if (H5F_istore_flush (f)<0) { + if (H5F_istore_flush (f, invalidate)<0) { HRETURN_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush raw data cache"); } @@ -1493,7 +1493,7 @@ H5F_flush(H5F_t *f, hbool_t invalidate) /* write the boot block to disk */ #ifdef HAVE_PARALLEL - H5F_mpio_tas_allsame( f->shared->lf, TRUE ); /* only p0 will write */ + H5F_mpio_tas_allsame(f->shared->lf, TRUE); /* only p0 will write */ #endif if (H5F_low_write(f->shared->lf, f->shared->access_parms, H5D_XFER_DFLT, @@ -1507,6 +1507,7 @@ H5F_flush(H5F_t *f, hbool_t invalidate) } FUNC_LEAVE(SUCCEED); } + /*------------------------------------------------------------------------- * Function: H5F_close @@ -1532,18 +1533,17 @@ H5F_close(H5F_t *f) /* Close all current working groups */ while (H5G_pop(f)>=0) /*void*/; - /* Flush the boot block and caches */ - if (H5F_flush(f, FALSE) < 0) { - HRETURN_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, - "unable to flush cache"); - } - /* * If object headers are still open then delay deletion of resources until - * they have all been closed. The file is in a consistent state now, so - * forgetting to close everything is not a major problem. + * they have all been closed. Flush all caches and update the object + * header anyway so that failing to close all objects isn't a major + * problem. */ if (f->nopen>0) { + if (H5F_flush(f, FALSE)<0) { + HRETURN_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, + "unable to flush cache"); + } #ifdef H5F_DEBUG if (H5DEBUG(F)) { fprintf(H5DEBUG(F), "H5F: H5F_close(%s): %u object header%s still " @@ -1559,7 +1559,7 @@ H5F_close(H5F_t *f) } else if (f->close_pending) { #ifdef H5F_DEBUG if (H5DEBUG(F)) { - fprintf(H5DEBUG(F), "H5F: H5F_close: operation completed\n"); + fprintf(H5DEBUG(F), "H5F: H5F_close: operation completing\n"); } #endif } @@ -1569,7 +1569,7 @@ H5F_close(H5F_t *f) * close it also. */ if (1==f->shared->nrefs) { - /* Flush again just to be safe, but this time clean up the cache */ + /* Flush and destroy all caches */ if (H5F_flush (f, TRUE)<0) { HRETURN_ERROR (H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache"); @@ -1581,7 +1581,18 @@ H5F_close(H5F_t *f) /* Close files and release resources */ H5F_low_close(f->shared->lf, f->shared->access_parms); + } else { + /* + * Flush all caches but do not destroy. As long as all handles for + * this file are closed the flush isn't really necessary, but lets + * just be safe. + */ + if (H5F_flush(f, TRUE)<0) { + HRETURN_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, + "unable to flush cache"); + } } + if (H5F_dest(f)<0) { HRETURN_ERROR (H5E_FILE, H5E_CANTINIT, FAIL, "problems closing file"); diff --git a/src/H5Fistore.c b/src/H5Fistore.c index 278bca9..31f1ec8 100644 --- a/src/H5Fistore.c +++ b/src/H5Fistore.c @@ -188,7 +188,7 @@ H5F_istore_sizeof_rkey(H5F_t __unused__ *f, const void *_udata) nbytes = 4 + /*storage size */ 4 + /*filter mask */ - udata->mesg.ndims * 4; /*dimension indices */ + udata->mesg.ndims*8; /*dimension indices */ return nbytes; } @@ -230,7 +230,7 @@ H5F_istore_decode_key(H5F_t __unused__ *f, H5B_t *bt, uint8 *raw, void *_key) UINT32DECODE(raw, key->nbytes); UINT32DECODE(raw, key->filter_mask); for (i = 0; i < ndims; i++) { - UINT32DECODE(raw, key->offset[i]); + UINT64DECODE(raw, key->offset[i]); } FUNC_LEAVE(SUCCEED); @@ -273,7 +273,7 @@ H5F_istore_encode_key(H5F_t __unused__ *f, H5B_t *bt, uint8 *raw, void *_key) UINT32ENCODE(raw, key->nbytes); UINT32ENCODE(raw, key->filter_mask); for (i = 0; i < ndims; i++) { - UINT32ENCODE(raw, key->offset[i]); + UINT64ENCODE(raw, key->offset[i]); } FUNC_LEAVE(SUCCEED); @@ -870,45 +870,6 @@ H5F_istore_flush_entry (H5F_t *f, H5F_rdcc_ent_t *ent, hbool_t reset) FUNC_LEAVE (ret_value); } - -/*------------------------------------------------------------------------- - * Function: H5F_istore_flush - * - * Purpose: Writes all dirty chunks to disk but does not remove them from - * the cache. - * - * Return: Success: SUCCEED - * - * Failure: FAIL - * - * Programmer: Robb Matzke - * Thursday, May 21, 1998 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5F_istore_flush (H5F_t *f) -{ - H5F_rdcc_t *rdcc = &(f->shared->rdcc); - intn nerrors=0; - H5F_rdcc_ent_t *ent=NULL; - - FUNC_ENTER (H5F_istore_flush, FAIL); - - for (ent=rdcc->head; ent; ent=ent->next) { - if (H5F_istore_flush_entry(f, ent, FALSE)<0) { - nerrors++; - } - } - if (nerrors) { - HRETURN_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL, - "unable to flush one or more raw data chunks"); - } - FUNC_LEAVE (SUCCEED); -} - /*------------------------------------------------------------------------- * Function: H5F_istore_preempt * @@ -968,6 +929,53 @@ H5F_istore_preempt (H5F_t *f, H5F_rdcc_ent_t *ent) /*------------------------------------------------------------------------- + * Function: H5F_istore_flush + * + * Purpose: Writes all dirty chunks to disk and optionally preempts them + * from the cache. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Thursday, May 21, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_istore_flush (H5F_t *f, hbool_t preempt) +{ + H5F_rdcc_t *rdcc = &(f->shared->rdcc); + intn nerrors=0; + H5F_rdcc_ent_t *ent=NULL, *next=NULL; + + FUNC_ENTER (H5F_istore_flush, FAIL); + + for (ent=rdcc->head; ent; ent=next) { + next = ent->next; + if (preempt) { + if (H5F_istore_preempt(f, ent)<0) { + nerrors++; + } + } else { + if (H5F_istore_flush_entry(f, ent, FALSE)<0) { + nerrors++; + } + } + } + + if (nerrors) { + HRETURN_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL, + "unable to flush one or more raw data chunks"); + } + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- * Function: H5F_istore_dest * * Purpose: Destroy the entire chunk cache by flushing dirty entries, diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index 6e80fa0..a4e47fd 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -544,7 +544,7 @@ herr_t H5F_arr_write (H5F_t *f, const struct H5O_layout_t *layout, /* Functions that operate on indexed storage */ herr_t H5F_istore_init (H5F_t *f); -herr_t H5F_istore_flush (H5F_t *f); +herr_t H5F_istore_flush (H5F_t *f, hbool_t preempt); herr_t H5F_istore_dest (H5F_t *f); herr_t H5F_istore_stats (H5F_t *f, hbool_t headers); herr_t H5F_istore_create(H5F_t *f, struct H5O_layout_t *layout /*in,out*/); @@ -523,14 +523,29 @@ H5Giterate(hid_t loc_id, const char *name, int *idx, *------------------------------------------------------------------------- */ herr_t -H5Gmove(hid_t __unused__ loc_id, const char __unused__ *src, - const char __unused__ *dst) +H5Gmove(hid_t loc_id, const char *src, const char *dst) { + H5G_entry_t *loc=NULL; + FUNC_ENTER (H5Gmove, FAIL); H5TRACE3("e","iss",loc_id,src,dst); - HRETURN_ERROR (H5E_SYM, H5E_UNSUPPORTED, FAIL, - "unable to rename object (not implemented yet)"); + if (NULL==(loc=H5G_loc(loc_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location"); + } + if (!src || !*src) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "no current name specified"); + } + if (!dst || !*dst) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "no new name specified"); + } + + if (H5G_move(loc, src, dst)<0) { + HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, + "unable to change object name"); + } FUNC_LEAVE (SUCCEED); } @@ -2383,3 +2398,40 @@ H5G_unlink(H5G_entry_t *loc, const char *name) FUNC_LEAVE(SUCCEED); } + + +/*------------------------------------------------------------------------- + * Function: H5G_move + * + * Purpose: Atomically rename an object. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, September 25, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_move(H5G_entry_t *loc, const char *src_name, const char *dst_name) +{ + FUNC_ENTER(H5G_move, FAIL); + assert(loc); + assert(src_name && *src_name); + assert(dst_name && *dst_name); + + if (H5G_link(loc, H5G_LINK_HARD, src_name, dst_name)<0) { + HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, + "unable to register new name for object"); + } + if (H5G_unlink(loc, src_name)<0) { + HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, + "unable to deregister old object name"); + } + + FUNC_LEAVE(SUCCEED); +} diff --git a/src/H5Gnode.c b/src/H5Gnode.c index ac7e991..9002c65 100644 --- a/src/H5Gnode.c +++ b/src/H5Gnode.c @@ -58,6 +58,9 @@ static H5B_ins_t H5G_node_insert(H5F_t *f, const haddr_t *addr, void *_md_key, void *_udata, void *_rt_key, hbool_t *rt_key_changed, haddr_t *new_node/*out*/); +static H5B_ins_t H5G_node_remove(H5F_t *f, const haddr_t *addr, void *lt_key, + hbool_t *lt_key_changed, void *udata, + void *rt_key, hbool_t *rt_key_changed); static herr_t H5G_node_iterate(H5F_t *f, const haddr_t *addr, void *_udata); static size_t H5G_node_sizeof_rkey(H5F_t *f, const void *_udata); @@ -80,7 +83,7 @@ H5B_class_t H5B_SNODE[1] = {{ H5G_node_insert, /*insert */ TRUE, /*follow min branch? */ TRUE, /*follow max branch? */ - NULL, /*remove */ + H5G_node_remove, /*remove */ H5G_node_iterate, /*list */ H5G_node_decode_key, /*decode */ H5G_node_encode_key, /*encode */ @@ -355,14 +358,13 @@ H5G_node_flush(H5F_t *f, hbool_t destroy, const haddr_t *addr, HDmemset(p, 0, size - (p - buf)); #ifdef HAVE_PARALLEL - H5F_mpio_tas_allsame( f->shared->lf, TRUE ); /* only p0 will write */ + H5F_mpio_tas_allsame(f->shared->lf, TRUE); /* only p0 will write */ #endif /* HAVE_PARALLEL */ status = H5F_block_write(f, addr, (hsize_t)size, H5D_XFER_DFLT, buf); buf = H5MM_xfree(buf); if (status < 0) HRETURN_ERROR(H5E_SYM, H5E_WRITEERROR, FAIL, - "unable to write symbol table node to " - "the file"); + "unable to write symbol table node to the file"); } /* * Destroy the symbol node? This might happen if the node is being @@ -652,8 +654,7 @@ H5G_node_found(H5F_t *f, const haddr_t *addr, const void __unused__ *_lt_key, lt = idx + 1; } } - if (cmp) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "not found"); + if (cmp) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "not found"); switch (bt_udata->operation) { case H5G_OPER_FIND: @@ -797,7 +798,7 @@ H5G_node_insert(H5F_t *f, const haddr_t *addr, void __unused__ *_lt_key, /* The right node */ if (H5G_node_create(f, H5B_INS_FIRST, NULL, NULL, NULL, - new_node /*out */ ) < 0) { + new_node/*out*/)<0) { HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5B_INS_ERROR, "unable to split symbol table node"); } @@ -862,6 +863,168 @@ H5G_node_insert(H5F_t *f, const haddr_t *addr, void __unused__ *_lt_key, /*------------------------------------------------------------------------- + * Function: H5G_node_remove + * + * Purpose: The B-tree removal engine has found the symbol table node + * which should contain the name which is being removed. This + * function removes the name from the symbol table and + * decrements the link count on the object to which the name + * points. + * + * Return: Success: If all names are removed from the symbol + * table node then H5B_INS_REMOVE is returned; + * otherwise H5B_INS_NOOP is returned. + * + * Failure: H5B_INS_ERROR + * + * Programmer: Robb Matzke + * Thursday, September 24, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static H5B_ins_t +H5G_node_remove(H5F_t *f, const haddr_t *addr, void *_lt_key/*in,out*/, + hbool_t __unused__ *lt_key_changed/*out*/, + void *_udata/*in,out*/, void *_rt_key/*in,out*/, + hbool_t *rt_key_changed/*out*/) +{ + H5G_node_key_t *lt_key = (H5G_node_key_t*)_lt_key; + H5G_node_key_t *rt_key = (H5G_node_key_t*)_rt_key; + H5G_bt_ud1_t *bt_udata = (H5G_bt_ud1_t*)_udata; + H5G_node_t *sn = NULL; + H5B_ins_t ret_value = H5B_INS_ERROR; + intn lt=0, rt, idx=0, cmp=1; + const char *s = NULL; + + FUNC_ENTER(H5G_node_remove, H5B_INS_ERROR); + + /* Check arguments */ + assert(f); + assert(addr && H5F_addr_defined(addr)); + assert(lt_key); + assert(rt_key); + assert(bt_udata); + + /* Load the symbol table */ + if (NULL==(sn=H5AC_protect(f, H5AC_SNODE, addr, NULL, NULL))) { + HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5B_INS_ERROR, + "unable to protect symbol table node"); + } + + /* Find the name with a binary search */ + rt = sn->nsyms; + while (lt<rt && cmp) { + idx = (lt+rt)/2; + if (NULL==(s=H5HL_peek(f, &(bt_udata->heap_addr), + sn->entry[idx].name_off))) { + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, + "unable to read symbol name"); + } + cmp = HDstrcmp(bt_udata->name, s); + if (cmp<0) { + rt = idx; + } else { + lt = idx+1; + } + } + if (cmp) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "not found"); + + if (H5G_CACHED_SLINK==sn->entry[idx].type) { + /* Remove the symbolic link value */ + if ((s=H5HL_peek(f, &(bt_udata->heap_addr), + sn->entry[idx].cache.slink.lval_offset))) { + H5HL_remove(f, &(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)<0) { + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, + "unable to decrement object link count"); + } + } + + /* Remove the name from the local heap */ + if ((s=H5HL_peek(f, &(bt_udata->heap_addr), sn->entry[idx].name_off))) { + H5HL_remove(f, &(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->dirty = TRUE; + if (H5AC_unprotect(f, H5AC_SNODE, addr, sn)<0 || + H5AC_flush(f, H5AC_SNODE, addr, TRUE)<0 || + H5MF_xfree(f, addr, 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->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->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->dirty = TRUE; + HDmemmove(sn->entry+idx, sn->entry+idx+1, + (sn->nsyms-idx)*sizeof(H5G_entry_t)); + ret_value = H5B_INS_NOOP; + } + + done: + if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn)<0) { + HRETURN_ERROR(H5E_SYM, H5E_PROTECT, H5B_INS_ERROR, + "unable to release symbol table node"); + } + FUNC_LEAVE(ret_value); +} + + +/*------------------------------------------------------------------------- * Function: H5G_node_iterate * * Purpose: This function gets called during a group iterate operation. diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h index 943dfaa..8c5f991 100644 --- a/src/H5Gprivate.h +++ b/src/H5Gprivate.h @@ -113,14 +113,15 @@ herr_t H5G_pop (H5F_t *f); H5G_t *H5G_getcwg(H5F_t *f); herr_t H5G_link (H5G_entry_t *loc, H5G_link_t type, const char *cur_name, const char *new_name); -herr_t H5G_get_objinfo (H5G_entry_t *loc, const char *name, hbool_t follow_link, - H5G_stat_t *statbuf/*out*/); +herr_t H5G_get_objinfo (H5G_entry_t *loc, const char *name, + hbool_t follow_link, H5G_stat_t *statbuf/*out*/); herr_t H5G_linkval (H5G_entry_t *loc, const char *name, size_t size, char *buf/*out*/); herr_t H5G_set_comment(H5G_entry_t *loc, const char *name, const char *buf); intn H5G_get_comment(H5G_entry_t *loc, const char *name, size_t bufsize, char *buf); herr_t H5G_insert (H5G_entry_t *loc, const char *name, H5G_entry_t *ent); +herr_t H5G_move(H5G_entry_t *loc, const char *src_name, const char *dst_name); herr_t H5G_unlink(H5G_entry_t *loc, const char *name); herr_t H5G_find (H5G_entry_t *loc, const char *name, H5G_entry_t *grp_ent/*out*/, H5G_entry_t *ent/*out*/); @@ -802,7 +802,7 @@ herr_t H5HL_remove(H5F_t *f, const haddr_t *addr, size_t offset, size_t size) { H5HL_t *heap = NULL; - H5HL_free_t *fl = heap->freelist, *fl2 = NULL; + H5HL_free_t *fl = NULL, *fl2 = NULL; FUNC_ENTER(H5HL_remove, FAIL); @@ -823,6 +823,7 @@ H5HL_remove(H5F_t *f, const haddr_t *addr, size_t offset, size_t size) } assert(offset < heap->mem_alloc); assert(offset + size <= heap->mem_alloc); + fl = heap->freelist; heap->dirty += 1; @@ -847,6 +848,7 @@ H5HL_remove(H5F_t *f, const haddr_t *addr, size_t offset, size_t size) fl2 = H5HL_remove_free(heap, fl2); HRETURN(SUCCEED); } + fl2 = fl2->next; } HRETURN(SUCCEED); @@ -861,6 +863,7 @@ H5HL_remove(H5F_t *f, const haddr_t *addr, size_t offset, size_t size) fl2 = H5HL_remove_free(heap, fl2); HRETURN(SUCCEED); } + fl2 = fl2->next; } HRETURN(SUCCEED); } @@ -237,7 +237,6 @@ H5MF_xfree(H5F_t *f, const haddr_t *addr, hsize_t size) f->shared->fl_free[i].addr = *addr; f->shared->fl_free[i].size = size; } - FUNC_LEAVE(SUCCEED); } @@ -423,7 +423,7 @@ H5V_hyper_copy(intn n, const hsize_t *_size, { hsize_t dst_acc; /*accumulator */ hsize_t src_acc; /*accumulator */ - int i; /*counter */ + int i; /*counter */ /* init */ dst_stride[n-1] = 1; diff --git a/test/Makefile.in b/test/Makefile.in index 068dce9..1fe8030 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -12,7 +12,7 @@ CPPFLAGS=-I. -I../src @CPPFLAGS@ # These are our main targets. They should be listed in the order to be # executed, generally most specific tests to least specific tests. TESTS=testhdf5 gheap hyperslab istore bittests dtypes dsets cmpd_dset extend \ - external shtype links big mtime + external shtype links unlink big mtime TIMINGS=iopipe chunk ragged # Temporary files @@ -24,7 +24,7 @@ MOSTLYCLEAN=cmpd_dset.h5 dataset.h5 extend.h5 istore.h5 tfile1.h5 tfile2.h5 \ gheap1.h5 gheap2.h5 gheap3.h5 gheap4.h5 shtype0.h5 shtype1.h5 \ shtype2a.h5 shtype2b.h5 shtype3.h5 links.h5 chunk.h5 big.data \ big[0-9][0-9][0-9][0-9][0-9].h5 dtypes1.h5 dtypes2.h5 tattr.h5 \ - tselect.h5 mtime.h5 ragged.h5 grptime.h5 + tselect.h5 mtime.h5 ragged.h5 grptime.h5 unlink.h5 CLEAN=$(TIMINGS) # Source and object files for programs... The TEST_SRC list contains all the @@ -34,7 +34,7 @@ CLEAN=$(TIMINGS) TEST_SRC=testhdf5.c tattr.c tfile.c theap.c tmeta.c tohdr.c tselect.c tstab.c \ th5s.c dtypes.c hyperslab.c istore.c dsets.c cmpd_dset.c extend.c \ external.c iopipe.c gheap.c shtype.c big.c links.c chunk.c bittests.c \ - mtime.c ragged.c + mtime.c ragged.c unlink.c TEST_OBJ=$(TEST_SRC:.c=.o) # Private header files (not to be installed)... @@ -106,4 +106,7 @@ mtime: mtime.o ../src/libhdf5.a ragged: ragged.o ../src/libhdf5.a $(CC) $(CFLAGS) -o $@ ragged.o ../src/libhdf5.a $(LIBS) +unlink: unlink.o ../src/libhdf5.a + $(CC) $(CFLAGS) -o $@ unlink.o ../src/libhdf5.a $(LIBS) + @CONCLUDE@ |