summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobb Matzke <matzke@llnl.gov>1998-09-22 15:27:26 (GMT)
committerRobb Matzke <matzke@llnl.gov>1998-09-22 15:27:26 (GMT)
commit6d9af583912f6cd35cdac05283740fdccc489cc4 (patch)
tree9c55a12cac6cdc6e7db890ce9f12e8fbbdd0bd39
parentb20de8612aac8f94916dd7813bec0c398c9bff4f (diff)
downloadhdf5-6d9af583912f6cd35cdac05283740fdccc489cc4.zip
hdf5-6d9af583912f6cd35cdac05283740fdccc489cc4.tar.gz
hdf5-6d9af583912f6cd35cdac05283740fdccc489cc4.tar.bz2
[svn-r714] Changes since 19980911
---------------------- This checkin is to fix a couple bugs for Jim Reus. Some features are not fully implemented but it shouldn't break anything. ./config/conclude.in ./test/Makefile.in `make clean' removes object files from the test directory as well as a couple more *.h5 temp files. ./config/hpux9.03 [NEW] New config file for HP/UX 9.03 ./src/H5B.c ./src/H5Bprivate.h ./src/H5Fistore.c ./src/H5G.c ./src/H5Gnode.c ./src/H5Gpkg.h ./src/H5Gprivate.h ./src/H5Gstab.c Not-yet-complete version of object removal. ./src/H5Fistore.c ./src/H5Fprivate.h Experimental optimizations, disabled by default. ./src/H5Fprivate.h Default low-level driver was changed to H5F_LOW_SEC instead of H5F_LOW_STDIO because the sec2 driver is much easier to debug. ./src/H5Fsplit.c ./src/H5G.c ./src/H5Z.c Changed a couple return statements to HRETURN. ./src/H5Odtype.c Removed a check for nested compound data types from back when they weren't implemented that raised an error. ./tools/h5tools.c Increased temp buffer sizes and added a check for buffer overflow so we fail an assertion (hopefully). This really needs to be fixed sometime. Added support for printing H5T_STRING data types.
-rw-r--r--config/conclude.in2
-rw-r--r--config/hpux9.0338
-rw-r--r--src/H5B.c291
-rw-r--r--src/H5Bprivate.h131
-rw-r--r--src/H5Distore.c153
-rw-r--r--src/H5Fistore.c153
-rw-r--r--src/H5Fprivate.h4
-rw-r--r--src/H5Fsplit.c4
-rw-r--r--src/H5G.c121
-rw-r--r--src/H5Gnode.c1
-rw-r--r--src/H5Gpkg.h7
-rw-r--r--src/H5Gprivate.h1
-rw-r--r--src/H5Gstab.c46
-rw-r--r--src/H5Odtype.c6
-rw-r--r--src/H5Z.c2
-rw-r--r--test/Makefile.in4
-rw-r--r--tools/h5tools.c100
17 files changed, 914 insertions, 150 deletions
diff --git a/config/conclude.in b/config/conclude.in
index 4e1b0b8..ff5f88b 100644
--- a/config/conclude.in
+++ b/config/conclude.in
@@ -69,7 +69,7 @@ uninstall:
# remove things like object files but not libraries or executables.
#
mostlyclean:
- $(RM) $(LIB_OBJ) $(PROG_OBJ) $(MOSTLYCLEAN)
+ $(RM) $(LIB_OBJ) $(TEST_OBJ) $(PROG_OBJ) $(MOSTLYCLEAN)
# Like `mostlyclean' except it also removes the final targets: things like
# libraries and executables. This target doesn't remove any file that
diff --git a/config/hpux9.03 b/config/hpux9.03
new file mode 100644
index 0000000..b593d0d
--- /dev/null
+++ b/config/hpux9.03
@@ -0,0 +1,38 @@
+# -*- shell-script -*-
+#
+# This file is part of the HDF5 build script. It is processed shortly
+# after configure starts and defines, among other things, flags for
+# the various compile modes.
+
+
+#----------------------------------------------------------------------------
+# Compiler flags. The CPPFLAGS values should not include package debug
+# flags like `-DH5G_DEBUG' since these are added with the
+# `--enable-debug' switch of configure.
+
+# What must *always* be present for things to compile correctly?
+CFLAGS="$CFLAGS -Ae"
+#CPPFLAGS="$CPPFLAGS -I."
+
+# What compiler flags should be used for code development?
+DEBUG_CFLAGS=-g
+DEBUG_CPPFLAGS=
+
+# What compiler flags should be used for building a production
+# library?
+PROD_CFLAGS=
+PROD_CPPFLAGS=
+
+# What compiler flags enable code profiling?
+PROFILE_CFLAGS=
+PROFILE_CPPFLAGS=
+
+
+#----------------------------------------------------------------------------
+# Values for overriding configuration tests when cross compiling.
+# This includes compiling on some machines where the serial front end
+# compiles for a parallel back end.
+
+# Set this to `yes' or `no' depending on whether the target is big
+# endian or little endian.
+#ac_cv_c_bigendian=${ac_cv_c_bigendian='yes'}
diff --git a/src/H5B.c b/src/H5B.c
index d8424a9..49b1f17 100644
--- a/src/H5B.c
+++ b/src/H5B.c
@@ -539,16 +539,17 @@ H5B_find(H5F_t *f, const H5B_class_t *type, const haddr_t *addr, void *udata)
}
/* compare */
if ((cmp = (type->cmp3) (f, bt->key[idx].nkey, udata,
- bt->key[idx + 1].nkey)) < 0) {
+ bt->key[idx+1].nkey)) < 0) {
rt = idx;
} else {
- lt = idx + 1;
+ lt = idx+1;
}
}
if (cmp) {
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL,
"B-tree key not found");
}
+
/*
* Follow the link to the subtree or to the data node.
*/
@@ -560,7 +561,7 @@ H5B_find(H5F_t *f, const H5B_class_t *type, const haddr_t *addr, void *udata)
}
} else {
ret_value = (type->found) (f, bt->child + idx, bt->key[idx].nkey,
- udata, bt->key[idx + 1].nkey);
+ udata, bt->key[idx+1].nkey);
if (ret_value < 0) {
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL,
"key not found in leaf node");
@@ -647,17 +648,17 @@ H5B_split(H5F_t *f, const H5B_class_t *type, H5B_t *old_bt,
k * recsize + new_bt->sizeof_rkey);
HDmemcpy(new_bt->native,
old_bt->native + k * type->sizeof_nkey,
- (k + 1) * type->sizeof_nkey);
+ (k+1) * type->sizeof_nkey);
for (i = 0; i <= k; i++) {
/* key */
- new_bt->key[i].dirty = old_bt->key[k + i].dirty;
- if (old_bt->key[k + i].nkey) {
+ new_bt->key[i].dirty = old_bt->key[k+i].dirty;
+ if (old_bt->key[k+i].nkey) {
new_bt->key[i].nkey = new_bt->native + i * type->sizeof_nkey;
}
/* child */
if (i < k) {
- new_bt->child[i] = old_bt->child[k + i];
+ new_bt->child[i] = old_bt->child[k+i];
}
}
new_bt->ndirty = new_bt->nchildren = k;
@@ -757,7 +758,7 @@ H5B_decode_keys(H5F_t *f, H5B_t *bt, intn idx)
HRETURN_ERROR(H5E_BTREE, H5E_CANTDECODE, FAIL,
"unable to decode key");
}
- if (!bt->key[idx + 1].nkey && H5B_decode_key(f, bt, idx + 1) < 0) {
+ if (!bt->key[idx+1].nkey && H5B_decode_key(f, bt, idx+1) < 0) {
HRETURN_ERROR(H5E_BTREE, H5E_CANTDECODE, FAIL,
"unable to decode key");
}
@@ -972,20 +973,20 @@ H5B_insert_child(H5F_t *f, const H5B_class_t *type, H5B_t *bt,
/*
* The MD_KEY is the left key of the new node.
*/
- HDmemmove(bt->page + H5B_SIZEOF_HDR(f) + (idx + 1) * recsize,
+ HDmemmove(bt->page + H5B_SIZEOF_HDR(f) + (idx+1) * recsize,
bt->page + H5B_SIZEOF_HDR(f) + idx * recsize,
(bt->nchildren - idx) * recsize + bt->sizeof_rkey);
- HDmemmove(bt->native + (idx + 1) * type->sizeof_nkey,
+ HDmemmove(bt->native + (idx+1) * type->sizeof_nkey,
bt->native + idx * type->sizeof_nkey,
((bt->nchildren - idx) + 1) * type->sizeof_nkey);
for (i = bt->nchildren; i >= idx; --i) {
- bt->key[i + 1].dirty = bt->key[i].dirty;
+ 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;
+ bt->key[i+1].nkey = bt->native + (i+1) * type->sizeof_nkey;
} else {
- bt->key[i + 1].nkey = NULL;
+ bt->key[i+1].nkey = NULL;
}
}
bt->key[idx].dirty = TRUE;
@@ -997,26 +998,26 @@ H5B_insert_child(H5F_t *f, const H5B_class_t *type, H5B_t *bt,
* The MD_KEY is the right key of the new node.
*/
HDmemmove(bt->page + (H5B_SIZEOF_HDR(f) +
- (idx + 1) * recsize + bt->sizeof_rkey),
+ (idx+1) * recsize + bt->sizeof_rkey),
bt->page + (H5B_SIZEOF_HDR(f) +
idx * recsize + bt->sizeof_rkey),
(bt->nchildren - idx) * recsize);
- HDmemmove(bt->native + (idx + 2) * type->sizeof_nkey,
- bt->native + (idx + 1) * type->sizeof_nkey,
+ HDmemmove(bt->native + (idx+2) * type->sizeof_nkey,
+ bt->native + (idx+1) * type->sizeof_nkey,
(bt->nchildren - idx) * type->sizeof_nkey);
for (i = bt->nchildren; i > idx; --i) {
- bt->key[i + 1].dirty = bt->key[i].dirty;
+ 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;
+ bt->key[i+1].nkey = bt->native + (i+1) * type->sizeof_nkey;
} else {
- bt->key[i + 1].nkey = NULL;
+ bt->key[i+1].nkey = NULL;
}
}
- bt->key[idx + 1].dirty = TRUE;
- bt->key[idx + 1].nkey = bt->native + (idx + 1) * type->sizeof_nkey;
- HDmemcpy(bt->key[idx + 1].nkey, md_key, type->sizeof_nkey);
+ bt->key[idx+1].dirty = TRUE;
+ bt->key[idx+1].nkey = bt->native + (idx+1) * type->sizeof_nkey;
+ HDmemcpy(bt->key[idx+1].nkey, md_key, type->sizeof_nkey);
}
HDmemmove(bt->child + idx + 1,
@@ -1111,7 +1112,7 @@ H5B_insert_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type,
"unable to decode key");
}
if ((cmp = (type->cmp3) (f, bt->key[idx].nkey, udata,
- bt->key[idx + 1].nkey)) < 0) {
+ bt->key[idx+1].nkey)) < 0) {
rt = idx;
} else {
lt = idx + 1;
@@ -1255,9 +1256,9 @@ H5B_insert_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type,
"unable to decode key");
}
my_ins = H5B_INS_RIGHT;
- HDmemcpy(md_key, bt->key[idx + 1].nkey, type->sizeof_nkey);
+ HDmemcpy(md_key, bt->key[idx+1].nkey, type->sizeof_nkey);
if ((type->new_node) (f, H5B_INS_RIGHT, md_key, udata,
- bt->key[idx + 1].nkey, &child_addr/*out*/) < 0) {
+ bt->key[idx+1].nkey, &child_addr/*out*/) < 0) {
HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR,
"can't insert maximum leaf node");
}
@@ -1268,7 +1269,8 @@ H5B_insert_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type,
* We couldn't figure out which branch to follow out of this node. THIS
* IS A MAJOR PROBLEM THAT NEEDS TO BE FIXED --rpm.
*/
- assert("INTERNAL HDF5 ERROR (see rpm)" && 0);
+ assert("INTERNAL HDF5 ERROR (contact rpm)" && 0);
+ HDabort();
} else if (bt->level > 0) {
/*
@@ -1278,8 +1280,8 @@ H5B_insert_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type,
if ((my_ins = H5B_insert_helper(f, bt->child + idx, type,
bt->key[idx].nkey, lt_key_changed,
md_key, udata,
- bt->key[idx + 1].nkey, rt_key_changed,
- &child_addr /*out */ )) < 0) {
+ bt->key[idx+1].nkey, rt_key_changed,
+ &child_addr/*out*/)) < 0) {
HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR,
"can't insert subtree");
}
@@ -1312,11 +1314,11 @@ H5B_insert_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) {
+ bt->key[idx+1].dirty = TRUE;
+ if (idx+1 < bt->nchildren) {
*rt_key_changed = FALSE;
} else {
- HDmemcpy(rt_key, bt->key[idx + 1].nkey, type->sizeof_nkey);
+ HDmemcpy(rt_key, bt->key[idx+1].nkey, type->sizeof_nkey);
}
}
if (H5B_INS_CHANGE == my_ins) {
@@ -1325,7 +1327,7 @@ H5B_insert_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type,
*/
bt->child[idx] = child_addr;
bt->dirty = TRUE;
- bt->ndirty = MAX(bt->ndirty, idx + 1);
+ bt->ndirty = MAX(bt->ndirty, idx+1);
ret_value = H5B_INS_NOOP;
} else if (H5B_INS_LEFT == my_ins || H5B_INS_RIGHT == my_ins) {
@@ -1363,6 +1365,7 @@ H5B_insert_helper(H5F_t *f, const haddr_t *addr, const H5B_class_t *type,
"can't insert child");
}
}
+
/*
* If this node split, return the mid key (the one that is shared
* by the left and right node).
@@ -1500,6 +1503,228 @@ H5B_iterate (H5F_t *f, const H5B_class_t *type, const haddr_t *addr,
/*-------------------------------------------------------------------------
+ * Function: H5B_remove_helper
+ *
+ * Purpose: The recursive part of removing an item from a B-tree. The
+ * sub B-tree that is being considered is located at ADDR and
+ * the item to remove is described by UDATA. If the removed
+ * item falls at the left or right end of the current level then
+ * it might be necessary to adjust the left and/or right keys.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, September 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+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*/)
+{
+ H5B_t *bt = NULL;
+ H5B_ins_t ret_value = H5B_INS_ERROR;
+ intn idx=-1, lt=0, rt, cmp=1;
+
+ FUNC_ENTER(H5B_remove_helper, FAIL);
+ assert(f);
+ assert(addr && H5F_addr_defined(addr));
+ assert(type);
+ assert(type->decode);
+ assert(type->cmp3);
+ assert(type->found);
+ assert(lt_key && lt_key_changed);
+ assert(md_key);
+ assert(udata);
+ assert(rt_key && rt_key_changed);
+
+ /*
+ * Perform a binary search to locate the child which contains the thing
+ * for which we're searching.
+ */
+ if (NULL==(bt=H5AC_protect(f, H5AC_BT, addr, type, udata))) {
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL,
+ "unable to load B-tree node");
+ }
+ rt = bt->nchildren;
+ while (lt<rt && cmp) {
+ idx = (lt+rt)/2;
+ if (H5B_decode_keys(f, bt, idx)<0) {
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, FAIL,
+ "unable to decode B-tree key(s)");
+ }
+ if ((cmp=(type->cmp3)(f, bt->key[idx].nkey, udata,
+ bt->key[idx+1].nkey))<0) {
+ rt = idx;
+ } else {
+ lt = idx+1;
+ }
+ }
+ if (cmp) {
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "B-tree key not found");
+ }
+
+ /*
+ * Follow the link to the subtree or to the data node. The return value
+ * will be one of H5B_INS_ERROR, H5B_INS_NOOP, or H5B_INS_REMOVE.
+ */
+ assert(idx>=0 && idx<bt->nchildren);
+ if (bt->level>0) {
+ if ((ret_value=H5B_remove_helper(f,
+ bt->child+idx,
+ type,
+ bt->key[idx].nkey/*out*/,
+ lt_key_changed/*out*/,
+ md_key/*out*/,
+ udata,
+ bt->key[idx+1].nkey/*out*/,
+ rt_key_changed/*out*/))<0) {
+ HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL,
+ "key not found in subtree");
+ }
+ } else if (type->remove) {
+ 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");
+ }
+ }
+
+ /*
+ * Update left and right key dirty bits if the subtree indicates that they
+ * have changed. If the subtree's left key changed and the subtree is the
+ * left-most child of the current node then we must update the key in our
+ * parent and indicate that it changed. Similarly, if the rigt subtree
+ * key changed and it's the right most key of this node we must update
+ * our right key and indicate that it changed.
+ */
+ if (*lt_key_changed) {
+ bt->dirty = TRUE;
+ bt->key[idx].dirty = TRUE;
+ if (idx>0) {
+ *lt_key_changed = FALSE;
+ } else {
+ HDmemcpy(lt_key, bt->key[idx].nkey, type->sizeof_nkey);
+ }
+ }
+ if (*rt_key_changed) {
+ bt->dirty = TRUE;
+ if (idx+1<bt->nchildren) {
+ *rt_key_changed = FALSE;
+ } else {
+ HDmemcpy(rt_key, bt->key[idx+1].nkey, type->sizeof_nkey);
+ }
+ }
+
+ /*
+ * 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)");
+ } else {
+ HGOTO_ERROR(H5E_BTREE, H5E_UNSUPPORTED, FAIL,
+ "not implemented yet (middle node removal)");
+ }
+
+ done:
+ if (bt && H5AC_unprotect(f, H5AC_BT, addr, bt)<0) {
+ HRETURN_ERROR(H5E_BTREE, H5E_PROTECT, FAIL,
+ "unable to release node");
+ }
+ FUNC_LEAVE(ret_value);
+}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_remove
+ *
+ * Purpose: Removes an item from a B-tree.
+ *
+ * Note: The current version does not attempt to rebalance the tree.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL. Failure includes not being able to
+ * find the object which is to be removed.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, September 16, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+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];
+ 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?*/
+
+ FUNC_ENTER(H5B_remove, FAIL);
+ 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,
+ udata, rt_key, &rt_key_changed)<0) {
+ HRETURN_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL,
+ "unable to remove entry from B-tree");
+ }
+
+ FUNC_LEAVE(SUCCEED);
+}
+
+
+/*-------------------------------------------------------------------------
* Function: H5B_nodesize
*
* Purpose: Returns the number of bytes needed for this type of
@@ -1744,7 +1969,7 @@ H5B_assert(H5F_t *f, const haddr_t *addr, const H5B_class_t *type,
status = H5B_decode_keys(f, bt, i);
assert(status >= 0);
cmp = (type->cmp2) (f, bt->key[i].nkey, udata,
- bt->key[i + 1].nkey);
+ bt->key[i+1].nkey);
assert(cmp < 0);
}
}
diff --git a/src/H5Bprivate.h b/src/H5Bprivate.h
index 17addf5..33a9d99 100644
--- a/src/H5Bprivate.h
+++ b/src/H5Bprivate.h
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
- * Copyright (C) 1997 National Center for Supercomputing Applications.
- * All rights reserved.
+ * Copyright (C) 1997 National Center for Supercomputing Applications.
+ * All rights reserved.
*
*-------------------------------------------------------------------------
*
- * Created: H5Bprivate.h
- * Jul 10 1997
- * Robb Matzke <matzke@llnl.gov>
+ * Created: H5Bprivate.h
+ * Jul 10 1997
+ * Robb Matzke <matzke@llnl.gov>
*
- * Purpose: Private non-prototype header.
+ * Purpose: Private non-prototype header.
*
* Modifications:
*
@@ -17,7 +17,7 @@
#ifndef _H5Bprivate_H
#define _H5Bprivate_H
-#include <H5Bpublic.h> /*API prototypes */
+#include <H5Bpublic.h> /*API prototypes */
/* Private headers needed by this file */
#include <H5private.h>
@@ -25,35 +25,36 @@
/*
* Feature: Define this constant if you want to check B-tree consistency
- * after each B-tree operation. Note that this slows down the
- * library considerably! Debugging the B-tree depends on assert()
- * being enabled.
+ * after each B-tree operation. Note that this slows down the
+ * library considerably! Debugging the B-tree depends on assert()
+ * being enabled.
*/
#ifdef NDEBUG
# undef H5B_DEBUG
#endif
-#define H5B_MAGIC "TREE" /*tree node magic number */
-#define H5B_SIZEOF_MAGIC 4 /*size of magic number */
-#define H5B_SIZEOF_HDR(F) \
- (H5B_SIZEOF_MAGIC + /*magic number */ \
- 4 + /*type, level, num entries */ \
- 2*H5F_SIZEOF_ADDR(F)) /*left and right sibling addresses */
+#define H5B_MAGIC "TREE" /*tree node magic number */
+#define H5B_SIZEOF_MAGIC 4 /*size of magic number */
+#define H5B_SIZEOF_HDR(F) \
+ (H5B_SIZEOF_MAGIC + /*magic number */ \
+ 4 + /*type, level, num entries */ \
+ 2*H5F_SIZEOF_ADDR(F)) /*left and right sibling addresses */
-#define H5B_K(F,TYPE) /*K value given file and Btree subclass */ \
+#define H5B_K(F,TYPE) /*K value given file and Btree subclass */ \
((F)->shared->create_parms->btree_k[(TYPE)->id])
typedef enum H5B_ins_t {
- H5B_INS_ERROR = -1, /*error return value */
- H5B_INS_NOOP = 0, /*insert made no changes */
- H5B_INS_LEFT = 1, /*insert new node to left of cur node */
- H5B_INS_RIGHT = 2, /*insert new node to right of cur node */
- H5B_INS_CHANGE = 3, /*change child address for cur node */
- H5B_INS_FIRST = 4 /*insert first node in (sub)tree */
+ H5B_INS_ERROR = -1, /*error return value */
+ H5B_INS_NOOP = 0, /*insert made no changes */
+ H5B_INS_LEFT = 1, /*insert new node to left of cur node */
+ H5B_INS_RIGHT = 2, /*insert new node to right of cur node */
+ H5B_INS_CHANGE = 3, /*change child address for cur node */
+ H5B_INS_FIRST = 4, /*insert first node in (sub)tree */
+ H5B_INS_REMOVE = 5 /*remove current node */
} H5B_ins_t;
typedef enum H5B_subid_t {
- H5B_SNODE_ID = 0, /*B-tree is for symbol table nodes */
- H5B_ISTORE_ID = 1 /*B-tree is for indexed object storage */
+ H5B_SNODE_ID = 0, /*B-tree is for symbol table nodes */
+ H5B_ISTORE_ID = 1 /*B-tree is for indexed object storage */
} H5B_subid_t;
/*
@@ -63,66 +64,72 @@ typedef enum H5B_subid_t {
* has an array of K values indexed by the `id' class field below. The
* array is initialized with the HDF5_BTREE_K_DEFAULT macro.
*/
-struct H5B_t; /*forward decl */
+struct H5B_t; /*forward decl */
typedef struct H5B_class_t {
- H5B_subid_t id; /*id as found in file*/
- size_t sizeof_nkey; /*size of native (memory) key*/
- size_t (*get_sizeof_rkey) (H5F_t*, const void*); /*raw key size */
- herr_t (*new_node) (H5F_t*, H5B_ins_t, void*, void*, void*, haddr_t*);
- intn (*cmp2) (H5F_t*, void*, void*, void*); /*compare 2 keys */
- intn (*cmp3) (H5F_t*, void*, void*, void*); /*compare 3 keys */
- herr_t (*found) (H5F_t*, const haddr_t*, const void*, void*,
- const void*);
-
- /* insert new data */
- H5B_ins_t (*insert) (H5F_t*, const haddr_t*, void*, hbool_t*,
- void*, void*, void*, hbool_t*, haddr_t*);
+ H5B_subid_t id; /*id as found in file*/
+ size_t sizeof_nkey; /*size of native (memory) key*/
+ size_t (*get_sizeof_rkey)(H5F_t*, const void*); /*raw key size */
+ herr_t (*new_node) (H5F_t*, H5B_ins_t, void*, void*, void*, haddr_t*);
+ intn (*cmp2)(H5F_t*, void*, void*, void*); /*compare 2 keys */
+ intn (*cmp3)(H5F_t*, void*, void*, void*); /*compare 3 keys */
+ herr_t (*found)(H5F_t*, const haddr_t*, const void*, void*,
+ const void*);
+ /* insert new data */
+ H5B_ins_t (*insert)(H5F_t*, const haddr_t*, void*, hbool_t*,
+ void*, void*, void*, hbool_t*, haddr_t*);
+
/* min insert uses min leaf, not new(), similarily for max insert */
- hbool_t follow_min;
- hbool_t follow_max;
+ hbool_t follow_min;
+ hbool_t follow_max;
+
+ /* remove existing data */
+ H5B_ins_t (*remove)(H5F_t*, const haddr_t*, void*, hbool_t*,
+ void*, 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*);
- herr_t (*encode) (H5F_t*, struct H5B_t*, uint8*, void*);
- herr_t (*debug_key)(FILE*, intn, intn, const void*, const void*);
+ herr_t (*list)(H5F_t*, const haddr_t*, void*); /*walk leaf nodes*/
+ herr_t (*decode)(H5F_t*, struct H5B_t*, uint8*, void*);
+ herr_t (*encode)(H5F_t*, struct H5B_t*, uint8*, void*);
+ herr_t (*debug_key)(FILE*, intn, intn, const void*, const void*);
} H5B_class_t;
/*
* The B-tree node as stored in memory...
*/
typedef struct H5B_key_t {
- hbool_t dirty; /*native key is more recent than raw key */
- uint8 *rkey; /*ptr into node->page for raw key */
- void *nkey; /*null or ptr into node->native for key */
+ hbool_t dirty; /*native key is more recent than raw key */
+ uint8 *rkey; /*ptr into node->page for raw key */
+ void *nkey; /*null or ptr into node->native for key */
} H5B_key_t;
typedef struct H5B_t {
- const H5B_class_t *type; /*type of tree */
- size_t sizeof_rkey; /*size of raw (disk) key */
- hbool_t dirty; /*something in the tree is dirty */
- intn ndirty; /*num child ptrs to emit */
- intn level; /*node level */
- haddr_t left; /*address of left sibling */
- haddr_t right; /*address of right sibling */
- intn nchildren; /*number of child pointers */
- uint8 *page; /*disk page */
- uint8 *native; /*array of keys in native format */
- H5B_key_t *key; /*2k+1 key entries */
- haddr_t *child; /*2k child pointers */
+ const H5B_class_t *type; /*type of tree */
+ size_t sizeof_rkey; /*size of raw (disk) key */
+ hbool_t dirty; /*something in the tree is dirty */
+ intn ndirty; /*num child ptrs to emit */
+ intn level; /*node level */
+ haddr_t left; /*address of left sibling */
+ haddr_t right; /*address of right sibling */
+ intn nchildren; /*number of child pointers */
+ uint8 *page; /*disk page */
+ uint8 *native; /*array of keys in native format */
+ H5B_key_t *key; /*2k+1 key entries */
+ haddr_t *child; /*2k child pointers */
} H5B_t;
/*
* Library prototypes.
*/
herr_t H5B_debug (H5F_t *f, const haddr_t *addr, FILE * stream, intn indent,
- intn fwidth, const H5B_class_t *type, void *udata);
+ intn fwidth, const H5B_class_t *type, void *udata);
herr_t H5B_create (H5F_t *f, const H5B_class_t *type, void *udata, haddr_t *);
herr_t H5B_find (H5F_t *f, const H5B_class_t *type, const haddr_t *addr,
- void *udata);
+ void *udata);
herr_t H5B_insert (H5F_t *f, const H5B_class_t *type, const haddr_t *addr,
- void *udata);
+ void *udata);
+herr_t H5B_remove(H5F_t *f, const H5B_class_t *type, const haddr_t *addr,
+ void *udata);
herr_t H5B_iterate (H5F_t *f, const H5B_class_t *type, const haddr_t *addr,
void *udata);
#endif
diff --git a/src/H5Distore.c b/src/H5Distore.c
index aa7c266..3a54612 100644
--- a/src/H5Distore.c
+++ b/src/H5Distore.c
@@ -107,6 +107,7 @@ H5B_class_t H5B_ISTORE[1] = {{
H5F_istore_insert, /*insert */
FALSE, /*follow min branch? */
FALSE, /*follow max branch? */
+ NULL, /*remove */
NULL, /*list */
H5F_istore_decode_key, /*decode */
H5F_istore_encode_key, /*encode */
@@ -850,11 +851,20 @@ H5F_istore_flush (H5F_t *f)
FUNC_ENTER (H5F_istore_flush, FAIL);
+#ifdef H5F_RDCC_NEW
+ for (i=0; i<rdcc->nslots; i++) {
+ if (rdcc->slot[i].chunk &&
+ H5F_istore_flush_entry(f, rdcc->slot+i, FALSE)<0) {
+ nerrors++;
+ }
+ }
+#else
for (i=0; i<rdcc->nused; i++) {
if (H5F_istore_flush_entry (f, rdcc->slot+i, FALSE)<0) {
nerrors++;
}
}
+#endif
if (nerrors) {
HRETURN_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL,
"unable to flush one or more raw data chunks");
@@ -886,6 +896,14 @@ H5F_istore_preempt (H5F_t *f, intn idx)
H5F_rdcc_ent_t *ent = rdcc->slot + idx;
FUNC_ENTER (H5F_istore_preempt, FAIL);
+
+#ifdef H5F_RDCC_NEW
+ assert(idx>=0 && idx<rdcc->nslots);
+ assert (!ent->locked);
+
+ H5F_istore_flush_entry(f, ent, TRUE);
+ rdcc->nbytes -= ent->chunk_size;
+#else
assert (idx>=0 && idx<rdcc->nused);
assert (!ent->locked);
@@ -894,7 +912,8 @@ H5F_istore_preempt (H5F_t *f, intn idx)
(rdcc->nused-(idx+1)) * sizeof(H5F_rdcc_ent_t));
rdcc->nused -= 1;
rdcc->nbytes -= ent->chunk_size;
-
+#endif
+
FUNC_LEAVE (SUCCEED);
}
@@ -924,11 +943,20 @@ H5F_istore_dest (H5F_t *f)
FUNC_ENTER (H5F_istore_dest, FAIL);
+#ifdef H5F_RDCC_NEW
+ for (i=0; i<rdcc->nslots; i++) {
+ if (rdcc->slot[i].chunk &&
+ H5F_istore_preempt(f, i)<0) {
+ nerrors++;
+ }
+ }
+#else
for (i=rdcc->nused-1; i>=0; --i) {
if (H5F_istore_preempt(f, i)<0) {
nerrors++;
}
}
+#endif
if (nerrors) {
HRETURN_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL,
"unable to flush one or more raw data chunks");
@@ -961,14 +989,31 @@ H5F_istore_dest (H5F_t *f)
static herr_t
H5F_istore_prune (H5F_t *f, size_t size)
{
+#ifdef H5F_RDCC_NEW
+ intn i, nerrors=0;
+ static intn place=0;
+ H5F_rdcc_t *rdcc = &(f->shared->rdcc);
+ H5F_rdcc_ent_t *ent = NULL;
+ size_t total = f->shared->access_parms->rdcc_nbytes;
+#else
intn i, meth0, meth1, nerrors=0;
H5F_rdcc_t *rdcc = &(f->shared->rdcc);
H5F_rdcc_ent_t *ent0, *ent1;
double w0 = f->shared->access_parms->rdcc_w0;
size_t total = f->shared->access_parms->rdcc_nbytes;
-
+#endif
+
FUNC_ENTER (H5F_istore_prune, FAIL);
+#ifdef H5F_RDCC_NEW
+ for (i=0; rdcc->nbytes+size>total && i<rdcc->nslots; i++, place++) {
+ if (place>=rdcc->nslots) place = 0;
+ ent = rdcc->slot+place;
+ if (ent->chunk && !ent->locked) {
+ if (H5F_istore_preempt(f, place)<0) nerrors++;
+ }
+ }
+#else
/*
* We have two pointers that slide down the cache beginning at the least
* recently used entry. The distance between the pointers represents the
@@ -1003,6 +1048,7 @@ H5F_istore_prune (H5F_t *f, size_t size)
if (H5F_istore_preempt (f, meth1)<0) nerrors++;
}
}
+#endif
if (nerrors) {
HRETURN_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL,
"unable to preempt one or more raw data cache entry");
@@ -1015,11 +1061,14 @@ H5F_istore_prune (H5F_t *f, size_t size)
/*-------------------------------------------------------------------------
* Function: H5F_istore_lock
*
- * Purpose: Return a pointer to a file chunk chunk. The pointer
- * points directly into the chunk cache and should not be freed
+ * Purpose: Return a pointer to a dataset chunk. The pointer points
+ * directly into the chunk cache and should not be freed
* by the caller but will be valid until it is unlocked. The
* input value IDX_HINT is used to speed up cache lookups and
* it's output value should be given to H5F_rdcc_unlock().
+ * IDX_HINT is ignored if it is out of range, and if it points
+ * to the wrong entry then we fall back to the normal search
+ * method.
*
* If RELAX is non-zero and the chunk isn't in the cache then
* don't try to read it from the file, but just allocate an
@@ -1043,19 +1092,41 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
const H5O_pline_t *pline, const hssize_t offset[],
hbool_t relax, intn *idx_hint/*in,out*/)
{
- H5F_rdcc_t *rdcc = &(f->shared->rdcc);
- H5F_rdcc_ent_t *ent = NULL;
- intn i, j, found = -1;
+#ifdef H5F_RDCC_NEW
+ uintn idx;
+#endif
+ H5F_rdcc_t *rdcc = &(f->shared->rdcc);/*raw data chunk cache*/
+ H5F_rdcc_ent_t *ent = NULL; /*cache entry */
+ intn i, j, found = -1; /*counters */
H5F_istore_ud1_t udata; /*B-tree pass-through */
size_t chunk_size=0; /*size of a chunk */
size_t chunk_alloc=0; /*allocated chunk size */
herr_t status; /*func return status */
void *chunk=NULL; /*the file chunk */
void *ret_value=NULL; /*return value */
-
+
FUNC_ENTER (H5F_istore_lock, NULL);
- /* First use the hint */
+#ifdef H5F_RDCC_NEW
+ if (rdcc->nslots>0) {
+ idx = layout->addr.offset;
+ for (i=0; i<layout->ndims; i++) idx ^= offset[i];
+ idx %= rdcc->nslots;
+ ent = rdcc->slot + idx;
+
+ if (ent->chunk &&
+ layout->ndims==ent->layout->ndims &&
+ H5F_addr_eq(&(layout->addr), &(ent->layout->addr))) {
+ for (i=0, found=idx; i<ent->layout->ndims; i++) {
+ if (offset[i]!=ent->offset[i]) {
+ found = -1;
+ break;
+ }
+ }
+ }
+ }
+#else
+ /* First use the hint because that's O(1) */
if (idx_hint && *idx_hint>=0 && *idx_hint<rdcc->nused) {
ent = rdcc->slot + *idx_hint;
if (layout->ndims==ent->layout->ndims &&
@@ -1066,7 +1137,7 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
}
}
- /* Then look at all the entries */
+ /* If the hint is wrong then search the cache, O(n) */
for (i=0; found<0 && i<rdcc->nused; i++) {
ent = rdcc->slot + i;
if (layout->ndims==ent->layout->ndims &&
@@ -1076,7 +1147,7 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
}
}
}
-
+#endif
if (found>=0) {
/*
@@ -1146,6 +1217,39 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
}
assert (found>=0 || chunk_size>0);
+#ifdef H5F_RDCC_NEW
+ if (found<0 && rdcc->nslots>0 &&
+ chunk_size<=f->shared->access_parms->rdcc_nbytes &&
+ (NULL==ent->chunk || !ent->locked)) {
+ /*
+ * Add the chunk to the cache only if the slot is not already locked.
+ * Preempt enough things from the cache to make room.
+ */
+ if (H5F_istore_prune(f, chunk_size)<0) {
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL,
+ "unable to preempt chunk(s) from cache");
+ }
+ if (rdcc->slot[idx].chunk &&
+ H5F_istore_preempt(f, idx)<0) {
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL,
+ "unable to preempt chunk from cache");
+ }
+ ent = rdcc->slot + idx;
+ ent->locked = 0;
+ ent->dirty = FALSE;
+ ent->chunk_size = chunk_size;
+ ent->alloc_size = chunk_size;
+ ent->layout = H5O_copy(H5O_LAYOUT, layout, NULL);
+ ent->pline = H5O_copy(H5O_PLINE, pline, NULL);
+ for (i=0; i<layout->ndims; i++) {
+ ent->offset[i] = offset[i];
+ }
+ ent->rd_count = chunk_size;
+ ent->wr_count = chunk_size;
+ ent->chunk = chunk;
+ found = idx;
+ }
+#else
if (found<0 && chunk_size<=f->shared->access_parms->rdcc_nbytes) {
/*
* Add the chunk to the beginning of the cache after pruning the cache
@@ -1183,8 +1287,9 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
ent->wr_count = chunk_size;
ent->chunk = chunk;
found = 0;
-
- } else if (found<0) {
+ }
+#endif
+ else if (found<0) {
/*
* The chunk is larger than the entire cache so we don't cache it.
* This is the reason all those arguments have to be repeated for the
@@ -1192,7 +1297,8 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
*/
ent = NULL;
found = -999;
-
+
+#ifndef H5F_RDCC_NEW
} else if (found>0) {
/*
* The chunk is not at the beginning of the cache; move it forward by
@@ -1202,17 +1308,24 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
rdcc->slot[found] = rdcc->slot[found-1];
rdcc->slot[found-1] = x;
ent = rdcc->slot + --found;
+#endif
}
/* Lock the chunk into the cache */
if (ent) {
assert (!ent->locked);
ent->locked = TRUE;
+#ifndef H5F_RDCC_NEW
if (idx_hint) *idx_hint = found;
+#endif
chunk = ent->chunk;
}
+#ifdef H5F_RDCC_NEW
+ if (idx_hint) *idx_hint = found;
+#endif
ret_value = chunk;
+
done:
if (!ret_value) H5MM_xfree (chunk);
FUNC_LEAVE (ret_value);
@@ -1257,6 +1370,15 @@ H5F_istore_unlock (H5F_t *f, const H5O_layout_t *layout,
FUNC_ENTER (H5F_istore_unlock, FAIL);
+#ifdef H5F_RDCC_NEW
+ if (-999==*idx_hint) {
+ /*not in cache*/
+ } else {
+ assert(*idx_hint>=0 && *idx_hint<rdcc->nslots);
+ assert(rdcc->slot[*idx_hint].chunk==chunk);
+ found = *idx_hint;
+ }
+#else
/* First look at the hint */
if (idx_hint && *idx_hint>=0 && *idx_hint<rdcc->nused) {
if (rdcc->slot[*idx_hint].chunk==chunk) found = *idx_hint;
@@ -1266,7 +1388,8 @@ H5F_istore_unlock (H5F_t *f, const H5O_layout_t *layout,
for (i=0; found<0 && i<rdcc->nused; i++) {
if (rdcc->slot[i].chunk==chunk) found = i;
}
-
+#endif
+
if (found<0) {
/*
* It's not in the cache, probably because it's too big. If it's
diff --git a/src/H5Fistore.c b/src/H5Fistore.c
index aa7c266..3a54612 100644
--- a/src/H5Fistore.c
+++ b/src/H5Fistore.c
@@ -107,6 +107,7 @@ H5B_class_t H5B_ISTORE[1] = {{
H5F_istore_insert, /*insert */
FALSE, /*follow min branch? */
FALSE, /*follow max branch? */
+ NULL, /*remove */
NULL, /*list */
H5F_istore_decode_key, /*decode */
H5F_istore_encode_key, /*encode */
@@ -850,11 +851,20 @@ H5F_istore_flush (H5F_t *f)
FUNC_ENTER (H5F_istore_flush, FAIL);
+#ifdef H5F_RDCC_NEW
+ for (i=0; i<rdcc->nslots; i++) {
+ if (rdcc->slot[i].chunk &&
+ H5F_istore_flush_entry(f, rdcc->slot+i, FALSE)<0) {
+ nerrors++;
+ }
+ }
+#else
for (i=0; i<rdcc->nused; i++) {
if (H5F_istore_flush_entry (f, rdcc->slot+i, FALSE)<0) {
nerrors++;
}
}
+#endif
if (nerrors) {
HRETURN_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL,
"unable to flush one or more raw data chunks");
@@ -886,6 +896,14 @@ H5F_istore_preempt (H5F_t *f, intn idx)
H5F_rdcc_ent_t *ent = rdcc->slot + idx;
FUNC_ENTER (H5F_istore_preempt, FAIL);
+
+#ifdef H5F_RDCC_NEW
+ assert(idx>=0 && idx<rdcc->nslots);
+ assert (!ent->locked);
+
+ H5F_istore_flush_entry(f, ent, TRUE);
+ rdcc->nbytes -= ent->chunk_size;
+#else
assert (idx>=0 && idx<rdcc->nused);
assert (!ent->locked);
@@ -894,7 +912,8 @@ H5F_istore_preempt (H5F_t *f, intn idx)
(rdcc->nused-(idx+1)) * sizeof(H5F_rdcc_ent_t));
rdcc->nused -= 1;
rdcc->nbytes -= ent->chunk_size;
-
+#endif
+
FUNC_LEAVE (SUCCEED);
}
@@ -924,11 +943,20 @@ H5F_istore_dest (H5F_t *f)
FUNC_ENTER (H5F_istore_dest, FAIL);
+#ifdef H5F_RDCC_NEW
+ for (i=0; i<rdcc->nslots; i++) {
+ if (rdcc->slot[i].chunk &&
+ H5F_istore_preempt(f, i)<0) {
+ nerrors++;
+ }
+ }
+#else
for (i=rdcc->nused-1; i>=0; --i) {
if (H5F_istore_preempt(f, i)<0) {
nerrors++;
}
}
+#endif
if (nerrors) {
HRETURN_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL,
"unable to flush one or more raw data chunks");
@@ -961,14 +989,31 @@ H5F_istore_dest (H5F_t *f)
static herr_t
H5F_istore_prune (H5F_t *f, size_t size)
{
+#ifdef H5F_RDCC_NEW
+ intn i, nerrors=0;
+ static intn place=0;
+ H5F_rdcc_t *rdcc = &(f->shared->rdcc);
+ H5F_rdcc_ent_t *ent = NULL;
+ size_t total = f->shared->access_parms->rdcc_nbytes;
+#else
intn i, meth0, meth1, nerrors=0;
H5F_rdcc_t *rdcc = &(f->shared->rdcc);
H5F_rdcc_ent_t *ent0, *ent1;
double w0 = f->shared->access_parms->rdcc_w0;
size_t total = f->shared->access_parms->rdcc_nbytes;
-
+#endif
+
FUNC_ENTER (H5F_istore_prune, FAIL);
+#ifdef H5F_RDCC_NEW
+ for (i=0; rdcc->nbytes+size>total && i<rdcc->nslots; i++, place++) {
+ if (place>=rdcc->nslots) place = 0;
+ ent = rdcc->slot+place;
+ if (ent->chunk && !ent->locked) {
+ if (H5F_istore_preempt(f, place)<0) nerrors++;
+ }
+ }
+#else
/*
* We have two pointers that slide down the cache beginning at the least
* recently used entry. The distance between the pointers represents the
@@ -1003,6 +1048,7 @@ H5F_istore_prune (H5F_t *f, size_t size)
if (H5F_istore_preempt (f, meth1)<0) nerrors++;
}
}
+#endif
if (nerrors) {
HRETURN_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL,
"unable to preempt one or more raw data cache entry");
@@ -1015,11 +1061,14 @@ H5F_istore_prune (H5F_t *f, size_t size)
/*-------------------------------------------------------------------------
* Function: H5F_istore_lock
*
- * Purpose: Return a pointer to a file chunk chunk. The pointer
- * points directly into the chunk cache and should not be freed
+ * Purpose: Return a pointer to a dataset chunk. The pointer points
+ * directly into the chunk cache and should not be freed
* by the caller but will be valid until it is unlocked. The
* input value IDX_HINT is used to speed up cache lookups and
* it's output value should be given to H5F_rdcc_unlock().
+ * IDX_HINT is ignored if it is out of range, and if it points
+ * to the wrong entry then we fall back to the normal search
+ * method.
*
* If RELAX is non-zero and the chunk isn't in the cache then
* don't try to read it from the file, but just allocate an
@@ -1043,19 +1092,41 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
const H5O_pline_t *pline, const hssize_t offset[],
hbool_t relax, intn *idx_hint/*in,out*/)
{
- H5F_rdcc_t *rdcc = &(f->shared->rdcc);
- H5F_rdcc_ent_t *ent = NULL;
- intn i, j, found = -1;
+#ifdef H5F_RDCC_NEW
+ uintn idx;
+#endif
+ H5F_rdcc_t *rdcc = &(f->shared->rdcc);/*raw data chunk cache*/
+ H5F_rdcc_ent_t *ent = NULL; /*cache entry */
+ intn i, j, found = -1; /*counters */
H5F_istore_ud1_t udata; /*B-tree pass-through */
size_t chunk_size=0; /*size of a chunk */
size_t chunk_alloc=0; /*allocated chunk size */
herr_t status; /*func return status */
void *chunk=NULL; /*the file chunk */
void *ret_value=NULL; /*return value */
-
+
FUNC_ENTER (H5F_istore_lock, NULL);
- /* First use the hint */
+#ifdef H5F_RDCC_NEW
+ if (rdcc->nslots>0) {
+ idx = layout->addr.offset;
+ for (i=0; i<layout->ndims; i++) idx ^= offset[i];
+ idx %= rdcc->nslots;
+ ent = rdcc->slot + idx;
+
+ if (ent->chunk &&
+ layout->ndims==ent->layout->ndims &&
+ H5F_addr_eq(&(layout->addr), &(ent->layout->addr))) {
+ for (i=0, found=idx; i<ent->layout->ndims; i++) {
+ if (offset[i]!=ent->offset[i]) {
+ found = -1;
+ break;
+ }
+ }
+ }
+ }
+#else
+ /* First use the hint because that's O(1) */
if (idx_hint && *idx_hint>=0 && *idx_hint<rdcc->nused) {
ent = rdcc->slot + *idx_hint;
if (layout->ndims==ent->layout->ndims &&
@@ -1066,7 +1137,7 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
}
}
- /* Then look at all the entries */
+ /* If the hint is wrong then search the cache, O(n) */
for (i=0; found<0 && i<rdcc->nused; i++) {
ent = rdcc->slot + i;
if (layout->ndims==ent->layout->ndims &&
@@ -1076,7 +1147,7 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
}
}
}
-
+#endif
if (found>=0) {
/*
@@ -1146,6 +1217,39 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
}
assert (found>=0 || chunk_size>0);
+#ifdef H5F_RDCC_NEW
+ if (found<0 && rdcc->nslots>0 &&
+ chunk_size<=f->shared->access_parms->rdcc_nbytes &&
+ (NULL==ent->chunk || !ent->locked)) {
+ /*
+ * Add the chunk to the cache only if the slot is not already locked.
+ * Preempt enough things from the cache to make room.
+ */
+ if (H5F_istore_prune(f, chunk_size)<0) {
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL,
+ "unable to preempt chunk(s) from cache");
+ }
+ if (rdcc->slot[idx].chunk &&
+ H5F_istore_preempt(f, idx)<0) {
+ HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL,
+ "unable to preempt chunk from cache");
+ }
+ ent = rdcc->slot + idx;
+ ent->locked = 0;
+ ent->dirty = FALSE;
+ ent->chunk_size = chunk_size;
+ ent->alloc_size = chunk_size;
+ ent->layout = H5O_copy(H5O_LAYOUT, layout, NULL);
+ ent->pline = H5O_copy(H5O_PLINE, pline, NULL);
+ for (i=0; i<layout->ndims; i++) {
+ ent->offset[i] = offset[i];
+ }
+ ent->rd_count = chunk_size;
+ ent->wr_count = chunk_size;
+ ent->chunk = chunk;
+ found = idx;
+ }
+#else
if (found<0 && chunk_size<=f->shared->access_parms->rdcc_nbytes) {
/*
* Add the chunk to the beginning of the cache after pruning the cache
@@ -1183,8 +1287,9 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
ent->wr_count = chunk_size;
ent->chunk = chunk;
found = 0;
-
- } else if (found<0) {
+ }
+#endif
+ else if (found<0) {
/*
* The chunk is larger than the entire cache so we don't cache it.
* This is the reason all those arguments have to be repeated for the
@@ -1192,7 +1297,8 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
*/
ent = NULL;
found = -999;
-
+
+#ifndef H5F_RDCC_NEW
} else if (found>0) {
/*
* The chunk is not at the beginning of the cache; move it forward by
@@ -1202,17 +1308,24 @@ H5F_istore_lock (H5F_t *f, const H5O_layout_t *layout,
rdcc->slot[found] = rdcc->slot[found-1];
rdcc->slot[found-1] = x;
ent = rdcc->slot + --found;
+#endif
}
/* Lock the chunk into the cache */
if (ent) {
assert (!ent->locked);
ent->locked = TRUE;
+#ifndef H5F_RDCC_NEW
if (idx_hint) *idx_hint = found;
+#endif
chunk = ent->chunk;
}
+#ifdef H5F_RDCC_NEW
+ if (idx_hint) *idx_hint = found;
+#endif
ret_value = chunk;
+
done:
if (!ret_value) H5MM_xfree (chunk);
FUNC_LEAVE (ret_value);
@@ -1257,6 +1370,15 @@ H5F_istore_unlock (H5F_t *f, const H5O_layout_t *layout,
FUNC_ENTER (H5F_istore_unlock, FAIL);
+#ifdef H5F_RDCC_NEW
+ if (-999==*idx_hint) {
+ /*not in cache*/
+ } else {
+ assert(*idx_hint>=0 && *idx_hint<rdcc->nslots);
+ assert(rdcc->slot[*idx_hint].chunk==chunk);
+ found = *idx_hint;
+ }
+#else
/* First look at the hint */
if (idx_hint && *idx_hint>=0 && *idx_hint<rdcc->nused) {
if (rdcc->slot[*idx_hint].chunk==chunk) found = *idx_hint;
@@ -1266,7 +1388,8 @@ H5F_istore_unlock (H5F_t *f, const H5O_layout_t *layout,
for (i=0; found<0 && i<rdcc->nused; i++) {
if (rdcc->slot[i].chunk==chunk) found = i;
}
-
+#endif
+
if (found<0) {
/*
* It's not in the cache, probably because it's too big. If it's
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
index 98b4944..cf92283 100644
--- a/src/H5Fprivate.h
+++ b/src/H5Fprivate.h
@@ -400,7 +400,7 @@ typedef struct H5F_low_t {
/* What types of low-level files are there? */
#ifndef H5F_LOW_DFLT
-# define H5F_LOW_DFLT H5F_LOW_STDIO /* The default type */
+# define H5F_LOW_DFLT H5F_LOW_SEC2 /* The default type */
#endif
extern const H5F_low_class_t H5F_LOW_SEC2_g[]; /* Posix section 2 */
extern const H5F_low_class_t H5F_LOW_STDIO_g[]; /* Posix stdio */
@@ -419,7 +419,9 @@ typedef struct H5F_rdcc_t {
uintn nflushes;/* Number of cache flushes */
size_t nbytes; /* Current cached raw data in bytes */
intn nslots; /* Number of chunk slots allocated */
+#ifndef H5F_RDCC_NEW
intn nused; /* Number of chunk slots in use */
+#endif
struct H5F_rdcc_ent_t *slot; /* Chunk slots, each points to a chunk */
} H5F_rdcc_t;
diff --git a/src/H5Fsplit.c b/src/H5Fsplit.c
index e4a78f2..25ef2d5 100644
--- a/src/H5Fsplit.c
+++ b/src/H5Fsplit.c
@@ -501,10 +501,10 @@ H5F_split_alloc (H5F_low_t *lf, intn op, hsize_t alignment, hsize_t threshold,
switch (op) {
case H5MF_META:
- if (blk->addr.offset & lf->u.split.mask) return FAIL;
+ if (blk->addr.offset & lf->u.split.mask) HRETURN(FAIL);
break;
case H5MF_RAW:
- if (0==(blk->addr.offset & lf->u.split.mask)) return FAIL;
+ if (0==(blk->addr.offset & lf->u.split.mask)) HRETURN(FAIL);
break;
}
diff --git a/src/H5G.c b/src/H5G.c
index 8e591bd..a8fa956 100644
--- a/src/H5G.c
+++ b/src/H5G.c
@@ -618,13 +618,25 @@ H5Glink(hid_t loc_id, H5G_link_t type, const char *cur_name,
*-------------------------------------------------------------------------
*/
herr_t
-H5Gunlink(hid_t __unused__ loc_id, const char __unused__ *name)
+H5Gunlink(hid_t loc_id, const char *name)
{
+ H5G_entry_t *loc = NULL;
+
FUNC_ENTER (H5Gunlink, FAIL);
H5TRACE2("e","is",loc_id,name);
- HRETURN_ERROR (H5E_SYM, H5E_UNSUPPORTED, FAIL,
- "unable to unlink name (not implemented yet)");
+ /* Check arguments */
+ if (NULL==(loc=H5G_loc(loc_id))) {
+ HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location");
+ }
+ if (!name || !*name) {
+ HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name");
+ }
+
+ /* Unlink */
+ if (H5G_unlink(loc, name)<0) {
+ HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to unlink object");
+ }
FUNC_LEAVE (SUCCEED);
}
@@ -907,6 +919,50 @@ H5G_component(const char *name, size_t *size_p)
/*-------------------------------------------------------------------------
+ * Function: H5G_basename
+ *
+ * Purpose: Returns a pointer to the last component of the specified
+ * name. The length of the component is returned through SIZE_P.
+ * The base name is followed by zero or more slashes and a null
+ * terminator, but SIZE_P does not count the slashes or the null
+ * terminator.
+ *
+ * Note: The base name of the root directory is a single slash.
+ *
+ * Return: Success: Ptr to base name.
+ *
+ * Failure: Ptr to the null terminator.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 17, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static const char *
+H5G_basename(const char *name, size_t *size_p)
+{
+ size_t i, end;
+
+ FUNC_ENTER(H5G_basename, NULL);
+
+ /* Find the end of the base name */
+ i = strlen(name);
+ while (i>0 && '/'==name[i-1]) --i;
+ end = i;
+
+ /* Skip backward over base name */
+ while (i>0 && '/'!=name[i-1]) --i;
+
+ /* Watch out for root special case */
+ if ('/'==name[i] && size_p) *size_p = 1;
+
+ FUNC_LEAVE(name+i);
+}
+
+
+/*-------------------------------------------------------------------------
* Function: H5G_namei
*
* Purpose: Translates a name to a symbol table entry.
@@ -930,9 +986,9 @@ H5G_component(const char *name, size_t *size_p)
* undefined object header address if the search failed at the
* root object. For instance, if NAME is `/foo/bar/baz' and the
* root directory exists and contains an entry for `foo', and
- * foo is a group that contains an entry for baz, but baz is not
+ * foo is a group that contains an entry for bar, but bar is not
* a group, then the results will be that REST points to `baz',
- * GRP_ENT has an undefined object header address, and GRP_ENT
+ * OBJ_ENT has an undefined object header address, and GRP_ENT
* is the symbol table entry for `bar' in `/foo'.
*
* Every file has a root group whose name is `/'. Components of
@@ -1131,7 +1187,7 @@ H5G_traverse_slink (H5G_entry_t *grp_ent/*in,out*/,
*
* Purpose: Creates a root group in an empty file and opens it. If a
* root group is already open then this function immediately
- * returnes. If ENT is non-null then it's the symbol table
+ * returns. If ENT is non-null then it's the symbol table
* entry for an existing group which will be opened as the root
* group. Otherwise a new root group is created and then
* opened.
@@ -1158,7 +1214,7 @@ H5G_mkroot (H5F_t *f, H5G_entry_t *ent)
/* check args */
assert(f);
- if (f->shared->root_grp) return SUCCEED;
+ if (f->shared->root_grp) HRETURN(SUCCEED);
/*
* If there is no root object then create one. The root group always has
@@ -1663,7 +1719,7 @@ H5G_insert(H5G_entry_t *loc, const char *name, H5G_entry_t *ent)
}
/*
- * The object into a symbol table.
+ * Insert the object into a symbol table.
*/
if (H5O_link(ent, 1) < 0) {
HRETURN_ERROR(H5E_SYM, H5E_LINK, FAIL, "link inc failure");
@@ -2278,3 +2334,52 @@ H5G_get_comment(H5G_entry_t *loc, const char *name, size_t bufsize, char *buf)
FUNC_LEAVE(retval);
}
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_unlink
+ *
+ * Purpose: Unlink a name from a group.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 17, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_unlink(H5G_entry_t *loc, const char *name)
+{
+ H5G_entry_t grp_ent, obj_ent;
+ size_t len;
+ const char *base=NULL;
+
+ FUNC_ENTER(H5G_unlink, FAIL);
+ assert(loc);
+ assert(name && *name);
+
+ /* Get the entry for the group that contains the object to be unlinked */
+ if (H5G_namei(loc, name, NULL, &grp_ent, &obj_ent, FALSE, NULL)<0) {
+ HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found");
+ }
+ if (!H5F_addr_defined(&(grp_ent.header))) {
+ HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL,
+ "no containing group specified");
+ }
+ if (NULL==(base=H5G_basename(name, &len)) || '/'==*base) {
+ HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL,
+ "problems obtaining object base name");
+ }
+
+ /* Remove the name from the symbol table */
+ if (H5G_stab_remove(&grp_ent, base)<0) {
+ HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL,
+ "unable to unlink name from symbol table");
+ }
+
+ FUNC_LEAVE(SUCCEED);
+}
diff --git a/src/H5Gnode.c b/src/H5Gnode.c
index 1751edb..ac7e991 100644
--- a/src/H5Gnode.c
+++ b/src/H5Gnode.c
@@ -80,6 +80,7 @@ H5B_class_t H5B_SNODE[1] = {{
H5G_node_insert, /*insert */
TRUE, /*follow min branch? */
TRUE, /*follow max branch? */
+ NULL, /*remove */
H5G_node_iterate, /*list */
H5G_node_decode_key, /*decode */
H5G_node_encode_key, /*encode */
diff --git a/src/H5Gpkg.h b/src/H5Gpkg.h
index c4579be..f0ee156 100644
--- a/src/H5Gpkg.h
+++ b/src/H5Gpkg.h
@@ -70,8 +70,9 @@ typedef struct H5G_cwgstk_t {
* H5G_node layer through the B-tree layer.
*/
typedef enum H5G_oper_t {
- H5G_OPER_FIND = 0, /*find a symbol */
- H5G_OPER_INSERT = 1 /*insert a new symbol */
+ H5G_OPER_FIND = 0, /*find a symbol */
+ H5G_OPER_INSERT = 1, /*insert a new symbol */
+ H5G_OPER_REMOVE = 2 /*remove existing symbol */
} H5G_oper_t;
/*
@@ -125,6 +126,8 @@ herr_t H5G_stab_find (H5G_entry_t *grp_ent, const char *name,
H5G_entry_t *obj_ent/*out*/);
herr_t H5G_stab_insert (H5G_entry_t *grp_ent, const char *name,
H5G_entry_t *obj_ent);
+herr_t H5G_stab_remove(H5G_entry_t *grp_ent, const char *name);
+
/*
* Functions that understand symbol table entries.
*/
diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h
index be7113e..943dfaa 100644
--- a/src/H5Gprivate.h
+++ b/src/H5Gprivate.h
@@ -121,6 +121,7 @@ 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_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*/);
herr_t H5G_traverse_slink (H5G_entry_t *grp_ent/*in,out*/,
diff --git a/src/H5Gstab.c b/src/H5Gstab.c
index b2fa9d2..e5a5bab 100644
--- a/src/H5Gstab.c
+++ b/src/H5Gstab.c
@@ -203,10 +203,54 @@ H5G_stab_insert(H5G_entry_t *grp_ent, const char *name, H5G_entry_t *obj_ent)
/* insert */
if (H5B_insert(grp_ent->file, H5B_SNODE, &(stab.btree_addr), &udata) < 0) {
- HRETURN_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "can't insert entry");
+ HRETURN_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert entry");
}
/* update the name offset in the entry */
obj_ent->name_off = udata.ent.name_off;
FUNC_LEAVE(SUCCEED);
}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_stab_remove
+ *
+ * Purpose: Remove NAME from a symbol table.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 17, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_stab_remove(H5G_entry_t *grp_ent, const char *name)
+{
+ H5O_stab_t stab; /*symbol table message */
+ H5G_bt_ud1_t udata; /*data to pass through B-tree */
+
+ FUNC_ENTER(H5G_stab_remove, FAIL);
+ assert(grp_ent && grp_ent->file);
+ assert(name && *name);
+
+ /* initialize data to pass through B-tree */
+ if (NULL==H5O_read(grp_ent, H5O_STAB, 0, &stab)) {
+ HRETURN_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table");
+ }
+ udata.operation = H5G_OPER_REMOVE;
+ udata.name = name;
+ udata.heap_addr = stab.heap_addr;
+ HDmemset(&(udata.ent), 0, sizeof(udata.ent));
+
+ /* remove */
+ if (H5B_remove(grp_ent->file, H5B_SNODE, &(stab.btree_addr), &udata)<0) {
+ HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to remove entry");
+ }
+
+ FUNC_LEAVE(SUCCEED);
+}
diff --git a/src/H5Odtype.c b/src/H5Odtype.c
index 1653921..79bf74f 100644
--- a/src/H5Odtype.c
+++ b/src/H5Odtype.c
@@ -203,10 +203,8 @@ H5O_dtype_decode_helper(const uint8 **pp, H5T_t *dt)
"memory allocation failed");
}
H5F_addr_undef (&(dt->u.compnd.memb[i].type->ent.header));
- if (H5O_dtype_decode_helper(pp, dt->u.compnd.memb[i].type) < 0 ||
- H5T_COMPOUND == dt->u.compnd.memb[i].type->type) {
- for (j = 0; j <= i; j++)
- H5MM_xfree(dt->u.compnd.memb[i].name);
+ if (H5O_dtype_decode_helper(pp, dt->u.compnd.memb[i].type)<0) {
+ for (j=0; j<=i; j++) H5MM_xfree(dt->u.compnd.memb[j].name);
H5MM_xfree(dt->u.compnd.memb);
HRETURN_ERROR(H5E_DATATYPE, H5E_CANTDECODE, FAIL,
"can't decode member type");
diff --git a/src/H5Z.c b/src/H5Z.c
index d16ea52..68cfcc1 100644
--- a/src/H5Z.c
+++ b/src/H5Z.c
@@ -349,7 +349,7 @@ H5Z_find(H5Z_filter_t id)
for (i=0; i<H5Z_table_used_g; i++) {
if (H5Z_table_g[i].id == id) {
- return H5Z_table_g + i;
+ HRETURN(H5Z_table_g+i);
}
}
diff --git a/test/Makefile.in b/test/Makefile.in
index e98e1de..068dce9 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -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
+ tselect.h5 mtime.h5 ragged.h5 grptime.h5
CLEAN=$(TIMINGS)
# Source and object files for programs... The TEST_SRC list contains all the
@@ -35,7 +35,7 @@ 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
-TEST_OBJ=$(PROG_SRC:.c=.o)
+TEST_OBJ=$(TEST_SRC:.c=.o)
# Private header files (not to be installed)...
PRIVATE_HDR=testhdf5.h
diff --git a/tools/h5tools.c b/tools/h5tools.c
index 3994c57..d3cc110 100644
--- a/tools/h5tools.c
+++ b/tools/h5tools.c
@@ -108,14 +108,19 @@ static void
h5dump_sprint(char *s/*out*/, const h5dump_t *info, hid_t type, void *vp)
{
size_t i, n, offset, size, dims[4], nelmts;
- char temp[1024], *name;
+ unsigned overflow = 0xaaaaaaaa;
+ char temp[8192];
+ char *name, quote='\0';
hid_t memb;
int nmembs, j, k, ndims;
+ const int repeat_threshold = 8;
if (H5Tequal(type, H5T_NATIVE_DOUBLE)) {
sprintf(temp, "%g", *((double*)vp));
+
} else if (H5Tequal(type, H5T_NATIVE_FLOAT)) {
sprintf(temp, "%g", *((float*)vp));
+
} else if (H5Tequal(type, H5T_NATIVE_CHAR) ||
H5Tequal(type, H5T_NATIVE_UCHAR)) {
switch (*((char*)vp)) {
@@ -145,18 +150,93 @@ h5dump_sprint(char *s/*out*/, const h5dump_t *info, hid_t type, void *vp)
else sprintf(temp, "\\%03o", *((unsigned char*)vp));
break;
}
+
+ } else if (H5T_STRING==H5Tget_class(type)) {
+ size = H5Tget_size(type);
+ temp[0] = '\0';
+ quote = '\0';
+
+ for (i=0; i<size; i++) {
+
+ /* Count how many times the next character repeats */
+ j=1;
+ while (i+j<size && ((char*)vp)[i]==((char*)vp)[i+j]) j++;
+
+ /*
+ * Print the opening quote. If the repeat count is high enough
+ * to warrant printing the number of repeats instead of
+ * enumerating the characters, then make sure the character to be
+ * repeated is in it's own quote.
+ */
+ if (j>repeat_threshold) {
+ if (quote) sprintf(temp+strlen(temp), "%c", quote);
+ quote = '\'';
+ sprintf(temp+strlen(temp), "%s%c", i?" ":"", quote);
+ } else if (!quote) {
+ quote = '"';
+ sprintf(temp+strlen(temp), "%s%c", i?" ":"", quote);
+ }
+
+ /* Print the character */
+ switch (((char*)vp)[i]) {
+ case '"':
+ strcat(temp, "\\\"");
+ break;
+ case '\\':
+ strcat(temp, "\\\\");
+ break;
+ case '\b':
+ strcat(temp, "\\b");
+ break;
+ case '\f':
+ strcat(temp, "\\f");
+ break;
+ case '\n':
+ strcat(temp, "\\n");
+ break;
+ case '\r':
+ strcat(temp, "\\r");
+ break;
+ case '\t':
+ strcat(temp, "\\t");
+ break;
+ default:
+ if (isprint(((char*)vp)[i])) {
+ sprintf(temp+strlen(temp), "%c", ((char*)vp)[i]);
+ } else {
+ sprintf(temp+strlen(temp), "\\%03o",
+ ((unsigned char*)vp)[i]);
+ }
+ break;
+ }
+
+ /* Print the repeat count */
+ if (j>repeat_threshold) {
+ sprintf(temp+strlen(temp), "%c repeats %d times", quote, j-1);
+ quote = '\0';
+ i += j-1;
+ }
+ }
+ if (quote) sprintf(temp+strlen(temp), "%c", quote);
+
} else if (H5Tequal(type, H5T_NATIVE_SHORT)) {
sprintf(temp, "%d", *((short*)vp));
+
} else if (H5Tequal(type, H5T_NATIVE_USHORT)) {
sprintf(temp, "%u", *((unsigned short*)vp));
+
} else if (H5Tequal(type, H5T_NATIVE_INT)) {
sprintf(temp, "%d", *((int*)vp));
+
} else if (H5Tequal(type, H5T_NATIVE_UINT)) {
sprintf(temp, "%u", *((unsigned*)vp));
+
} else if (H5Tequal(type, H5T_NATIVE_LONG)) {
sprintf(temp, "%ld", *((long*)vp));
+
} else if (H5Tequal(type, H5T_NATIVE_ULONG)) {
sprintf(temp, "%lu", *((unsigned long*)vp));
+
} else if (H5Tequal(type, H5T_NATIVE_HSSIZE)) {
if (sizeof(hssize_t)==sizeof(long)) {
sprintf(temp, "%ld", *((long*)vp));
@@ -167,6 +247,7 @@ h5dump_sprint(char *s/*out*/, const h5dump_t *info, hid_t type, void *vp)
strcat(fmt, "d");
sprintf(temp, fmt, *((long long*)vp));
}
+
} else if (H5Tequal(type, H5T_NATIVE_HSIZE)) {
if (sizeof(hsize_t)==sizeof(long)) {
sprintf(temp, "%lu", *((unsigned long*)vp));
@@ -177,6 +258,7 @@ h5dump_sprint(char *s/*out*/, const h5dump_t *info, hid_t type, void *vp)
strcat(fmt, "u");
sprintf(temp, fmt, *((unsigned long long*)vp));
}
+
} else if (H5T_COMPOUND==H5Tget_class(type)) {
nmembs = H5Tget_nmembers(type);
strcpy(temp, OPT(info->cmpd_pre, "{"));
@@ -206,6 +288,7 @@ h5dump_sprint(char *s/*out*/, const h5dump_t *info, hid_t type, void *vp)
H5Tclose(memb);
}
strcat(temp, OPT(info->cmpd_suf, "}"));
+
} else {
strcpy(temp, "0x");
n = H5Tget_size(type);
@@ -215,6 +298,12 @@ h5dump_sprint(char *s/*out*/, const h5dump_t *info, hid_t type, void *vp)
}
sprintf(s, OPT(info->elmt_fmt, "%s"), temp);
+
+ /*
+ * We should really fix this so it's not possible to overflow the `temp'
+ * buffer.
+ */
+ assert(overflow==0xaaaaaaaa);
}
@@ -250,7 +339,7 @@ h5dump_simple(FILE *stream, const h5dump_t *info, hid_t dset, hid_t p_type)
hsize_t p_max_idx[8]; /*max selected index */
size_t p_type_nbytes; /*size of memory type */
hsize_t p_nelmts; /*total selected elmts */
- char p_buf[256]; /*output string */
+ char p_buf[8192]; /*output string */
size_t p_column=0; /*output column */
size_t p_ncolumns=80; /*default num columns */
char p_prefix[1024]; /*line prefix string */
@@ -444,6 +533,12 @@ h5dump_fixtype(hid_t f_type)
}
break;
+ case H5T_STRING:
+ m_type = H5Tcopy(f_type);
+ H5Tset_cset(m_type, H5T_CSET_ASCII);
+ H5Tset_strpad(m_type, H5T_STR_NULLPAD);
+ break;
+
case H5T_COMPOUND:
/*
* We have to do this in two steps. The first step scans the file
@@ -494,7 +589,6 @@ h5dump_fixtype(hid_t f_type)
break;
case H5T_TIME:
- case H5T_STRING:
case H5T_BITFIELD:
case H5T_OPAQUE:
/*