diff options
-rw-r--r-- | config/conclude.in | 2 | ||||
-rw-r--r-- | config/hpux9.03 | 38 | ||||
-rw-r--r-- | src/H5B.c | 291 | ||||
-rw-r--r-- | src/H5Bprivate.h | 131 | ||||
-rw-r--r-- | src/H5Distore.c | 153 | ||||
-rw-r--r-- | src/H5Fistore.c | 153 | ||||
-rw-r--r-- | src/H5Fprivate.h | 4 | ||||
-rw-r--r-- | src/H5Fsplit.c | 4 | ||||
-rw-r--r-- | src/H5G.c | 121 | ||||
-rw-r--r-- | src/H5Gnode.c | 1 | ||||
-rw-r--r-- | src/H5Gpkg.h | 7 | ||||
-rw-r--r-- | src/H5Gprivate.h | 1 | ||||
-rw-r--r-- | src/H5Gstab.c | 46 | ||||
-rw-r--r-- | src/H5Odtype.c | 6 | ||||
-rw-r--r-- | src/H5Z.c | 2 | ||||
-rw-r--r-- | test/Makefile.in | 4 | ||||
-rw-r--r-- | tools/h5tools.c | 100 |
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'} @@ -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, <_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; } @@ -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"); @@ -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: /* |