summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST1
-rw-r--r--src/H5AC.c8
-rw-r--r--src/H5B.c224
-rw-r--r--src/H5Bprivate.h2
-rw-r--r--src/H5Distore.c92
-rw-r--r--src/H5F.c35
-rw-r--r--src/H5Fistore.c92
-rw-r--r--src/H5Fprivate.h2
-rw-r--r--src/H5G.c60
-rw-r--r--src/H5Gnode.c177
-rw-r--r--src/H5Gprivate.h5
-rw-r--r--src/H5HL.c5
-rw-r--r--src/H5MF.c1
-rw-r--r--src/H5V.c2
-rw-r--r--test/Makefile.in9
15 files changed, 546 insertions, 169 deletions
diff --git a/MANIFEST b/MANIFEST
index 54c260b..fe4cbeb 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -306,6 +306,7 @@
./test/tohdr.c
./test/tselect.c
./test/tstab.c
+./test/unlink.c
./testpar/Makefile.ascired
./testpar/Makefile.ibmsp
diff --git a/src/H5AC.c b/src/H5AC.c
index cb7c7cd..ac6e140 100644
--- a/src/H5AC.c
+++ b/src/H5AC.c
@@ -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)
{
diff --git a/src/H5B.c b/src/H5B.c
index 49b1f17..5546140 100644
--- a/src/H5B.c
+++ b/src/H5B.c
@@ -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, &lt_key_changed, md_key,
+ /* The actual removal */
+ if (H5B_remove_helper(f, addr, type, 0, lt_key, &lt_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,
diff --git a/src/H5F.c b/src/H5F.c
index 25c328c..ea7f693 100644
--- a/src/H5F.c
+++ b/src/H5F.c
@@ -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*/);
diff --git a/src/H5G.c b/src/H5G.c
index a8fa956..6f37549 100644
--- a/src/H5G.c
+++ b/src/H5G.c
@@ -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*/);
diff --git a/src/H5HL.c b/src/H5HL.c
index 05f71ef..44cbab6 100644
--- a/src/H5HL.c
+++ b/src/H5HL.c
@@ -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);
}
diff --git a/src/H5MF.c b/src/H5MF.c
index 0176929..0896c2c 100644
--- a/src/H5MF.c
+++ b/src/H5MF.c
@@ -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);
}
diff --git a/src/H5V.c b/src/H5V.c
index 7708794..c4ad0bb 100644
--- a/src/H5V.c
+++ b/src/H5V.c
@@ -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@