From 25d866e9b433142c38fa6c4c8d3cad5e00d46163 Mon Sep 17 00:00:00 2001 From: Robb Matzke Date: Fri, 19 Sep 1997 11:36:59 -0500 Subject: [svn-r100] Interim checkin for purify. Also contains H5G shadow stuff, changes to int64 encode/decode to fix purify on 32-bit systems, changes to H5O_modify, changes to H5D.c to use H5F_open/close(), etc. Documentation will be mailed shortly... --- src/H5AC.c | 20 +-- src/H5ACprivate.h | 6 +- src/H5B.c | 40 +++-- src/H5Bprivate.h | 8 +- src/H5D.c | 188 +++++++++++----------- src/H5Dprivate.h | 15 -- src/H5E.c | 4 +- src/H5Epublic.h | 6 +- src/H5F.c | 5 +- src/H5Fprivate.h | 84 +++++++--- src/H5G.c | 462 +++++++++++++++++++++++++++--------------------------- src/H5Gnode.c | 264 +++++++++++++++++++++++-------- src/H5Gpkg.h | 158 +++++++++++++++++++ src/H5Gprivate.h | 150 ++++++------------ src/H5Gshad.c | 460 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/H5H.c | 49 +++--- src/H5MM.c | 12 +- src/H5O.c | 79 ++++++---- src/H5Ocont.c | 1 + src/H5Oname.c | 1 + src/H5Onull.c | 1 + src/H5Oprivate.h | 7 +- src/H5Osdim.c | 1 + src/H5Osdtyp.c | 9 +- src/H5Ostab.c | 1 + src/H5Ostdst.c | 1 + src/H5private.h | 9 +- src/Makefile.in | 5 +- test/Makefile.in | 2 +- test/th5d.c | 2 +- test/tohdr.c | 21 +-- test/tstab.c | 3 +- 32 files changed, 1433 insertions(+), 641 deletions(-) create mode 100644 src/H5Gpkg.h create mode 100644 src/H5Gshad.c diff --git a/src/H5AC.c b/src/H5AC.c index 478923c..9dc49ed 100644 --- a/src/H5AC.c +++ b/src/H5AC.c @@ -173,7 +173,7 @@ H5AC_dest (hdf5_file_t *f) */ void * H5AC_find_f (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, - const void *udata) + void *udata) { unsigned idx; herr_t status; @@ -298,9 +298,11 @@ H5AC_compare (const void *_a, const void *_b) * Function: H5AC_flush * * Purpose: Flushes (and destroys if DESTROY is non-zero) the specified - * entry from the cache. If the entry type is CACHE_FREE then - * all types of entries are flushed. If the ADDR is zero then - * all entries of the specified type are flushed. + * entry from the cache. If the entry TYPE is CACHE_FREE and + * ADDR is zero then all types of entries are flushed. If TYPE + * is CACHE_FREE and ADDR is non-zero, then whatever is cached + * at ADDR is flushed. Otherwise the thing at ADDR is flushed + * if it is the correct type. * * If there are protected objects they will not be flushed. * However, an attempt will be made to flush all non-protected @@ -334,7 +336,7 @@ H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, assert (f->cache); i = H5AC_HASH (f, addr); - if (!type || 0==addr) { + if (0==addr) { #ifdef SORT_BY_ADDR /* @@ -360,8 +362,7 @@ H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, slot = f->cache->slot + i; if (NULL==slot->type) continue; #endif - if ((!type || type==slot->type) && - (0==addr || addr==slot->addr)) { + if (!type || type==slot->type) { flush = slot->type->flush; status = (flush)(f, destroy, slot->addr, slot->thing); if (status<0) { @@ -373,7 +374,8 @@ H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, } map = H5MM_xfree (map); - } else if (f->cache->slot[i].type==type && f->cache->slot[i].addr==addr) { + } else if ((!type || f->cache->slot[i].type==type) && + f->cache->slot[i].addr==addr) { /* * Flush just this entry. */ @@ -583,7 +585,7 @@ H5AC_rename (hdf5_file_t *f, const H5AC_class_t *type, */ void * H5AC_protect (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, - const void *udata) + void *udata) { int idx; void *thing = NULL; diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h index ee002f4..83a1b38 100644 --- a/src/H5ACprivate.h +++ b/src/H5ACprivate.h @@ -39,7 +39,7 @@ * by the LOAD method if the DEST argument is non-zero. */ typedef struct H5AC_class_t { - void *(*load)(hdf5_file_t*, haddr_t addr, const void *udata); + void *(*load)(hdf5_file_t*, haddr_t addr, void *udata); herr_t (*flush)(hdf5_file_t*, hbool_t dest, haddr_t addr, void *thing); } H5AC_class_t; @@ -79,9 +79,9 @@ typedef struct H5AC_t { */ herr_t H5AC_dest (hdf5_file_t *f); void *H5AC_find_f (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, - const void *udata); + void *udata); void * H5AC_protect (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, - const void *udata); + void *udata); herr_t H5AC_unprotect (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, void *thing); herr_t H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, diff --git a/src/H5B.c b/src/H5B.c index c6249eb..8fe6790 100644 --- a/src/H5B.c +++ b/src/H5B.c @@ -100,7 +100,7 @@ /* PRIVATE PROTOTYPES */ static haddr_t H5B_insert_helper (hdf5_file_t *f, haddr_t addr, - const H5B_class_t *type, + H5B_class_t *type, uint8 *lt_key, hbool_t *lt_key_changed, uint8 *md_key, void *udata, uint8 *rt_key, hbool_t *rt_key_changed); @@ -109,14 +109,14 @@ static herr_t H5B_insert_child (hdf5_file_t *f, const H5B_class_t *type, intn anchor, void *md_key); static herr_t H5B_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5B_t *b); -static H5B_t *H5B_load (hdf5_file_t *f, haddr_t addr, const void *_data); +static H5B_t *H5B_load (hdf5_file_t *f, haddr_t addr, void *_data); static herr_t H5B_decode_key (hdf5_file_t *f, H5B_t *bt, intn idx); static size_t H5B_nodesize (hdf5_file_t *f, const H5B_class_t *type, size_t *total_nkey_size, size_t sizeof_rkey); /* H5B inherits cache-like properties from H5AC */ static const H5AC_class_t H5AC_BT[1] = {{ - (void*(*)(hdf5_file_t*,haddr_t,const void*))H5B_load, + (void*(*)(hdf5_file_t*,haddr_t,void*))H5B_load, (herr_t(*)(hdf5_file_t*,hbool_t,haddr_t,void*))H5B_flush, }}; @@ -231,13 +231,14 @@ H5B_new (hdf5_file_t *f, const H5B_class_t *type) *------------------------------------------------------------------------- */ static H5B_t * -H5B_load (hdf5_file_t *f, haddr_t addr, const void *_data) +H5B_load (hdf5_file_t *f, haddr_t addr, void *_data) { - const H5B_class_t *type = (const H5B_class_t *)_data; + const H5B_class_t *type = (H5B_class_t *)_data; size_t size, total_nkey_size; H5B_t *bt = NULL; intn i; uint8 *p; + H5B_t *ret_value = NULL; FUNC_ENTER (H5B_load, NULL, NULL); @@ -263,11 +264,15 @@ H5B_load (hdf5_file_t *f, haddr_t addr, const void *_data) p = bt->page; /* magic number */ - if (HDmemcmp (p, H5B_MAGIC, H5B_SIZEOF_MAGIC)) goto error; + if (HDmemcmp (p, H5B_MAGIC, H5B_SIZEOF_MAGIC)) { + HGOTO_ERROR (H5E_BTREE, H5E_CANTLOAD, NULL); + } p += 4; /* node type and level */ - if (*p++ != type->id) goto error; + if (*p++ != type->id) { + HGOTO_ERROR (H5E_BTREE, H5E_CANTLOAD, NULL); + } bt->level = *p++; /* entries used */ @@ -296,17 +301,18 @@ H5B_load (hdf5_file_t *f, haddr_t addr, const void *_data) bt->key[2*H5B_K(f,type)].dirty = FALSE; bt->key[2*H5B_K(f,type)].rkey = p; bt->key[2*H5B_K(f,type)].nkey = NULL; - FUNC_LEAVE (bt); + ret_value = bt; -error: - if (bt) { + done: + if (!ret_value && bt) { H5MM_xfree (bt->child); H5MM_xfree (bt->key); H5MM_xfree (bt->page); H5MM_xfree (bt->native); H5MM_xfree (bt); } - HRETURN_ERROR (H5E_BTREE, H5E_CANTLOAD, NULL); + + FUNC_LEAVE (ret_value); } @@ -438,7 +444,7 @@ H5B_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5B_t *bt) *------------------------------------------------------------------------- */ herr_t -H5B_find (hdf5_file_t *f, const H5B_class_t *type, haddr_t addr, void *udata) +H5B_find (hdf5_file_t *f, H5B_class_t *type, haddr_t addr, void *udata) { H5B_t *bt=NULL; intn idx=-1, lt=0, rt, cmp=1; @@ -538,7 +544,7 @@ done: *------------------------------------------------------------------------- */ static haddr_t -H5B_split (hdf5_file_t *f, const H5B_class_t *type, H5B_t *old_bt, +H5B_split (hdf5_file_t *f, H5B_class_t *type, H5B_t *old_bt, haddr_t old_addr, intn anchor) { H5B_t *new_bt=NULL, *tmp_bt=NULL; @@ -727,7 +733,7 @@ H5B_decode_key (hdf5_file_t *f, H5B_t *bt, intn idx) *------------------------------------------------------------------------- */ haddr_t -H5B_insert (hdf5_file_t *f, const H5B_class_t *type, haddr_t addr, void *udata) +H5B_insert (hdf5_file_t *f, H5B_class_t *type, haddr_t addr, void *udata) { uint8 lt_key[256], md_key[256], rt_key[256]; hbool_t lt_key_changed=FALSE, rt_key_changed=FALSE; @@ -980,7 +986,7 @@ H5B_insert_child (hdf5_file_t *f, const H5B_class_t *type, H5B_t *bt, *------------------------------------------------------------------------- */ static haddr_t -H5B_insert_helper (hdf5_file_t *f, haddr_t addr, const H5B_class_t *type, +H5B_insert_helper (hdf5_file_t *f, haddr_t addr, H5B_class_t *type, uint8 *lt_key, hbool_t *lt_key_changed, uint8 *md_key, void *udata, uint8 *rt_key, hbool_t *rt_key_changed) @@ -1219,7 +1225,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5B_list (hdf5_file_t *f, const H5B_class_t *type, haddr_t addr, void *udata) +H5B_list (hdf5_file_t *f, H5B_class_t *type, haddr_t addr, void *udata) { H5B_t *bt=NULL; haddr_t next_addr; @@ -1352,7 +1358,7 @@ H5B_nodesize (hdf5_file_t *f, const H5B_class_t *type, */ herr_t H5B_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, - intn fwidth, const H5B_class_t *type) + intn fwidth, H5B_class_t *type) { H5B_t *bt = NULL; int i; diff --git a/src/H5Bprivate.h b/src/H5Bprivate.h index 457c8af..f7c3e50 100644 --- a/src/H5Bprivate.h +++ b/src/H5Bprivate.h @@ -91,13 +91,13 @@ typedef struct H5B_t { * Library prototypes. */ herr_t H5B_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, - intn fwidth, const H5B_class_t *type); + intn fwidth, H5B_class_t *type); haddr_t H5B_new (hdf5_file_t *f, const H5B_class_t *type); -herr_t H5B_find (hdf5_file_t *f, const H5B_class_t *type, haddr_t addr, +herr_t H5B_find (hdf5_file_t *f, H5B_class_t *type, haddr_t addr, void *udata); -haddr_t H5B_insert (hdf5_file_t *f, const H5B_class_t *type, haddr_t addr, +haddr_t H5B_insert (hdf5_file_t *f, H5B_class_t *type, haddr_t addr, void *udata); -herr_t H5B_list (hdf5_file_t *f, const H5B_class_t *type, haddr_t addr, +herr_t H5B_list (hdf5_file_t *f, H5B_class_t *type, haddr_t addr, void *udata); diff --git a/src/H5D.c b/src/H5D.c index 8ab6b19..d3c1a5d 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -45,6 +45,18 @@ static char RcsId[] = "@(#)$Revision$"; #define PABLO_MASK H5D_mask +/* + * A dataset is the following struct. + */ +typedef struct H5D_t { + hdf5_file_t *file; /* File store for this object */ + H5G_entry_t *ent; /* Cached object header stuff */ + h5_datatype_t *type; /* Datatype of this dataset */ + H5P_dim_t *dim; /* Dimensionality of this dataset */ + haddr_t data_addr; /* Data storage address */ + hbool_t dirty; /* Header messages not updated yet */ +} H5D_t; + /*--------------------- Locally scoped variables -----------------------------*/ /* Whether we've installed the library termination function yet for this interface */ @@ -110,15 +122,16 @@ void H5D_term_interface (void) RETURNS Returns ID (atom) on success, FAIL on failure DESCRIPTION - This function actually creates the dataset object, but it cannot be - accessed by name until it is stored in the file. + This function actually creates a dataset object in a file (of course, + output might not happen for some time). --------------------------------------------------------------------------*/ hatom_t H5D_create(hatom_t owner_id, hobjtype_t type, const char *name) { H5D_t *new_dset; /* new dataset object to create */ hatom_t ret_value = SUCCEED; - hdf5_file_t *file = NULL; - + hdf5_file_t *file = NULL; + H5G_entry_t tmp_ent; + FUNC_ENTER(H5D_create, H5D_init_interface, FAIL); /* Clear errors and check args and all the boring stuff. */ @@ -135,14 +148,37 @@ hatom_t H5D_create(hatom_t owner_id, hobjtype_t type, const char *name) /* Initialize the dataset object */ new_dset->file = file; - new_dset->name = H5MM_xstrdup (name); - new_dset->cwd = file->root_sym; - new_dset->ent.header = -1; /* Not on disk yet */ - new_dset->ent.type = H5G_NOTHING_CACHED; new_dset->type=NULL; /* No type yet */ new_dset->dim=NULL; /* No dimensions yet */ new_dset->data_addr = -1; /* No data yet */ - new_dset->modified=BTRUE; /* Yep, we're new */ + new_dset->dirty = FALSE; /* There are no messages yet */ + + /* Create the (empty) object header in the file */ + memset (&tmp_ent, 0, sizeof(tmp_ent)); + if ((tmp_ent.header = H5O_new (file, 0, H5D_MINHDR_SIZE))<0) { + HGOTO_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't create header*/ + } + + /* + * Link the (empty) object header into the symbol table so others can + * access it. At least that way no one will try to create another one of + * these things with the same name. We also hold the object open while + * H5D has a handle, preventing others from moving or deleting it from + * under us. + */ +#ifdef LATER + /* We should use the real CWD instead of always the root object! */ +#else + H5G_shadow_sync (file->root_sym); + if (H5G_insert (file, file->root_sym, NULL, name, &tmp_ent)<0) { + /* Something by that name already exists, or some other failure */ + HGOTO_ERROR (H5E_SYM, H5E_EXISTS, FAIL); + } + if (NULL==(new_dset->ent = H5G_open (file, file->root_sym, name))) { + /* Can't open the header we just created -- should never happen */ + HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); + } +#endif /* Register the new datatype and get an ID for it */ if((ret_value=H5Aregister_atom(H5_DATASET, (const VOIDP)new_dset))<0) @@ -197,39 +233,44 @@ hatom_t H5D_find_name(hatom_t grp_id, hobjtype_t type, const char *name) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL); /* Initialize file, directory, name fields */ - dset->modified = FALSE; dset->file = file; - dset->name = H5MM_xstrdup (name); -/* WARNING! WARNING! WARNING! */ -/* The following line explicitly uses the root symbol as the - current working directory. This should be changed to something more - appropriate and is only hacked in here to get the prototype working. -QAK -*/ -/* WARNING! WARNING! WARNING! */ - dset->cwd = file->root_sym; - - /* Get the dataset's symbol table entry */ - if (H5G_find (dset->file, dset->cwd, NULL, dset->name, &(dset->ent))<0) - HGOTO_ERROR(H5E_DATASET, H5E_NOTFOUND, FAIL); + dset->dirty = FALSE; + +#ifdef LATER + /* We should really use the real CWD instead of the root object! */ +#else + /* + * WARNING! WARNING! WARNING! + * The following line explicitly uses the root symbol as the current + * working directory. This should be changed to something more + * appropriate and is only hacked in here to get the prototype working. + * -QAK + * WARNING! WARNING! WARNING! + */ + H5G_shadow_sync (file->root_sym); + if (NULL==(dset->ent=H5G_open (file, file->root_sym, name))) { + HGOTO_ERROR (H5E_DATASET, H5E_NOTFOUND, FAIL); + } +#endif /* Get the dataset's type (currently only atomic types) */ if((dset->type=HDcalloc(1,sizeof(h5_datatype_t)))==NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL); - if (NULL==H5O_read (dset->file, dset->ent.header, &(dset->ent), - H5O_SIM_DTYPE, 0, dset->type)) + if (NULL==H5O_read (dset->file, NO_ADDR, dset->ent, H5O_SIM_DTYPE, 0, + dset->type)) HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL); /* Get the dataset's dimensionality (currently only simple dataspaces) */ if((dset->dim=HDcalloc(1,sizeof(H5P_dim_t)))==NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL); dset->dim->type=H5P_TYPE_SIMPLE; /* for now... */ - if (NULL==(dset->dim->s=H5O_read (dset->file, dset->ent.header, - &(dset->ent), H5O_SIM_DIM, 0, NULL))) + if (NULL==(dset->dim->s=H5O_read (dset->file, NO_ADDR, dset->ent, + H5O_SIM_DIM, 0, NULL))) HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL); /* Get the dataset's data offset (currently only standard storage) */ - if (NULL==H5O_read (dset->file, dset->ent.header ,&(dset->ent), - H5O_STD_STORE, 0, &store)) + if (NULL==H5O_read (dset->file, NO_ADDR, dset->ent, H5O_STD_STORE, 0, + &store)) HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL); dset->data_addr=store.off; @@ -241,7 +282,6 @@ done: if(ret_value == FAIL) { /* Error condition cleanup */ if (dset) { - dset->name = H5MM_xfree (dset->name); #ifdef LATER /* We might need to free the `type' and `dim' fields also... */ #endif @@ -290,9 +330,10 @@ herr_t H5Dset_info(hatom_t oid, hatom_t tid, hatom_t did) if(dataset->type || dataset->dim) HGOTO_ERROR(H5E_FUNC, H5E_ALREADYINIT, FAIL); + /* Update the dataset in memory */ dataset->type=H5Aatom_object(tid); dataset->dim=H5Aatom_object(did); - dataset->modified=BTRUE; /* indicate the values have changed */ + dataset->dirty = TRUE; done: if(ret_value == FAIL) @@ -499,7 +540,7 @@ herr_t H5Dwrite(hatom_t oid, hatom_t did, VOIDP buf) if(dataset->data_addr<0) { if((dataset->data_addr=H5MF_alloc(dataset->file,towrite))<0) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL); - dataset->modified = TRUE; + dataset->dirty = TRUE; } /* Check memory to disk datatype conversions, etc. */ @@ -551,9 +592,6 @@ herr_t H5D_flush(hatom_t oid) { H5D_t *dataset; /* dataset object to release */ herr_t ret_value = SUCCEED; - intn mesg_sequence = 0; /*message sequence number */ - hbool_t new_dataset; /*is this a new dataset on disk?*/ - hbool_t entry_changed = FALSE; /*did symbol table entry change?*/ FUNC_ENTER(H5D_flush, H5D_init_interface, FAIL); @@ -564,37 +602,15 @@ herr_t H5D_flush(hatom_t oid) if((dataset=H5Aatom_object(oid))==NULL) HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL); - if (dataset->modified) { - /* - * A new dataset is one which doesn't exist on disk yet. - */ - new_dataset = (dataset->ent.header < 0); - - - /* - * If the dataset is new then create an object header for it. Set the - * message sequence numbers to H5O_NEW_MESSAGE so we create new - * messages instead of trying to modify existing messages. - */ - if (new_dataset) { - dataset->ent.type = H5G_NOTHING_CACHED; - if ((dataset->ent.header = H5O_new (dataset->file, 0, - H5D_MINHDR_SIZE))<0) { - /* Can't create header. */ - HGOTO_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); - } - mesg_sequence = H5O_NEW_MESG; - } - + if (dataset->dirty) { /* - * Create or update messages for this dataset. Begin with the + * Modify/create messages for this dataset. Begin with the * type information. */ if (H5T_is_atomic (dataset->type)) { - if (H5O_modify (dataset->file, dataset->ent.header, - &(dataset->ent), &entry_changed, H5O_SIM_DTYPE, - mesg_sequence, dataset->type)<0) { + if (H5O_modify (dataset->file, NO_ADDR, dataset->ent, + H5O_SIM_DTYPE, 0, dataset->type)<0) { /* Can't create/update type message */ HGOTO_ERROR (H5E_INTERNAL, H5E_CANTCREATE, FAIL); } @@ -604,12 +620,11 @@ herr_t H5D_flush(hatom_t oid) } /* - * Write the dimensionality information. + * Modify/create the dimensionality information. */ if (H5P_is_simple (dataset->dim)) { - if (H5O_modify (dataset->file, dataset->ent.header, - &(dataset->ent), &entry_changed, H5O_SIM_DIM, - mesg_sequence, dataset->dim->s)<0) { + if (H5O_modify (dataset->file, NO_ADDR, dataset->ent, + H5O_SIM_DIM, 0, dataset->dim->s)<0) { /* Can't create/update dimensionality message */ HGOTO_ERROR (H5E_INTERNAL, H5E_CANTCREATE, FAIL); } @@ -619,7 +634,7 @@ herr_t H5D_flush(hatom_t oid) } /* - * Write the dataset's storage information. + * Modify/create the dataset's storage information. */ if (dataset->data_addr>=0) { H5O_std_store_t store; /* standard storage info */ @@ -627,41 +642,21 @@ herr_t H5D_flush(hatom_t oid) store.len = H5T_size (dataset->type, BTRUE) * H5P_nelem (dataset->dim); store.off = dataset->data_addr; - if (H5O_modify (dataset->file, dataset->ent.header, - &(dataset->ent), &entry_changed, H5O_STD_STORE, - mesg_sequence, &store)<0) { + if (H5O_modify (dataset->file, NO_ADDR, dataset->ent, + H5O_STD_STORE, 0, &store)<0) { /* Can't create/modify storage information */ HGOTO_ERROR (H5E_INTERNAL, H5E_CANTCREATE, FAIL); } } - /* - * If this is a new dataset then we must give it a name so others can - * access it. - */ - if (new_dataset) { - assert (dataset->name); - if (H5G_insert (dataset->file, dataset->cwd, NULL, - dataset->name, &(dataset->ent))<0) { - /* Can't name dataset */ - HGOTO_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); - } - } else if (entry_changed) { - if (H5G_modify (dataset->file, dataset->cwd, NULL, - dataset->name, &(dataset->ent))<0) { - /* Can't update symbol table entry */ - HGOTO_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); - } - } - -#ifdef ROBB - /* Flush dataset header to disk */ - if (H5O_flush (dataset->file, FALSE, dataset->ent.header, NULL)<0) { +#if 1 + /* Flush dataset header to disk -- just for debugging */ + if (H5AC_flush (dataset->file, NULL, dataset->ent->header, FALSE)<0) { HRETURN_ERROR (H5E_OHDR, H5E_CANTFLUSH, FAIL); } -#endif /* ROBB */ - - dataset->modified = FALSE; /*it's clean now*/ +#endif + + dataset->dirty = FALSE; /*it's clean now*/ } done: @@ -703,13 +698,16 @@ herr_t H5D_release(hatom_t oid) HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL); /* Check if we have information to flush to the file... */ - if(dataset->modified && H5D_flush(oid)<0) { + if(dataset->dirty && H5D_flush(oid)<0) { /* Can't flush dataset */ HGOTO_ERROR (H5E_OHDR, H5E_CANTFLUSH, FAIL); } + + /* Close the dataset object */ + H5G_close (dataset->file, dataset->ent); + dataset->ent = NULL; /* release the memory used for the dataset */ - dataset->name = H5MM_xfree (dataset->name); H5MM_xfree (dataset); /* Delete the dataset from the atom group */ diff --git a/src/H5Dprivate.h b/src/H5Dprivate.h index f0a08a2..149de5e 100644 --- a/src/H5Dprivate.h +++ b/src/H5Dprivate.h @@ -28,21 +28,6 @@ #include /* for the H5P_sdim_t type */ #include /* Object Headers */ -/* - * A dataset is the following struct. It can exist in memory without - * existing in a file. - */ -typedef struct H5D_t { - hdf5_file_t *file; /* File store for this object */ - char *name; /* Name of dataset, relative or absolute */ - H5G_entry_t *cwd; /* Directory for relative name lookup */ - H5G_entry_t ent; /* Cached object header stuff */ - h5_datatype_t *type; /* Datatype of this dataset */ - H5P_dim_t *dim; /* Dimensionality of this dataset */ - haddr_t data_addr; /* Data storage address */ - hbool_t modified; /* Is memory out of data wrt file? */ -} H5D_t; - #define H5D_RESERVED_ATOMS 0 /* Set the minimum object header size to create objects with */ diff --git a/src/H5E.c b/src/H5E.c index 2a586e1..137a970 100644 --- a/src/H5E.c +++ b/src/H5E.c @@ -77,7 +77,8 @@ static const hdf_min_error_messages_t hdf_min_error_messages[] = {H5E_FILEEXISTS, "File already exists"}, {H5E_FILEOPEN, "File already open"}, {H5E_CANTCREATE, "Can't create file"}, - {H5E_CANTOPEN, "Can't open file"}, + {H5E_CANTOPENFILE, "Can't open file"}, + {H5E_CANTOPENOBJ, "Can't open object"}, {H5E_NOTHDF5, "Not an HDF5 format file"}, {H5E_BADFILE, "Bad file ID accessed"}, {H5E_SEEKERROR, "Seek failed"}, @@ -90,6 +91,7 @@ static const hdf_min_error_messages_t hdf_min_error_messages[] = {H5E_CANTFLUSH, "Can't flush object from cache"}, {H5E_CANTLOAD, "Can't load object into cache"}, {H5E_PROTECT, "Protected object error"}, + {H5E_NOTCACHED, "Object not currently cached"}, {H5E_NOTFOUND, "Object not found"}, {H5E_EXISTS, "Object already exists"}, {H5E_CANTENCODE, "Can't encode value"}, diff --git a/src/H5Epublic.h b/src/H5Epublic.h index 101ad76..bde74e5 100644 --- a/src/H5Epublic.h +++ b/src/H5Epublic.h @@ -64,7 +64,7 @@ typedef enum H5E_FILEEXISTS, /* File already exists */ H5E_FILEOPEN, /* File already open */ H5E_CANTCREATE, /* Can't create file */ - H5E_CANTOPEN, /* Can't open file */ + H5E_CANTOPENFILE, /* Can't open file */ H5E_NOTHDF5, /* Not an HDF5 format file */ H5E_BADFILE, /* Bad file ID accessed */ @@ -85,7 +85,8 @@ typedef enum H5E_CANTFLUSH, /* Can't flush object from cache */ H5E_CANTLOAD, /* Can't load object into cache */ H5E_PROTECT, /* Protected object error */ - + H5E_NOTCACHED, /* Object not currently cached */ + /* B-tree related errors */ H5E_NOTFOUND, /* Object not found */ H5E_EXISTS, /* Object already exists */ @@ -102,6 +103,7 @@ typedef enum H5E_BADMESG, /* Unrecognized message */ /* Directory related errors */ + H5E_CANTOPENOBJ, /* Can't open object */ H5E_COMPLEN, /* Name component is too long */ H5E_LINK /* Link count failure */ } diff --git a/src/H5F.c b/src/H5F.c index 348e477..6d1aec0 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -399,8 +399,7 @@ H5F_new (void) H5AC_new (f, H5AC_NSLOTS); /* Create a root symbol slot */ - f->root_sym = H5MM_xcalloc (1, sizeof (H5G_entry_t)); - f->root_sym->type = H5G_NOTHING_CACHED; + f->root_sym = H5G_new_entry (); return f; } @@ -688,7 +687,7 @@ hatom_t H5Fopen(const char *filename, uintn flags, hatom_t access_temp) /* Check if the file already exists */ f_handle=H5F_OPEN(filename,flags); if(H5F_OPENERR(f_handle)) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPEN, FAIL);/*file doesn't exist*/ + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL);/*file doesn't exist*/ /* Create the file node */ if (NULL==(new_file=H5F_new())) diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index 275cb1d..f1c7b59 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -185,10 +185,22 @@ typedef MPFILE *hdf_file_t; *(p) = (uint8)(((uint64)(i) >> 8) & 0xff); (p)++; \ *(p) = (uint8)(((uint64)(i) >> 16) & 0xff); (p)++; \ *(p) = (uint8)(((uint64)(i) >> 24) & 0xff); (p)++; \ - *(p) = (uint8)(((uint64)(i) >> 32) & 0xff); (p)++; \ - *(p) = (uint8)(((uint64)(i) >> 40) & 0xff); (p)++; \ - *(p) = (uint8)(((uint64)(i) >> 48) & 0xff); (p)++; \ - *(p) = (uint8)(((uint64)(i) >> 56) & 0xff); (p)++; \ + if (sizeof(int64)>4) { \ + *(p) = (uint8)(((uint64)(i) >> 32) & 0xff); (p)++; \ + *(p) = (uint8)(((uint64)(i) >> 40) & 0xff); (p)++; \ + *(p) = (uint8)(((uint64)(i) >> 48) & 0xff); (p)++; \ + *(p) = (uint8)(((uint64)(i) >> 56) & 0xff); (p)++; \ + } else if ((i)<0) { \ + *(p)++ = 0xff; \ + *(p)++ = 0xff; \ + *(p)++ = 0xff; \ + *(p)++ = 0xff; \ + } else { \ + *(p)++ = 0x00; \ + *(p)++ = 0x00; \ + *(p)++ = 0x00; \ + *(p)++ = 0x00; \ + } \ } # define UINT64ENCODE(p, i) { \ @@ -196,10 +208,17 @@ typedef MPFILE *hdf_file_t; *(p) = (uint8)(((i) >> 8) & 0xff); (p)++; \ *(p) = (uint8)(((i) >> 16) & 0xff); (p)++; \ *(p) = (uint8)(((i) >> 24) & 0xff); (p)++; \ - *(p) = (uint8)(((i) >> 32) & 0xff); (p)++; \ - *(p) = (uint8)(((i) >> 40) & 0xff); (p)++; \ - *(p) = (uint8)(((i) >> 48) & 0xff); (p)++; \ - *(p) = (uint8)(((i) >> 56) & 0xff); (p)++; \ + if (sizeof(uint64)>4) { \ + *(p) = (uint8)(((i) >> 32) & 0xff); (p)++; \ + *(p) = (uint8)(((i) >> 40) & 0xff); (p)++; \ + *(p) = (uint8)(((i) >> 48) & 0xff); (p)++; \ + *(p) = (uint8)(((i) >> 56) & 0xff); (p)++; \ + } else { \ + *(p)++ = 0x00; \ + *(p)++ = 0x00; \ + *(p)++ = 0x00; \ + *(p)++ = 0x00; \ + } \ } # define INT16DECODE(p, i) { \ @@ -231,10 +250,14 @@ typedef MPFILE *hdf_file_t; (i) |= ((int64)(*(p) & 0xff) << 8); (p)++; \ (i) |= ((int64)(*(p) & 0xff) << 16); (p)++; \ (i) |= ((int64)(*(p) & 0xff) << 24); (p)++; \ - (i) |= ((int64)(*(p) & 0xff) << 32); (p)++; \ - (i) |= ((int64)(*(p) & 0xff) << 40); (p)++; \ - (i) |= ((int64)(*(p) & 0xff) << 48); (p)++; \ - (i) |= ((int64)(*(p) & 0xff) << 56); (p)++; \ + if (sizeof(int64)>4) { \ + (i) |= ((int64)(*(p) & 0xff) << 32); (p)++; \ + (i) |= ((int64)(*(p) & 0xff) << 40); (p)++; \ + (i) |= ((int64)(*(p) & 0xff) << 48); (p)++; \ + (i) |= ((int64)(*(p) & 0xff) << 56); (p)++; \ + } else { \ + (p) += 4; \ + } \ } # define UINT64DECODE(p, i) { \ @@ -242,10 +265,14 @@ typedef MPFILE *hdf_file_t; (i) |= ((uint64)(*(p) & 0xff) << 8); (p)++; \ (i) |= ((uint64)(*(p) & 0xff) << 16); (p)++; \ (i) |= ((uint64)(*(p) & 0xff) << 24); (p)++; \ - (i) |= ((uint64)(*(p) & 0xff) << 32); (p)++; \ - (i) |= ((uint64)(*(p) & 0xff) << 40); (p)++; \ - (i) |= ((uint64)(*(p) & 0xff) << 48); (p)++; \ - (i) |= ((uint64)(*(p) & 0xff) << 56); (p)++; \ + if (sizeof(uint64)>4) { \ + (i) |= ((uint64)(*(p) & 0xff) << 32); (p)++; \ + (i) |= ((uint64)(*(p) & 0xff) << 40); (p)++; \ + (i) |= ((uint64)(*(p) & 0xff) << 48); (p)++; \ + (i) |= ((uint64)(*(p) & 0xff) << 56); (p)++; \ + } else { \ + (p) += 4; \ + } \ } #else @@ -254,8 +281,29 @@ typedef MPFILE *hdf_file_t; # define UINT16ENCODE(p, i) { *((uint16 *)(p)) = (uint16)(i); (p)+=2; } # define INT32ENCODE(p, i) { *((int32 *)(p)) = (int32)(i); (p)+=4; } # define UINT32ENCODE(p, i) { *((uint32 *)(p)) = (uint32)(i); (p)+=4; } -# define INT64ENCODE(p, i) { *((int64 *)(p)) = (int64)(i); (p)+=8; } -# define UINT64ENCODE(p, i) { *((uint64 *)(p)) = (uint64)(i); (p)+=8; } + +# define INT64ENCODE(p, i) { \ + *((int64 *)(p)) = (int64)(i); \ + (p) += sizeof(int64); \ + if (4==sizeof(int64)) { \ + *(p)++ = (i)<0?0xff:0x00; \ + *(p)++ = (i)<0?0xff:0x00; \ + *(p)++ = (i)<0?0xff:0x00; \ + *(p)++ = (i)<0?0xff:0x00; \ + } \ +} + +# define UINT64ENCODE(p, i) { \ + *((uint64 *)(p)) = (uint64)(i); \ + (p) += sizeof(uint64); \ + if (4==sizeof(uint64)) { \ + *(p)++ = 0x00; \ + *(p)++ = 0x00; \ + *(p)++ = 0x00; \ + *(p)++ = 0x00; \ + } \ +} + # define INT16DECODE(p, i) { (i) = (int16)(*(const int16 *)(p)); (p)+=2; } # define UINT16DECODE(p, i) { (i) = (uint16)(*(const uint16 *)(p)); (p)+=2; } # define INT32DECODE(p, i) { (i) = (int32)(*(const int32 *)(p)); (p)+=4; } diff --git a/src/H5G.c b/src/H5G.c index ea2ae3e..88c8576 100644 --- a/src/H5G.c +++ b/src/H5G.c @@ -28,25 +28,29 @@ * Robb Matzke, 30 Aug 1997 * Added `Errors:' field to function prologues. * + * Robb Matzke, 18 Sep 1997 + * Added shadow entry support. + * *------------------------------------------------------------------------- */ +#define H5G_PACKAGE /*suppress error message about including H5Gpkg.h*/ /* Packages needed by this file... */ #include #include #include -#include +#include #include #include #include #define H5G_INIT_HEAP 8192 -#define PABLO_MASK H5G_mask +#define PABLO_MASK H5G_mask static herr_t H5G_mkroot (hdf5_file_t *f, size_t size_hint); /* Is the interface initialized? */ -static intn interface_initialize_g = FALSE; +static hbool_t interface_initialize_g = FALSE; /*------------------------------------------------------------------------- @@ -155,37 +159,35 @@ H5G_basename (const char *name, size_t *size_p) * * If the name cannot be fully resolved, then REST will * point to the part of NAME where the traversal failed - * (REST will always point to a relative name) and BASE_ENT - * will not be initialized. DIR_ENT will be initialized with + * (REST will always point to a relative name) and this + * function will return null. DIR_ENT will be initialized with * information about the directory (or other object) at which * the traversal failed. However, if the name can be fully * resolved, then REST points to the null terminator of NAME. * * As a special case, if the NAME is the name `/' (or - * equivalent) then DIR_ENT is initialized to all zero and - * BASE_ENT is initialized with the contents of the root - * symbol table entry. + * equivalent) then DIR_ENT is initialized to all zero + * and a pointer to the root symbol table entry is returned. * * As a special case, if the NAME is the string `/foo' (or * equivalent) and the root symbol table entry points to a * non-directory object with a name message with the value - * `foo' then DIR_ENT is initialized to all zero and BASE_ENT - * is initialized with the contents of the root symbol table - * entry. + * `foo' then DIR_ENT is initialized to all zero and a pointer + * to the root symbol table entry is returned. * * Errors: * DIRECTORY COMPLEN Component is too long. * DIRECTORY NOTFOUND Component not found. * DIRECTORY NOTFOUND Root not found. * - * Return: Success: SUCCEED if the name can be fully - * resolved. + * Return: Success: Pointer to a cached symbol table entry if the + * name can be fully resolved. The pointer is + * valid until one of the H5AC (cache) functions + * is called. * - * Failure: FAIL if something bad happened (REST and - * DIR_ENT have undefined values). - * - * -2 if the name could not be fully resolved - * (REST and DIR_ENT are initialized). + * Failure: Null if the name could not be fully resolved. + * REST and DIR_ENT are initialized (possibly to + * zero if the failure occurred soon enough). * * Programmer: Robb Matzke * robb@maya.nuance.com @@ -195,17 +197,21 @@ H5G_basename (const char *name, size_t *size_p) * *------------------------------------------------------------------------- */ -static herr_t +static H5G_entry_t * H5G_namei (hdf5_file_t *f, H5G_entry_t *cwd, const char *name, - const char **rest, H5G_entry_t *dir_ent, H5G_entry_t *base_ent) + const char **rest, H5G_entry_t *dir_ent) { - H5G_entry_t ent[2]; - H5G_entry_t *tmp, *dir, *base; /*ptrs to DIR and BASE entries */ + H5G_entry_t dir; /*entry for current directory */ size_t nchars; /*component name length */ char comp[1024]; /*component name buffer */ hbool_t aside = FALSE; /*did we look at a name message?*/ + H5G_entry_t *ret_value=NULL; /*return value */ + + /* clear output args before FUNC_ENTER() in case it fails */ + if (rest) *rest = name; + if (dir_ent) memset (dir_ent, 0, sizeof(H5G_entry_t)); - FUNC_ENTER (H5G_namei, NULL, FAIL); + FUNC_ENTER (H5G_namei, NULL, NULL); /* check args */ assert (f); @@ -214,26 +220,30 @@ H5G_namei (hdf5_file_t *f, H5G_entry_t *cwd, const char *name, assert (cwd || '/'==*name); /* starting point */ - dir = ent+0; - base = ent+1; if ('/'==*name) { - ent[0] = ent[1] = *(f->root_sym); + if (f->root_sym->header<=0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, NULL); + } + ret_value = f->root_sym; + dir = *(f->root_sym); } else { - ent[0] = ent[1] = *cwd; + ret_value = cwd; + dir = *cwd; } /* traverse the name */ while ((name=H5G_component (name, &nchars)) && *name) { /* - * The special name `.'. + * The special name `.' is a no-op. */ if ('.'==name[0] && !name[1]) continue; /* - * Advance. + * Advance to the next component of the name. */ - tmp=dir; dir=base; base=tmp; /*swap*/ + dir = *ret_value; + ret_value = NULL; if (rest) *rest = name; /* @@ -242,38 +252,32 @@ H5G_namei (hdf5_file_t *f, H5G_entry_t *cwd, const char *name, */ if (nchars+1 > sizeof(comp)) { /* component is too long */ - if (dir_ent) *dir_ent = *dir; - HRETURN_ERROR (H5E_DIRECTORY, H5E_COMPLEN, -2); + if (dir_ent) *dir_ent = dir; + HRETURN_ERROR (H5E_DIRECTORY, H5E_COMPLEN, NULL); } HDmemcpy (comp, name, nchars); comp[nchars] = '\0'; - if (H5G_stab_find (f, dir, comp, base)<0) { + if (NULL==(ret_value=H5G_stab_find (f, NO_ADDR, &dir, comp))) { /* - * Component was not found in the current symbol table, probably - * because it isn't a symbol table. If it is the root symbol then + * Component was not found in the current symbol table, possibly + * because DIR isn't a symbol table. If it is the root symbol then * see if it has the appropriate name field. The ASIDE variable * prevents us from saying `/foo/foo' where the root object has * the name `foo'. */ H5O_name_t mesg={0}; - if (!aside && dir->header==f->root_sym->header && - H5O_read (f, dir->header, dir, H5O_NAME, 0, &mesg)) { - if (!HDstrcmp (mesg.s, comp)) { - H5O_reset (H5O_NAME, &mesg); - *base = *dir; - aside = TRUE; - } else { - /* component not found */ - H5O_reset (H5O_NAME, &mesg); - if (dir_ent) *dir_ent = *dir; - HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, -2); - } + if (!aside && dir.header==f->root_sym->header && + H5O_read (f, dir.header, &dir, H5O_NAME, 0, &mesg) && + !HDstrcmp (mesg.s, comp)) { H5O_reset (H5O_NAME, &mesg); + ret_value = f->root_sym; + aside = TRUE; } else { /* component not found */ - if (dir_ent) *dir_ent = *dir; - HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, -2); + H5O_reset (H5O_NAME, &mesg); + if (dir_ent) *dir_ent = dir; + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, NULL); } } @@ -284,20 +288,19 @@ H5G_namei (hdf5_file_t *f, H5G_entry_t *cwd, const char *name, /* output parameters */ if (rest) *rest = name; /*final null*/ if (dir_ent) { - if (base->header == f->root_sym->header) { + if (ret_value->header == f->root_sym->header) { HDmemset (dir_ent, 0, sizeof(H5G_entry_t)); /*root has no parent*/ } else { - *dir_ent = *dir; + *dir_ent = dir; } } - if (base_ent) *base_ent = *base; /* Perhaps the root object doesn't even exist! */ - if (base->header<=0) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, -2); /*root not found*/ + if (ret_value->header<=0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, NULL); /*root not found*/ } - FUNC_LEAVE (SUCCEED); + FUNC_LEAVE (ret_value); } @@ -338,29 +341,30 @@ H5G_mkroot (hdf5_file_t *f, size_t size_hint) H5G_entry_t root; /*old root entry */ const char *root_name=NULL; /*name of old root object */ intn nlinks; /*number of links */ - hbool_t reset = FALSE; /*should name message be reset? */ + H5G_entry_t *handle; /*handle for open object */ FUNC_ENTER (H5G_mkroot, NULL, FAIL); /* + * Make sure we have the latest info since someone might have the root + * object open for modifications. + */ + H5G_shadow_sync (f->root_sym); + + /* * Is there already a root object that needs to move into the new * root symbol table? The root object is a symbol table if we can * read the H5O_STAB message. */ if (f->root_sym->header>0) { - if (H5O_read (f, f->root_sym->header, f->root_sym, H5O_STAB, 0, &stab)) { + if (H5O_read (f, NO_ADDR, f->root_sym, H5O_STAB, 0, &stab)) { /* root directory already exists */ HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, FAIL); } else if (H5O_read (f, f->root_sym->header, f->root_sym, H5O_NAME, 0, &name)) { - /*dont reset name until root_name is done*/ - root_name = name.s; - reset = TRUE; - - /* remove all name messages -- don't care if it fails */ + root_name = name.s; /*dont reset name until root_name is done!*/ root = *(f->root_sym); - H5O_remove (f, root.header, &root, NULL, H5O_NAME, H5O_ALL); } else { root = *(f->root_sym); @@ -392,15 +396,31 @@ H5G_mkroot (hdf5_file_t *f, size_t size_hint) nlinks = H5O_link (f, root.header, &root, 0); assert (1==nlinks); #endif - - if (H5G_stab_insert (f, f->root_sym, root_name, &root)) { + if (H5G_stab_insert (f, f->root_sym, root_name, &root)<0) { + /* + * This should never happen. If it does and the root object is + * open, then bad things are going to happen because we've just + * deleted the symbol table entry for the open root object! + */ +#ifndef NDEBUG + abort (); +#endif + /* can't insert old root object in new root directory */ H5O_reset (H5O_NAME, &name); HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); } - if (reset) H5O_reset (H5O_NAME, &name); + + /* remove all name messages -- don't care if it fails */ + if ((handle = H5G_open (f, f->root_sym, root_name))) { + H5O_remove (f, NO_ADDR, handle, H5O_NAME, H5O_ALL); + H5G_shadow_close (f, handle); + handle = NULL; + } + H5ECLEAR; } + H5O_reset (H5O_NAME, &name); FUNC_LEAVE (SUCCEED); } @@ -449,7 +469,6 @@ H5G_new (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, { const char *rest=NULL; H5G_entry_t _parent, _child; - herr_t status; char _comp[1024]; size_t nchars; @@ -467,10 +486,7 @@ H5G_new (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, H5ECLEAR; /* lookup name */ - status = H5G_namei (f, cwd, name, &rest, dir_ent, NULL); - if (status<0 && !rest) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*lookup failed*/ - } else if (0==status) { + if (H5G_namei (f, cwd, name, &rest, dir_ent)) { HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, FAIL); /*already exists*/ } H5ECLEAR; /*it's OK that we didn't find it*/ @@ -508,6 +524,91 @@ H5G_new (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, /*------------------------------------------------------------------------- + * Function: H5G_open + * + * Purpose: Opens an object. That is, it prepares the object for + * modification by returning a handle to the object + * symbol table entry. Opening an object twice with the + * same name (or more precisely, through the same final + * symbol table entry) will return pointers to the same + * H5G_entry_t struct. But opening an object through + * different final H5G_entry_t structs (which implies + * different names) returns pointers to different + * structs. The structs that are returned should be + * released by calling H5G_close(). + * + * Return: Success: Ptr to a handle for the object. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Wednesday, September 17, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +H5G_entry_t * +H5G_open (hdf5_file_t *f, H5G_entry_t *cwd, const char *name) +{ + H5G_entry_t *ent=NULL; + H5G_entry_t *handle=NULL; + H5G_entry_t dir; + + FUNC_ENTER (H5G_open, NULL, NULL); + + /* check args */ + assert (f); + assert (name && *name); + assert (cwd || '/'==*name); + + if (f->root_sym->header<=0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, NULL); /*object not found*/ + } + + if (NULL==(ent=H5G_namei (f, cwd, name, NULL, &dir))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, NULL); /*object not found*/ + } + + if (NULL==(handle=H5G_shadow_open (f, &dir, ent))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTOPENOBJ, NULL); + } + + FUNC_LEAVE (handle); +} + + + +/*------------------------------------------------------------------------- + * Function: H5G_close + * + * Purpose: Closes an object that was open for modification. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Thursday, September 18, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_close (hdf5_file_t *f, H5G_entry_t *ent) +{ + FUNC_ENTER (H5G_close, NULL, FAIL); + + if (H5G_shadow_close (f, ent)<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTFLUSH, FAIL); + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- * Function: H5G_find * * Purpose: Finds an object with the specified NAME in file F. If @@ -527,7 +628,14 @@ H5G_new (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, * Errors: * DIRECTORY NOTFOUND Object not found. * - * Return: Success: SUCCEED with DIR_ENT and ENT initialized. + * Return: Success: SUCCEED with DIR_ENT and ENT initialized. ENT + * is intended for immediate read-only access. + * If the object that ENT refers to is open + * through the ENT entry (see H5G_open()) then + * the returned ENT will contain the latest + * information. However, subsequent changes to + * the symbol table entry will not be reflected + * in ENT since it is a copy of the symbol table. * * Failure: FAIL * @@ -543,6 +651,7 @@ herr_t H5G_find (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, const char *name, H5G_entry_t *ent) { + H5G_entry_t *ent_p = NULL; FUNC_ENTER (H5G_find, NULL, FAIL); /* check args */ @@ -554,10 +663,11 @@ H5G_find (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); /*object not found*/ } - if (H5G_namei (f, cwd, name, NULL, dir_ent, ent)<0) { + if (NULL==(ent_p=H5G_namei (f, cwd, name, NULL, dir_ent))) { HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); /*object not found*/ } + if (ent) *ent = *ent_p; FUNC_LEAVE (SUCCEED); } @@ -608,7 +718,6 @@ herr_t H5G_insert (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, const char *name, H5G_entry_t *ent) { - herr_t status; const char *rest=NULL; H5G_entry_t _parent; size_t nchars; @@ -622,8 +731,9 @@ H5G_insert (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, assert (name && *name); assert (cwd || '/'==*name); assert (ent); + assert (!ent->shadow); if (!dir_ent) dir_ent = &_parent; - + /* * If there's already an object or if this object is a directory then * create a root directory. The object is a directory if we can read @@ -639,10 +749,7 @@ H5G_insert (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, /* * Look up the name -- it shouldn't exist yet. */ - status = H5G_namei (f, cwd, name, &rest, dir_ent, NULL); - if (status<0 && !rest) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*lookup failed*/ - } else if (0==status) { + if (H5G_namei (f, cwd, name, &rest, dir_ent)) { HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, FAIL); /*already exists*/ } H5ECLEAR; /*it's OK that we didn't find it*/ @@ -687,14 +794,12 @@ H5G_insert (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, /* * If this is the only object then insert it as the root object. Add * a name messaage to the object header (or modify the first one we - * find). + * find). We don't have to worry about it being open. */ if (f->root_sym->header<=0) { H5O_name_t name_mesg; name_mesg.s = rest; - if (H5O_modify (f, ent->header, ent, NULL, H5O_NAME, 0, &name_mesg)<0 && - H5O_modify (f, ent->header, ent, NULL, H5O_NAME, H5O_NEW_MESG, - &name_mesg)<0) { + if (H5O_modify (f, NO_ADDR, ent, H5O_NAME, 0, &name_mesg)<0) { /* cannot add/change name message */ HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); } @@ -721,73 +826,6 @@ H5G_insert (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, /*------------------------------------------------------------------------- - * Function: H5G_modify - * - * Purpose: Modifies the symbol table entry for the object with the - * specified NAME by copying the new symbol table entry ENT - * over the top of the old one. If NAME is relative then it - * is interpreted with respect to the CWD pointer. If non-null, - * DIR_ENT will be initialized with the symbol table entry for the - * directory which contains the new ENT. - * - * Do not use this function to change the entry for the root - * symbol since that's a special case. This function returns - * failure if that is attempted. - * - * Errors: - * DIRECTORY CANTINIT Can't modify. - * DIRECTORY NOTFOUND Entry not found. - * - * Return: Success: SUCCEED with optional DIR_ENT initialized with - * the symbol table entry for the directory - * which contains the new ENT. - * - * Failure: FAIL (DIR_ENT is not modified). - * - * Programmer: Robb Matzke - * robb@maya.nuance.com - * Aug 11 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5G_modify (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, - const char *name, H5G_entry_t *ent) -{ - const char *rest=NULL; - H5G_entry_t _parent; - - FUNC_ENTER (H5G_modify, NULL, FAIL); - - /* check args */ - assert (f); - assert (name && *name); - assert (cwd || '/'==*name); - assert (ent); - if (!dir_ent) dir_ent = &_parent; - - /* lookup name */ - if (H5G_namei (f, cwd, name, &rest, dir_ent, NULL)<0) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); /*entry not found*/ - } - - /* - * Modify the entry in the parent or in the file struct. - */ - if (dir_ent->header<=0) { - *(f->root_sym) = *ent; - } else if (H5G_stab_modify (f, dir_ent, rest, ent)<0) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*can't modify*/ - } - - FUNC_LEAVE (SUCCEED); -} - - - -/*------------------------------------------------------------------------- * Function: H5G_stab_new * * Purpose: Creates a new empty symbol table (object header, name heap, @@ -869,11 +907,10 @@ H5G_stab_new (hdf5_file_t *f, H5G_entry_t *self, size_t init) /* insert the symbol table message */ if (self) { - self->name_off = 0; + memset (self, 0, sizeof(H5G_entry_t)); self->header = addr; - self->type = H5G_NOTHING_CACHED; } - if (H5O_modify(f, addr, self, NULL, H5O_STAB, H5O_NEW_MESG, &stab)<0) { + if (H5O_modify(f, addr, self, H5O_STAB, H5O_NEW_MESG, &stab)<0) { HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't create message*/ } @@ -886,15 +923,22 @@ H5G_stab_new (hdf5_file_t *f, H5G_entry_t *self, size_t init) * * Purpose: Finds a symbol named NAME in the symbol table whose * description is stored in SELF in file F and returns a - * copy of the symbol table entry through the ENT argument. + * pointer to the symbol table entry. SELF is optional if the + * symbol table address is supplied through ADDR. * * Errors: * SYM BADMESG Can't read message. * SYM NOTFOUND Not found. * - * Return: Success: Address corresponding to the name. + * Return: Success: Pointer to the symbol table entry. + * The pointer is intended for immediate + * read-only access since it points + * directly to an entry in a cached + * symbol table node. The pointer is + * guaranteed to be valid only until the + * next call to one of the H5AC functions. * - * Failure: FAIL + * Failure: NULL * * Programmer: Robb Matzke * matzke@llnl.gov @@ -904,93 +948,41 @@ H5G_stab_new (hdf5_file_t *f, H5G_entry_t *self, size_t init) * *------------------------------------------------------------------------- */ -haddr_t -H5G_stab_find (hdf5_file_t *f, H5G_entry_t *self, const char *name, - H5G_entry_t *ent) +H5G_entry_t * +H5G_stab_find (hdf5_file_t *f, haddr_t addr, H5G_entry_t *self, + const char *name) { - H5G_node_ud1_t udata; /*data to pass through B-tree */ + H5G_bt_ud1_t udata; /*data to pass through B-tree */ H5O_stab_t stab; /*symbol table message */ - FUNC_ENTER (H5G_stab_find, NULL, FAIL); + FUNC_ENTER (H5G_stab_find, NULL, NULL); /* Check arguments */ assert (f); - assert (self && self->header>=0); - assert (name && *name); + if (addr<=0 && (!self || self->header<=0)) { + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); + } + if (!name || !*name) { + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); + } + if (addr<=0) addr = self->header; /* set up the udata */ - if (NULL==H5O_read (f, self->header, self, H5O_STAB, 0, &stab)) { - HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL); /*can't read message*/ + if (NULL==H5O_read (f, addr, self, H5O_STAB, 0, &stab)) { + HRETURN_ERROR (H5E_SYM, H5E_BADMESG, NULL); /*can't read message*/ } udata.operation = H5G_OPER_FIND; udata.name = name; udata.heap_addr = stab.heap_addr; + udata.dir_addr = addr; /* search the B-tree */ if (H5B_find (f, H5B_SNODE, stab.btree_addr, &udata)<0) { - HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); /*not found*/ + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); /*not found*/ } /* return the result */ - if (ent) *ent = udata.entry; - FUNC_LEAVE (udata.entry.header); -} - - -/*------------------------------------------------------------------------- - * Function: H5G_stab_modify - * - * Purpose: Modifies the entry for an existing symbol. The name of the - * symbol is NAME in the symbol table described by SELF in - * file F. ENT is the new symbol table entry to use for the - * symbol. - * - * Errors: - * SYM BADMESG Can't read message. - * SYM NOTFOUND Not found. - * - * Return: Success: SUCCEED - * - * Failure: FAIL - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 1 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5G_stab_modify (hdf5_file_t *f, H5G_entry_t *self, const char *name, - H5G_entry_t *ent) -{ - H5G_node_ud1_t udata; /*data to pass through B-tree */ - H5O_stab_t stab; /*symbol table message */ - - FUNC_ENTER (H5G_stab_modify, NULL, FAIL); - - /* check arguments */ - assert (f); - assert (self && self->header>=0); - assert (name && *name); - assert (ent); - - /* set up the udata */ - if (NULL==H5O_read (f, self->header, self, H5O_STAB, 0, &stab)) { - HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL); /*can't read message*/ - } - udata.operation = H5G_OPER_MODIFY; - udata.name = name; - udata.heap_addr = stab.heap_addr; - udata.entry = *ent; - - /* search and modify the B-tree */ - if (H5B_find (f, H5B_SNODE, stab.btree_addr, &udata)<0) { - HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); /*not found*/ - } - - FUNC_LEAVE (SUCCEED); + FUNC_LEAVE (udata.entry_ptr); } @@ -1015,6 +1007,10 @@ H5G_stab_modify (hdf5_file_t *f, H5G_entry_t *self, const char *name, * * Modifications: * + * Robb Matzke, 18 Sep 1997 + * If ENT has a shadow, then the shadow will be associated with the + * entry when it is added to the symbol table. + * *------------------------------------------------------------------------- */ herr_t @@ -1022,7 +1018,7 @@ H5G_stab_insert (hdf5_file_t *f, H5G_entry_t *self, const char *name, H5G_entry_t *ent) { H5O_stab_t stab; /*symbol table message */ - H5G_node_ud1_t udata; /*data to pass through B-tree */ + H5G_bt_ud1_t udata; /*data to pass through B-tree */ FUNC_ENTER (H5G_stab_insert, NULL, FAIL); @@ -1036,9 +1032,13 @@ H5G_stab_insert (hdf5_file_t *f, H5G_entry_t *self, const char *name, if (NULL==H5O_read (f, self->header, self, H5O_STAB, 0, &stab)) { HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL); /*can't read message*/ } + + udata.operation = H5G_OPER_INSERT; udata.name = name; udata.heap_addr = stab.heap_addr; + udata.dir_addr = self->header; udata.entry = *ent; + udata.entry.name_off = -1; /* insert */ if (H5B_insert (f, H5B_SNODE, stab.btree_addr, &udata)<0) { @@ -1086,7 +1086,7 @@ intn H5G_stab_list (hdf5_file_t *f, H5G_entry_t *self, intn maxentries, char *names[], H5G_entry_t entries[]) { - H5G_node_list_t udata; + H5G_bt_ud2_t udata; H5O_stab_t stab; intn i; @@ -1103,6 +1103,7 @@ H5G_stab_list (hdf5_file_t *f, H5G_entry_t *self, intn maxentries, } udata.entry = entries; udata.name = names; + udata.dir_addr = self->header; udata.heap_addr = stab.heap_addr; udata.maxentries = maxentries; udata.nsyms = 0; @@ -1388,6 +1389,13 @@ H5G_debug (hdf5_file_t *f, H5G_entry_t *ent, FILE *stream, intn indent, fprintf (stream, "%*s%-*s %lu\n", indent, "", fwidth, "Object header address:", (unsigned long)(ent->header)); + fprintf (stream, "%*s%-*s %s\n", indent, "", fwidth, + "Dirty:", + ent->dirty ? "Yes" : "No"); + fprintf (stream, "%*s%-*s %s\n", indent, "", fwidth, + "Has a shadow:", + H5G_shadow_p (ent)?"This is a shadow!" : + (ent->shadow ? "Yes" : "No")); fprintf (stream, "%*s%-*s ", indent, "", fwidth, "Symbol type:"); diff --git a/src/H5Gnode.c b/src/H5Gnode.c index b344713..0729a78 100644 --- a/src/H5Gnode.c +++ b/src/H5Gnode.c @@ -18,22 +18,26 @@ * Robb Matzke, 5 Aug 1997 * Added calls to H5E. * + * Robb Matzke, 18 Sep 1997 + * Added shadow entries. + * *------------------------------------------------------------------------- */ +#define H5G_PACKAGE /*suppress error message about including H5Gpkg.h*/ /* Packages needed by this file... */ #include /*library */ #include /*cache */ #include /*B-link trees */ #include /*error handling */ -#include /*me */ +#include /*me */ #include /*heap */ #include /*file memory management */ #include /*core memory management */ +#include /*header messages */ #define PABLO_MASK H5G_node_mask - /* PRIVATE PROTOTYPES */ static herr_t H5G_node_decode_key (hdf5_file_t *f, uint8 *raw, void *_key); static herr_t H5G_node_encode_key (hdf5_file_t *f, uint8 *raw, void *_key); @@ -42,8 +46,7 @@ static haddr_t H5G_node_new (hdf5_file_t *f, void *_lt_key, void *_udata, void *_rt_key); static herr_t H5G_node_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5G_node_t *sym); -static H5G_node_t *H5G_node_load (hdf5_file_t *f, haddr_t addr, - const void *_data); +static H5G_node_t *H5G_node_load (hdf5_file_t *f, haddr_t addr, void *_data); static intn H5G_node_cmp (hdf5_file_t *f, void *_lt_key, void *_udata, void *_rt_key); static herr_t H5G_node_found (hdf5_file_t *f, haddr_t addr, @@ -58,12 +61,12 @@ static size_t H5G_node_sizeof_rkey (hdf5_file_t *f); /* H5G inherits cache-like properties from H5AC */ static const H5AC_class_t H5AC_SNODE[1] = {{ - (void*(*)(hdf5_file_t*,haddr_t,const void*))H5G_node_load, + (void*(*)(hdf5_file_t*,haddr_t,void*))H5G_node_load, (herr_t(*)(hdf5_file_t*,hbool_t,haddr_t,void*))H5G_node_flush, }}; /* H5G inherits B-tree like properties from H5B */ -const H5B_class_t H5B_SNODE[1] = {{ +H5B_class_t H5B_SNODE[1] = {{ H5B_SNODE_ID, /*id */ sizeof (H5G_node_key_t), /*sizeof_nkey */ H5G_node_sizeof_rkey, /*get_sizeof_rkey */ @@ -265,7 +268,10 @@ H5G_node_new (hdf5_file_t *f, void *_lt_key, void *_udata, void *_rt_key) /*------------------------------------------------------------------------- * Function: H5G_node_flush * - * Purpose: Flush a symbol table node to disk. + * Purpose: Flush a symbol table node to disk. If any entries have dirty + * shadows, the shadow value is copied into the entry before the + * entry is flushed. The association between shadows and + * entries is broken. * * Return: Success: SUCCEED * @@ -285,6 +291,7 @@ H5G_node_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5G_node_t *sym) uint8 *buf=NULL, *p=NULL; size_t size; herr_t status; + int i; FUNC_ENTER (H5G_node_flush, NULL, FAIL); @@ -295,6 +302,19 @@ H5G_node_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5G_node_t *sym) assert (addr>=0); assert (sym); + /* + * Synchronize all entries with their corresponding shadow if they have + * one. + */ + for (i=0; insyms; i++) { + if (H5G_shadow_sync (sym->entry+i)<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTFLUSH, FAIL); + } + } + + /* + * Write the symbol node to disk. + */ if (sym->dirty) { size = H5G_node_size (f); buf = p = H5MM_xmalloc (size); @@ -321,7 +341,15 @@ H5G_node_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5G_node_t *sym) if (status<0) HRETURN_ERROR (H5E_SYM, H5E_WRITEERROR, FAIL); } + /* + * Destroy the symbol node? This might happen if the node is being + * preempted from the cache. We should also dissociate the shadow + * from the entry. + */ if (destroy) { + for (i=0; insyms; i++) { + H5G_shadow_dissociate (sym->entry+i); + } sym->entry = H5MM_xfree (sym->entry); H5MM_xfree (sym); } @@ -333,7 +361,8 @@ H5G_node_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5G_node_t *sym) /*------------------------------------------------------------------------- * Function: H5G_node_load * - * Purpose: Loads a symbol table from the file. + * Purpose: Loads a symbol table from the file and associates shadows + * with their entries. * * Return: Success: Ptr to the new table. * @@ -348,11 +377,13 @@ H5G_node_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5G_node_t *sym) *------------------------------------------------------------------------- */ static H5G_node_t * -H5G_node_load (hdf5_file_t *f, haddr_t addr, const void *_udata) +H5G_node_load (hdf5_file_t *f, haddr_t addr, void *_udata) { H5G_node_t *sym = NULL; size_t size = 0; uint8 *buf = NULL, *p = NULL; + H5G_entry_t *self = NULL; + H5G_node_t *ret_value = NULL; /*for error handling*/ FUNC_ENTER (H5G_node_load, NULL, NULL); @@ -361,7 +392,8 @@ H5G_node_load (hdf5_file_t *f, haddr_t addr, const void *_udata) */ assert (f); assert (addr>=0); - assert (NULL==_udata); + assert (_udata); + self = (H5G_entry_t*)_udata; /* * Initialize variables. @@ -372,17 +404,19 @@ H5G_node_load (hdf5_file_t *f, haddr_t addr, const void *_udata) sym->entry = H5MM_xcalloc (2*H5G_NODE_K(f), sizeof(H5G_entry_t)); if (H5F_block_read (f, addr, size, buf)<0) { - H5MM_xfree (sym->entry); - H5MM_xfree (sym); - HRETURN_ERROR (H5E_SYM, H5E_READERROR, NULL); + HGOTO_ERROR (H5E_SYM, H5E_READERROR, NULL); } /* magic */ - if (HDmemcmp (p, H5G_NODE_MAGIC, H5G_NODE_SIZEOF_MAGIC)) goto error; + if (HDmemcmp (p, H5G_NODE_MAGIC, H5G_NODE_SIZEOF_MAGIC)) { + HGOTO_ERROR (H5E_SYM, H5E_CANTLOAD, NULL); + } p += 4; /* version */ - if (H5G_NODE_VERS!=*p++) goto error; + if (H5G_NODE_VERS!=*p++) { + HGOTO_ERROR (H5E_SYM, H5E_CANTLOAD, NULL); + } /* reserved */ p++; @@ -391,15 +425,28 @@ H5G_node_load (hdf5_file_t *f, haddr_t addr, const void *_udata) UINT16DECODE (p, sym->nsyms); /* entries */ - if (H5G_decode_vec (f, &p, sym->entry, sym->nsyms)<0) goto error; + if (H5G_decode_vec (f, &p, sym->entry, sym->nsyms)<0) { + HGOTO_ERROR (H5E_SYM, H5E_CANTLOAD, NULL); + } + buf = H5MM_xfree (buf); - H5MM_xfree (buf); - FUNC_LEAVE (sym); + /* shadows */ + if (H5G_shadow_assoc_node (f, sym, self)<0) { + HGOTO_ERROR (H5E_SYM, H5E_CANTLOAD, NULL); + } + + ret_value = sym; + -error: - H5MM_xfree (buf); - H5MM_xfree (sym); - HRETURN_ERROR (H5E_SYM, H5E_CANTLOAD, NULL); + done: + if (!ret_value) { + buf = H5MM_xfree (buf); + if (sym) { + sym->entry = H5MM_xfree (sym->entry); + sym = H5MM_xfree (sym); + } + } + FUNC_LEAVE (ret_value); } @@ -433,7 +480,7 @@ error: static intn H5G_node_cmp (hdf5_file_t *f, void *_lt_key, void *_udata, void *_rt_key) { - H5G_node_ud1_t *udata = (H5G_node_ud1_t *)_udata; + H5G_bt_ud1_t *udata = (H5G_bt_ud1_t *)_udata; H5G_node_key_t *lt_key = (H5G_node_key_t *)_lt_key; H5G_node_key_t *rt_key = (H5G_node_key_t *)_rt_key; const char *s; @@ -488,7 +535,8 @@ static herr_t H5G_node_found (hdf5_file_t *f, haddr_t addr, const void *_lt_key, void *_udata, const void *_rt_key) { - H5G_node_ud1_t *udata = (H5G_node_ud1_t *)_udata; + H5G_bt_ud1_t *bt_udata = (H5G_bt_ud1_t *)_udata; + H5G_ac_ud1_t ac_udata; H5G_node_t *sn = NULL; intn lt=0, idx=0, rt, cmp=1; const char *s; @@ -501,12 +549,15 @@ H5G_node_found (hdf5_file_t *f, haddr_t addr, const void *_lt_key, */ assert (f); assert (addr>=0); - assert (udata); + assert (bt_udata); + + ac_udata.dir_addr = bt_udata->dir_addr; + ac_udata.heap_addr = bt_udata->heap_addr; /* * Load the symbol table node for exclusive access. */ - if (NULL==(sn=H5AC_protect (f, H5AC_SNODE, addr, NULL))) { + if (NULL==(sn=H5AC_protect (f, H5AC_SNODE, addr, &ac_udata))) { HGOTO_ERROR (H5E_SYM, H5E_CANTLOAD, FAIL); } @@ -516,10 +567,11 @@ H5G_node_found (hdf5_file_t *f, haddr_t addr, const void *_lt_key, rt = sn->nsyms; while (ltheap_addr, sn->entry[idx].name_off))) { + if (NULL==(s=H5H_peek (f, bt_udata->heap_addr, + sn->entry[idx].name_off))) { HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); } - cmp = HDstrcmp (udata->name, s); + cmp = HDstrcmp (bt_udata->name, s); if (cmp<0) { rt = idx; @@ -529,20 +581,18 @@ H5G_node_found (hdf5_file_t *f, haddr_t addr, const void *_lt_key, } if (cmp) HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); - switch (udata->operation) { + switch (bt_udata->operation) { case H5G_OPER_FIND: /* - * The caller is querying the symbol entry. + * The caller is querying the symbol entry. Return just a pointer to + * the entry. The pointer is valid until the next call to H5AC. */ - udata->entry = sn->entry[idx]; + H5G_shadow_sync (sn->entry+idx); + bt_udata->entry_ptr = sn->entry+idx; break; - case H5G_OPER_MODIFY: - /* - * The caller is modifying the symbol entry. - */ - sn->entry[idx] = udata->entry; - sn->dirty += 1; + default: + HRETURN_ERROR (H5E_SYM, H5E_UNSUPPORTED, FAIL); break; } ret_value = SUCCEED; @@ -589,6 +639,10 @@ done: * * Modifications: * + * Robb Matzke, 18 Sep 1997 + * If the shadow pointer is non-null then the shadow is updated to point + * to the new entry. + * *------------------------------------------------------------------------- */ static haddr_t @@ -599,14 +653,17 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, { H5G_node_key_t *md_key = (H5G_node_key_t *)_md_key; H5G_node_key_t *rt_key = (H5G_node_key_t *)_rt_key; - H5G_node_ud1_t *udata = (H5G_node_ud1_t *)_udata; - + H5G_bt_ud1_t *bt_udata = (H5G_bt_ud1_t *)_udata; + + H5G_ac_ud1_t ac_udata; H5G_node_t *sn=NULL, *snrt=NULL; haddr_t new_node=0, offset; const char *s; intn idx=-1, cmp=1; intn lt=0, rt; /*binary search cntrs */ + intn i; haddr_t ret_value = FAIL; + H5G_shadow_t *shadow = NULL; FUNC_ENTER (H5G_node_insert, NULL, FAIL); @@ -618,7 +675,8 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, assert (anchor); assert (md_key); assert (rt_key); - assert (udata); + assert (bt_udata); + bt_udata->entry_ptr = NULL; /* * Symbol tables are always split so the new symbol table node is @@ -631,7 +689,9 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, /* * Load the symbol node. */ - if (NULL==(sn=H5AC_protect (f, H5AC_SNODE, addr, NULL))) { + ac_udata.dir_addr = bt_udata->dir_addr; + ac_udata.heap_addr = bt_udata->heap_addr; + if (NULL==(sn=H5AC_protect (f, H5AC_SNODE, addr, &ac_udata))) { HGOTO_ERROR (H5E_SYM, H5E_CANTLOAD, FAIL); } @@ -641,10 +701,11 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, rt = sn->nsyms; while (ltheap_addr, sn->entry[idx].name_off))) { + if (NULL==(s=H5H_peek (f, bt_udata->heap_addr, + sn->entry[idx].name_off))) { HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); } - if (0==(cmp=HDstrcmp (udata->name, s))) { + if (0==(cmp=HDstrcmp (bt_udata->name, s))) { HGOTO_ERROR (H5E_SYM, H5E_CANTINSERT, FAIL); /*already present*/ } if (cmp<0) { @@ -660,9 +721,9 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, * heap address changed and update the symbol table object header * with the new heap address. */ - offset = H5H_insert (f, udata->heap_addr, HDstrlen(udata->name)+1, - udata->name); - udata->entry.name_off = offset; + offset = H5H_insert (f, bt_udata->heap_addr, HDstrlen(bt_udata->name)+1, + bt_udata->name); + bt_udata->entry.name_off = offset; if (offset<0) HGOTO_ERROR (H5E_SYM, H5E_CANTINSERT, FAIL); if (sn->nsyms>=2*H5G_NODE_K(f)) { @@ -676,7 +737,7 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, if ((new_node = H5G_node_new (f, NULL, NULL, NULL))<0) { HGOTO_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); } - if (NULL==(snrt=H5AC_find (f, H5AC_SNODE, new_node, NULL))) { + if (NULL==(snrt=H5AC_find (f, H5AC_SNODE, new_node, &ac_udata))) { HGOTO_ERROR (H5E_SYM, H5E_CANTLOAD, FAIL); } HDmemcpy (snrt->entry, sn->entry + H5G_NODE_K(f), @@ -684,6 +745,13 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, snrt->nsyms = H5G_NODE_K(f); snrt->dirty += 1; + /* Right shadows */ + for (i=0; ientry[i].shadow)) { + shadow->main = snrt->entry + i; + } + } + /* The left node */ HDmemset (sn->entry + H5G_NODE_K(f), 0, H5G_NODE_K(f) * sizeof(H5G_entry_t)); @@ -692,19 +760,46 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, /* Insert the new entry */ if (idx<=H5G_NODE_K(f)) { + + /* Adjust shadows */ + for (i=idx; insyms; i++) { + if (sn->entry[i].shadow) { + sn->entry[i].shadow->main = sn->entry + i + 1; + } + } + if (bt_udata->entry.shadow) { + bt_udata->entry.shadow->main = sn->entry + idx; + } + + /* Move entries */ HDmemmove (sn->entry + idx + 1, sn->entry + idx, (H5G_NODE_K(f)-idx) * sizeof(H5G_entry_t)); - sn->entry[idx] = udata->entry; + sn->entry[idx] = bt_udata->entry; sn->entry[idx].name_off = offset; + sn->entry[idx].dirty = TRUE; sn->nsyms += 1; + } else { idx -= H5G_NODE_K (f); + + /* Adjust shadows */ + for (i=idx; insyms; i++) { + if (snrt->entry[i].shadow) { + snrt->entry[i].shadow->main = snrt->entry + i + 1; + } + } + if (bt_udata->entry.shadow) { + bt_udata->entry.shadow->main = snrt->entry + idx; + } + + /* Move entries */ HDmemmove (snrt->entry + idx + 1, snrt->entry + idx, (H5G_NODE_K(f)-idx) * sizeof (H5G_entry_t)); - snrt->entry[idx] = udata->entry; + snrt->entry[idx] = bt_udata->entry; snrt->entry[idx].name_off = offset; + snrt->entry[idx].dirty = TRUE; snrt->nsyms += 1; if (idx+1 == sn->nsyms) { @@ -721,12 +816,21 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, * Add the new symbol to the node. */ sn->dirty += 1; + for (i=idx; insyms; i++) { + if (sn->entry[i].shadow) { + sn->entry[i].shadow->main = sn->entry + i + 1; + } + } + if (bt_udata->entry.shadow) { + bt_udata->entry.shadow->main = sn->entry + idx; + } HDmemmove (sn->entry+idx+1, sn->entry+idx, (sn->nsyms-idx) * sizeof (H5G_entry_t)); sn->nsyms += 1; - sn->entry[idx] = udata->entry; + sn->entry[idx] = bt_udata->entry; sn->entry[idx].name_off = offset; - + sn->entry[idx].dirty = TRUE; + if (idx+1==sn->nsyms) { rt_key->offset = offset; *rt_key_changed = TRUE; @@ -765,12 +869,13 @@ done: static herr_t H5G_node_list (hdf5_file_t *f, haddr_t addr, void *_udata) { - H5G_node_list_t *udata = (H5G_node_list_t *)_udata; + H5G_bt_ud2_t *bt_udata = (H5G_bt_ud2_t *)_udata; H5G_node_t *sn = NULL; intn i; const char *s; herr_t ret_value = FAIL; - + H5G_ac_ud1_t ac_udata; + FUNC_ENTER (H5G_node_list, NULL, FAIL); /* @@ -778,9 +883,11 @@ H5G_node_list (hdf5_file_t *f, haddr_t addr, void *_udata) */ assert (f); assert (addr>=0); - assert (udata); + assert (bt_udata); - if (NULL==(sn=H5AC_protect (f, H5AC_SNODE, addr, NULL))) { + ac_udata.dir_addr = bt_udata->dir_addr; + ac_udata.heap_addr = bt_udata->heap_addr; + if (NULL==(sn=H5AC_protect (f, H5AC_SNODE, addr, &ac_udata))) { HGOTO_ERROR (H5E_SYM, H5E_CANTLOAD, FAIL); } @@ -789,32 +896,34 @@ H5G_node_list (hdf5_file_t *f, haddr_t addr, void *_udata) * keep track of how many names we've seen and don't bother doing * anything else. */ - if (udata->nsyms >= udata->maxentries) { - udata->nsyms += sn->nsyms; + if (bt_udata->nsyms >= bt_udata->maxentries) { + bt_udata->nsyms += sn->nsyms; HGOTO_DONE (SUCCEED); } /* * Save the symbol table entries. */ - if (udata->entry) { - for (i=0; insyms && udata->nsyms+imaxentries; i++) { - udata->entry[udata->nsyms+i] = sn->entry[i]; + if (bt_udata->entry) { + for (i=0; insyms && bt_udata->nsyms+imaxentries; i++) { + H5G_shadow_sync (sn->entry+i); + bt_udata->entry[bt_udata->nsyms+i] = sn->entry[i]; } } - if (udata->name) { - for (i=0; insyms && udata->nsyms+imaxentries; i++) { - if (NULL==(s=H5H_peek (f, udata->heap_addr, sn->entry[i].name_off))) { + if (bt_udata->name) { + for (i=0; insyms && bt_udata->nsyms+imaxentries; i++) { + if (NULL==(s=H5H_peek (f, bt_udata->heap_addr, + sn->entry[i].name_off))) { HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); } - udata->name[udata->nsyms+i] = H5MM_xstrdup (s); + bt_udata->name[bt_udata->nsyms+i] = H5MM_xstrdup (s); } } /* * Update the number of symbols. */ - udata->nsyms += sn->nsyms; + bt_udata->nsyms += sn->nsyms; ret_value = SUCCEED; done: @@ -847,10 +956,11 @@ herr_t H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, intn fwidth, haddr_t heap) { - int i; + int i, acc; H5G_node_t *sn = NULL; herr_t status; const char *s; + H5G_ac_ud1_t ac_udata; FUNC_ENTER (H5G_node_debug, NULL, FAIL); @@ -864,6 +974,18 @@ H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, assert (fwidth>=0); /* + * We have absolutely no idea where the object header for the symbol table + * to which this node belongs is located. In fact, if the file is corrupt, + * there may not even be an object header for that symbol table. So we + * supply `-1' as the directory address which causes no open objects to be + * associated with the node. For that reason, we flush this node from the + * cache when we're done so if some later caller knows the header address + * they'll be able to access the open objects. + */ + ac_udata.dir_addr = -1; + ac_udata.heap_addr = heap; + + /* * If we couldn't load the symbol table node, then try loading the * B-tree node. */ @@ -882,6 +1004,12 @@ H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, fprintf (stream, "%*s%-*s %d of %d\n", indent, "", fwidth, "Number of Symbols:", sn->nsyms, 2*H5G_NODE_K(f)); + for (i=acc=0; insyms; i++) { + if (sn->entry[i].shadow) acc++; + } + fprintf (stream, "%*s%-*s %d\n", indent, "", fwidth, + "Shadows:", acc); + indent += 3; fwidth = MAX (0, fwidth-3); @@ -893,8 +1021,12 @@ H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, s); } H5G_debug (f, sn->entry+i, stream, indent, fwidth); + fprintf (stream, "%*s%-*s %s\n", indent+3, "", MAX (0, fwidth-3), + "Shadow:", + sn->entry[i].shadow ? "Yes":"No"); } + H5AC_flush (f, H5AC_SNODE, addr, TRUE); /*see note above*/ FUNC_LEAVE (SUCCEED); } diff --git a/src/H5Gpkg.h b/src/H5Gpkg.h new file mode 100644 index 0000000..5a33d8d --- /dev/null +++ b/src/H5Gpkg.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 1997 National Center for Supercomputing Applications. + * All rights reserved. + * + * Programmer: Robb Matzke + * Thursday, September 18, 1997 + * + * Purpose: This file contains declarations which are visible + * only within the H5G package. Source files outside the + * H5G package should include H5Gprivate.h instead. + */ +#ifndef H5G_PACKAGE +#error "Do not include this file outside the H5G package!" +#endif + +#ifndef _H5Gpkg_H +#define _H5Gpkg_H + +#include + +#define H5G_NODE_VERS 1 /*symbol table node version number */ +#define H5G_SIZE_HINT 1024 /*default root dir size hint */ +#define H5G_NODE_K(F) ((F)->file_create_parms.sym_leaf_k) +#define H5G_NODE_SIZEOF_HDR(F) (H5G_NODE_SIZEOF_MAGIC + 4) +#define H5G_DEFAULT_ROOT_SIZE 32 + + +/* + * A shadow is a copy of a symbol table entry which corresponds to an + * `open' object. Shadows are necessary because normal symbol table + * entries can be preempted from the main cache. The `shadow' field + * of the `entry' points to the beginning of the shadow just like the + * shadow field from symbol table entries in H5G_node_t. + */ +struct H5G_shadow_t { + char *name; /*name for this entry */ + haddr_t dir_addr; /*hdr addr for dir containing shadow */ + uintn nrefs; /*reference counter */ + H5G_entry_t entry; /*local copy of symbol table entry */ + H5G_entry_t *main; /*main entry in stab node if cached */ + struct H5G_shadow_t *next; /*next shadow for same symbol table */ + struct H5G_shadow_t *prev; /*previous shadow for same symbol table */ +}; + +/* + * A symbol table node is a collection of symbol table entries. It can + * be thought of as the lowest level of the B-link tree that points to + * a collection of symbol table entries that belong to a specific symbol + * table or directory. + */ +typedef struct H5G_node_t { + int dirty; /*has cache been modified? */ + int nsyms; /*number of symbols */ + H5G_entry_t *entry; /*array of symbol table entries */ +} H5G_node_t; + +/* + * Each key field of the B-link tree that points to symbol table + * nodes consists of this structure... + */ +typedef struct H5G_node_key_t { + off_t offset; /*offset into heap for name */ +} H5G_node_key_t; + +/* + * These operations can be passed down from the H5G_stab layer to the + * 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_t; + +/* + * Data exchange structure for symbol table nodes. This structure is + * passed through the B-link tree layer to the methods for the objects + * to which the B-link tree points. + */ +typedef struct H5G_bt_ud1_t { + + /* downward */ + H5G_oper_t operation; /*what operation to perform */ + const char *name; /*points to temporary memory */ + haddr_t dir_addr; /*symbol table header address */ + haddr_t heap_addr; /*symbol table heap address */ + + /* downward for INSERT */ + H5G_entry_t entry; /*entry to insert into table */ + + /* upward for FIND */ + H5G_entry_t *entry_ptr; /*ptr into cached symbol table node */ + +} H5G_bt_ud1_t; + +/* + * Data exchange structure to pass through the B-tree layer for the + * H5B_list function. + */ +typedef struct H5G_bt_ud2_t { + + /* downward */ + H5G_entry_t *entry; /*array of entries, alloc'd by caller */ + char **name; /*array of string ptrs, allocd by caller*/ + intn maxentries; /*size of the ADDR and NAME arrays */ + haddr_t dir_addr; /*symbol table header address */ + haddr_t heap_addr; /*heap address */ + + /* upward */ + intn nsyms; /*num. symbols processed */ + +} H5G_bt_ud2_t; + +/* + * This is the class identifier to give to the B-tree functions. + */ +extern H5B_class_t H5B_SNODE[1]; + +/* + * This struct passes information through the H5AC layer. + */ +typedef struct H5G_ac_ud1_t { + haddr_t heap_addr; + haddr_t dir_addr; +} H5G_ac_ud1_t; + +/* + * Functions that understand symbol tables but not directories. The + * functions that understand directories are exported to the rest of + * the library and appear in H5Gprivate.h. + */ +haddr_t H5G_stab_new (hdf5_file_t *f, H5G_entry_t *self, size_t init); +H5G_entry_t *H5G_stab_find (hdf5_file_t *f, haddr_t addr, H5G_entry_t *self, + const char *name); +herr_t H5G_stab_insert (hdf5_file_t *f, H5G_entry_t *self, const char *name, + H5G_entry_t *ent); +intn H5G_stab_list (hdf5_file_t *f, H5G_entry_t *self, intn maxentries, + char *names[], H5G_entry_t entries[]); + +/* + * Functions that understand shadow entries. + */ +herr_t H5G_shadow_sync (H5G_entry_t *ent); +H5G_entry_t *H5G_shadow_open (hdf5_file_t *f, H5G_entry_t *dir, + H5G_entry_t *ent); +herr_t H5G_shadow_close (hdf5_file_t *f, H5G_entry_t *ent); +hbool_t H5G_shadow_p (H5G_entry_t *ent); +herr_t H5G_shadow_dissociate (H5G_entry_t *ent); +herr_t H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, + H5G_entry_t *self); +H5G_shadow_t *H5G_shadow_list (haddr_t stab_header_addr); + +/* + * Functions that understand symbol table entries. + */ +herr_t H5G_decode_vec (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent, intn n); +herr_t H5G_encode_vec (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent, intn n); + +#endif diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h index e6f5df4..dd26902 100644 --- a/src/H5Gprivate.h +++ b/src/H5Gprivate.h @@ -8,7 +8,7 @@ * Jul 11 1997 * Robb Matzke * - * Purpose: Private stuff for the H5G package (symbol tables). + * Purpose: Library-visible declarations. * * Modifications: * @@ -25,18 +25,17 @@ #define H5G_NODE_MAGIC "SNOD" /*symbol table node magic number */ #define H5G_NODE_SIZEOF_MAGIC 4 /*sizeof symbol node magic number */ -#define H5G_NODE_VERS 1 /*symbol table node version number */ -#define H5G_SIZE_HINT 1024 /*default root dir size hint */ -#define H5G_NODE_K(F) ((F)->file_create_parms.sym_leaf_k) -#define H5G_NODE_SIZEOF_HDR(F) (H5G_NODE_SIZEOF_MAGIC + 4) +#define H5G_new_entry() H5MM_xcalloc (1, sizeof(H5G_entry_t)) + +/* + * The disk size for a symbol table entry... + */ #define H5G_SIZEOF_ENTRY(F) \ (H5F_SIZEOF_OFFSET(F) + /*offset of name into heap */ \ H5F_SIZEOF_OFFSET(F) + /*address of object header */ \ 4 + /*entry type */ \ 24) /*scratch pad space */ -#define H5G_DEFAULT_ROOT_SIZE 32 - /* * Various types of object header information can be cached in a symbol * table entry (it's normal home is the object header to which the entry @@ -44,134 +43,73 @@ * symbol table entry. */ typedef enum H5G_type_t { - H5G_NOTHING_CACHED =0, /*nothing is cached */ + H5G_NOTHING_CACHED =0, /*nothing is cached, must be 0 */ H5G_CACHED_SDATA =1, /*simple dataset, `sdata' */ H5G_CACHED_STAB =2 /*symbol table, `stab' */ } H5G_type_t; /* + * A symbol table entry caches these parameters from object header + * messages... + */ +typedef union H5G_cache_t { + struct { + struct { + uint8 length; + uint8 arch; + uint16 type; + } nt ; /*number type */ + uint32 ndim; /*number of dimensions */ + uint32 dim[4]; /*dimension sizes */ + } sdata; + + struct { + haddr_t btree_addr; /*file address of symbol table B-tree */ + haddr_t heap_addr; /*file address of stab name heap */ + } stab; +} H5G_cache_t; + +/* + * An H5G_shadow_t is the struct used to describe object headers that + * are currently open for modification. It's contents is not + * important outside H5G. + */ +typedef struct H5G_shadow_t H5G_shadow_t; + +/* * A symbol table entry. The two important fields are `name_off' and * `header'. The remaining fields are used for caching information that * also appears in the object header to which this symbol table entry * points. */ typedef struct H5G_entry_t { + hbool_t dirty; /*entry out-of-date? */ off_t name_off; /*offset of name within name heap */ haddr_t header; /*file address of object header */ H5G_type_t type; /*type of information cached */ - - union { - struct { - struct { - uint8 length; - uint8 arch; - uint16 type; - } nt ; /*number type */ - uint32 ndim; /*number of dimensions */ - uint32 dim[4]; /*dimension sizes */ - } sdata; - - struct { - haddr_t btree_addr; /*file address of symbol table B-tree */ - haddr_t heap_addr; /*file address of stab name heap */ - } stab; - } cache; /*cached data from object header */ + H5G_cache_t cache; /*cached data from object header */ + H5G_shadow_t *shadow; /*optional ptr to the shadow */ } H5G_entry_t; /* - * A symbol table node is a collection of symbol table entries. It can - * be thought of as the lowest level of the B-link tree that points to - * a collection of symbol table entries that belong to a specific symbol - * table or directory. - */ -typedef struct H5G_node_t { - int dirty; /*has cache been modified? */ - int nsyms; /*number of symbols */ - H5G_entry_t *entry; /*symbol table entries */ -} H5G_node_t; - -/* - * Each key field of the B-link tree that points to symbol table - * nodes consists of this structure... - */ -typedef struct H5G_node_key_t { - off_t offset; /*offset into heap for name */ -} H5G_node_key_t; - -typedef enum H5G_oper_t { - H5G_OPER_FIND =0, /*find a symbol */ - H5G_OPER_MODIFY =1 /*modify a symbol */ -} H5G_oper_t; - -/* - * Data exchange structure for symbol table nodes. This structure is - * passed through the B-link tree layer to the methods for the objects - * to which the B-link tree points. - */ -typedef struct H5G_node_ud1_t { - - /* downward */ - H5G_oper_t operation; /*what operation to perform */ - const char *name; /*points to temporary memory */ - haddr_t heap_addr; /*symbol table heap address */ - - /* upward for H5G_OPER_FIND, downward for H5G_OPER_MODIFY */ - H5G_entry_t entry; /*symbol table entry */ - -} H5G_node_ud1_t; - -typedef struct H5G_node_list_t { - - /* downward */ - H5G_entry_t *entry; /*array of entries, alloc'd by caller */ - char **name; /*array of string ptrs, allocd by caller*/ - intn maxentries; /*size of the ADDR and NAME arrays */ - haddr_t heap_addr; /*heap address */ - - /* upward */ - intn nsyms; /*num. symbols processed */ - -} H5G_node_list_t; - -extern const H5B_class_t H5B_SNODE[1]; - -/* * Library prototypes... */ - -/* functions that understand directories */ herr_t H5G_new (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, const char *name, size_t size_hint, H5G_entry_t *ent); +H5G_entry_t *H5G_open (hdf5_file_t *f, H5G_entry_t *cwd, const char *name); +herr_t H5G_close (hdf5_file_t *f, H5G_entry_t *ent); herr_t H5G_find (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, const char *name, H5G_entry_t *ent); herr_t H5G_insert (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, const char *name, H5G_entry_t *ent); -herr_t H5G_modify (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, - const char *name, H5G_entry_t *ent); herr_t H5G_set_root (hdf5_file_t *f, const char *name, H5G_entry_t *ent); - -/* functions that understand symbol tables */ -haddr_t H5G_stab_new (hdf5_file_t *f, H5G_entry_t *self, size_t init); -haddr_t H5G_stab_find (hdf5_file_t *f, H5G_entry_t *self, const char *name, - H5G_entry_t *ent); -herr_t H5G_stab_modify (hdf5_file_t *f, H5G_entry_t *self, const char *name, - H5G_entry_t *ent); -herr_t H5G_stab_insert (hdf5_file_t *f, H5G_entry_t *self, const char *name, - H5G_entry_t *ent); -intn H5G_stab_list (hdf5_file_t *f, H5G_entry_t *self, intn maxentries, - char *names[], H5G_entry_t entries[]); - -/* functions that understand symbol table nodes */ -herr_t H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, - intn fwidth, haddr_t heap); - -/* functions that understand symbol table entries */ -herr_t H5G_decode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent); -herr_t H5G_decode_vec (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent, intn n); herr_t H5G_encode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent); -herr_t H5G_encode_vec (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent, intn n); +herr_t H5G_decode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent); herr_t H5G_debug (hdf5_file_t *f, H5G_entry_t *ent, FILE *stream, intn indent, intn fwidth); +herr_t H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, + intn fwidth, haddr_t heap); + #endif diff --git a/src/H5Gshad.c b/src/H5Gshad.c new file mode 100644 index 0000000..5de4b29 --- /dev/null +++ b/src/H5Gshad.c @@ -0,0 +1,460 @@ +/* + * Copyright (C) 1997 National Center for Supercomputing Applications. + * All rights reserved. + * + * Programmer: Robb Matzke + * Thursday, September 18, 1997 + */ +#define H5G_PACKAGE /*suppress error message about including H5Gpkg.h*/ + +#include /*library */ +#include /*error handling */ +#include /*symbol tables */ +#include /*heap functions */ +#include /*memory management */ +#include /*object header messages */ + +#define PABLO_MASK H5G_shadow_mask + +/* Is the interface initialized? */ +static hbool_t interface_initialize_g = FALSE; + +/* Shadow hash table */ +#define H5G_NSHADOWS 10331 + +typedef struct H5G_hash_t { + haddr_t dir_addr; + H5G_shadow_t *head; + struct H5G_hash_t *next; + struct H5G_hash_t *prev; +} H5G_hash_t; + +static H5G_hash_t *H5G_shadow_g[H5G_NSHADOWS]; + + + +/*------------------------------------------------------------------------- + * Function: H5G_shadow_p + * + * Purpose: Determines if ENT is a shadow or a real symbol table entry. + * + * Return: Success: Non-zero if ENT is a shadow; zero otherwise. + * + * Failure: FALSE + * + * Programmer: Robb Matzke + * Thursday, September 18, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +hbool_t +H5G_shadow_p (H5G_entry_t *ent) +{ + H5G_shadow_t tmp; + size_t delta = (char*)&(tmp.entry) - (char*)&tmp; + hbool_t ret_value = FALSE; + + FUNC_ENTER (H5G_shadow_p, NULL, FALSE); + + if (!ent || !ent->shadow) return FALSE; + ret_value = ((char*)ent - (char*)(ent->shadow) == delta); + + FUNC_LEAVE (ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_shadow_dissociate + * + * Purpose: Removes the association between a shadow and its entry or an + * entry and its shadow. The ENT argument can be a shadow or a + * cached entry. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Thursday, September 18, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_shadow_dissociate (H5G_entry_t *ent) +{ + FUNC_ENTER (H5G_shadow_dissociate, NULL, FAIL); + + if (H5G_shadow_p (ent)) { + if (ent->shadow->main) { + ent->shadow->main->shadow = NULL; + ent->shadow->main = NULL; + } + } else if (ent && ent->shadow) { + ent->shadow->main = NULL; + ent->shadow = NULL; + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_shadow_sync + * + * Purpose: Synchronizes a shadow with an entry by copying the + * shadow contents to the entry if the shadow is dirty, + * and then clearing the shadow dirty bit. You may call this + * function with either a shadow or a real entry. + * + * If ENT is a shadow, then the shadow is synchronized only if + * the entry is currently cached. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Thursday, September 18, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_shadow_sync (H5G_entry_t *ent) +{ + H5G_shadow_t *shadow = NULL; + FUNC_ENTER (H5G_shadow_sync, NULL, FAIL); + + /* + * If the caller supplied us with a shadow instead of the main entry, then + * adjust the arguments. + */ + if (H5G_shadow_p (ent)) { + shadow = ent->shadow; + ent = shadow->main; + } else { + shadow = ent->shadow; + } + + if (shadow && shadow->entry.dirty) { + if (!ent) { + /* Main entry is not cached */ + HRETURN_ERROR (H5E_SYM, H5E_NOTCACHED, FAIL); + } + *ent = shadow->entry; + shadow->entry.dirty = FALSE; + } + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_shadow_list + * + * Purpose: Returns a doubly linked list of shadows for the symbol + * table whose header address is DIR_ADDR. + * + * Return: Success: Ptr shadow list or null. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Wednesday, September 17, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +H5G_shadow_t * +H5G_shadow_list (haddr_t dir_addr) +{ + uintn idx = dir_addr % H5G_NSHADOWS; + H5G_hash_t *bucket = NULL; + + FUNC_ENTER (H5G_shadows, NULL, NULL); + + for (bucket=H5G_shadow_g[idx]; bucket; bucket=bucket->next) { + if (bucket->dir_addr==dir_addr) { + HRETURN (bucket->head); + } + } + FUNC_LEAVE (NULL); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_shadow_assoc_node + * + * Purpose: Given a new symbol table node and a symbol table header + * address, associate entries in that node with their shadow if + * they have one. + * + * SYM must be an uncached or protected symbol table node. + * + * Return: Success: SUCCEED + * + * Failure: FAIL, if an error occurs then none of the + * entries are associated with shadows. + * + * Programmer: Robb Matzke + * Wednesday, September 17, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, H5G_entry_t *self) +{ + H5G_shadow_t *shadow = NULL; + H5O_stab_t stab; + const char *s = NULL; + intn i = 0; + + FUNC_ENTER (H5G_shadow_assoc_node, NULL, FAIL); + + /* Check arguments */ + assert (f); /* The file */ + assert (sym); /* The symbol table node */ + assert (self); /* The symbol table header info */ + + if ((shadow=H5G_shadow_list (self->header))) { + + /* We need the heap address so we can see the symbol names */ + if (NULL==H5O_read (f, self->header, self, H5O_NAME, 0, &stab)) { + HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL); + } + + while (insyms && shadow) { + + /* Advance the Entry ptr until it gets to the next shadow. */ + while (insyms && + (s=H5H_peek (f, stab.heap_addr, sym->entry[i].name_off)) && + strcmp (s, shadow->name)<0) i++; + + /* Advance the Shadow ptr until it gets to the next entry. */ + while (insyms && s && shadow && + strcmp (s, shadow->name)>0) shadow = shadow->next; + + /* Did we find a match? */ + if (insyms && s && shadow && !strcmp (s, shadow->name)) { + shadow->main = sym->entry + i; + sym->entry[i].shadow = shadow; + } + } + } + + FUNC_LEAVE (SUCCEED); +} + + + +/*------------------------------------------------------------------------- + * Function: H5G_shadow_open + * + * Purpose: Given a handle to an already open object, or given a + * pointer to the cached symbol table entry for that + * object, open the object (again) and return a handle + * to it. + * + * Return: Success: Handle to open object + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Thursday, September 18, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +H5G_entry_t * +H5G_shadow_open (hdf5_file_t *f, H5G_entry_t *dir, H5G_entry_t *ent) +{ + H5G_shadow_t *shadow = NULL; + H5O_stab_t stab; + const char *s = NULL; + H5G_hash_t *hash = NULL; + H5G_shadow_t *hash_ent = NULL; + uintn idx; + H5O_name_t name_mesg = {NULL}; + H5G_entry_t *ret_value = NULL; + + FUNC_ENTER (H5G_shadow_open, NULL, NULL); + + /* check args */ + assert (f); + assert (dir); + assert (ent); + + if (ent->shadow) { + /* + * Object is already open. Open it again. + */ + ent->shadow->nrefs += 1; + HRETURN (ent); + + } else { + shadow = H5MM_xcalloc (1, sizeof(H5G_shadow_t)); + + if (ent==f->root_sym && dir->header<=0) { + /* + * We're opening the root entry. + */ + if (H5O_read (f, NO_ADDR, ent, H5O_NAME, 0, &name_mesg)) { + shadow->name = H5MM_xstrdup (name_mesg.s); + H5O_reset (H5O_NAME, &name_mesg); + } else { + shadow->name = H5MM_xstrdup ("Root Object"); + } + + } else { + /* + * Some entry other than the root. + */ + if (NULL==H5O_read (f, NO_ADDR, dir, H5O_STAB, 0, &stab)) { + HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); + } + if (NULL==(s=H5H_peek (f, stab.heap_addr, ent->name_off))) { + HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); + } + shadow->name = H5MM_xstrdup (s); + } + + /* + * Build the new shadow. + */ + ent->shadow = shadow; + shadow->main = ent; + shadow->nrefs = 1; + shadow->entry = *ent; + shadow->entry.dirty = FALSE; + shadow->dir_addr = dir->header; + + /* + * Link it into the shadow heap + */ + idx = dir->header % H5G_NSHADOWS; + for (hash=H5G_shadow_g[idx]; hash; hash=hash->next) { + if (hash->dir_addr==dir->header) break; + } + if (!hash) { + hash = H5MM_xcalloc (1, sizeof(H5G_hash_t)); + hash->dir_addr = dir->header; + hash->next = H5G_shadow_g[idx]; + H5G_shadow_g[idx] = hash; + } + for (hash_ent=hash->head; hash_ent; hash_ent=hash_ent->next) { + if (strcmp (shadow->name, hash_ent->name)<0) break; + } + if (hash_ent) { + if (hash_ent->prev) hash_ent->prev->next = shadow; + else hash->head = shadow; + shadow->prev = hash_ent->prev; + shadow->next = hash_ent; + hash_ent->prev = shadow; + } else { + hash->head = shadow; + } + } + + ret_value = &(shadow->entry); + + done: + if (!ret_value) { + if (shadow) { + H5MM_xfree (shadow->name); + H5MM_xfree (shadow); + } + } + + FUNC_LEAVE (ret_value); +} + + + +/*------------------------------------------------------------------------- + * Function: H5G_shadow_close + * + * Purpose: Closes an open object. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Thursday, September 18, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_shadow_close (hdf5_file_t *f, H5G_entry_t *ent) +{ + uintn idx; + H5G_hash_t *hash=NULL; + H5G_shadow_t *hash_ent=NULL, *shadow=NULL; + + FUNC_ENTER (H5G_shadow_close, NULL, FAIL); + + /* check args */ + assert (ent); + assert (H5G_shadow_p (ent)); + assert (ent->shadow->nrefs>0); + shadow = ent->shadow; + + /* clean the shadow */ + if (1==shadow->nrefs && ent->dirty) { + if (!shadow->main && + NULL==H5G_stab_find (f, shadow->dir_addr, NULL, shadow->name)) { + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); + } + assert (shadow->main); + *(shadow->main) = *ent; + ent->dirty = FALSE; + } + + /* close */ + shadow->nrefs -= 1; + + if (0==shadow->nrefs) { + /* dissociate shadow and entry */ + H5G_shadow_dissociate (ent); + + /* find symtabs shadow list */ + idx = shadow->dir_addr % H5G_NSHADOWS; + for (hash=H5G_shadow_g[idx]; hash; hash=hash->next) { + if (hash->dir_addr==shadow->dir_addr) break; + } + assert (hash); + + /* find shadow in shadow list */ + for (hash_ent=hash->head; hash_ent; hash_ent=hash_ent->next) { + if (hash_ent==shadow) break; + } + assert (hash_ent); + + /* remove shadow from shadow list */ + if (hash_ent->prev) hash_ent->prev->next = hash_ent->next; + else hash->head = hash_ent->next; + if (hash_ent->next) hash_ent->next->prev = hash_ent->prev; + H5MM_xfree (shadow->name); + H5MM_xfree (shadow); + + /* remove symtab's shadow list if empty */ + if (!hash->head) { + if (hash->prev) hash->prev->next = hash->next; + else H5G_shadow_g[idx] = hash->next; + if (hash->next) hash->next->prev = hash->prev; + H5MM_xfree (hash); + } + } + + FUNC_LEAVE (SUCCEED); +} diff --git a/src/H5H.c b/src/H5H.c index dc0a10c..8afcea4 100644 --- a/src/H5H.c +++ b/src/H5H.c @@ -45,7 +45,7 @@ typedef struct H5H_t { } H5H_t; /* PRIVATE PROTOTYPES */ -static H5H_t *H5H_load (hdf5_file_t *f, haddr_t addr, const void *udata); +static H5H_t *H5H_load (hdf5_file_t *f, haddr_t addr, void *udata); static herr_t H5H_flush (hdf5_file_t *f, hbool_t dest, haddr_t addr, H5H_t *heap); @@ -53,7 +53,7 @@ static herr_t H5H_flush (hdf5_file_t *f, hbool_t dest, haddr_t addr, * H5H inherits cache-like properties from H5AC */ static const H5AC_class_t H5AC_HEAP[1] = {{ - (void*(*)(hdf5_file_t*,haddr_t,const void*))H5H_load, + (void*(*)(hdf5_file_t*,haddr_t,void*))H5H_load, (herr_t(*)(hdf5_file_t*,hbool_t,haddr_t,void*))H5H_flush, }}; @@ -162,12 +162,13 @@ H5H_new (hdf5_file_t *f, H5H_type_t heap_type, size_t size_hint) *------------------------------------------------------------------------- */ static H5H_t * -H5H_load (hdf5_file_t *f, haddr_t addr, const void *udata) +H5H_load (hdf5_file_t *f, haddr_t addr, void *udata) { uint8 hdr[20], *p; H5H_t *heap=NULL; H5H_free_t *fl=NULL, *tail=NULL; haddr_t free_block=H5H_FREE_NULL; + H5H_t *ret_value=NULL; FUNC_ENTER (H5H_load, NULL, NULL); @@ -184,7 +185,9 @@ H5H_load (hdf5_file_t *f, haddr_t addr, const void *udata) heap = H5MM_xcalloc (1, sizeof(H5H_t)); /* magic number */ - if (HDmemcmp (hdr, H5H_MAGIC, H5H_SIZEOF_MAGIC)) goto error; + if (HDmemcmp (hdr, H5H_MAGIC, H5H_SIZEOF_MAGIC)) { + HGOTO_ERROR (H5E_HEAP, H5E_CANTLOAD, NULL); + } p += H5H_SIZEOF_MAGIC; /* heap data size */ @@ -194,7 +197,7 @@ H5H_load (hdf5_file_t *f, haddr_t addr, const void *udata) /* free list head */ H5F_decode_offset (f, p, free_block); if (-1!=free_block && (free_block<0 || free_block>=heap->disk_alloc)) { - goto error; + HGOTO_ERROR (H5E_HEAP, H5E_CANTLOAD, NULL); } /* data */ @@ -203,12 +206,14 @@ H5H_load (hdf5_file_t *f, haddr_t addr, const void *udata) if (heap->disk_alloc && H5F_block_read (f, heap->addr, heap->disk_alloc, heap->chunk + H5H_SIZEOF_HDR(f))<0) { - goto error; + HGOTO_ERROR (H5E_HEAP, H5E_CANTLOAD, NULL); } /* free list */ while (H5H_FREE_NULL!=free_block) { - if (free_block<0 || free_block>=heap->disk_alloc) goto error; + if (free_block<0 || free_block>=heap->disk_alloc) { + HGOTO_ERROR (H5E_HEAP, H5E_CANTLOAD, NULL); + } fl = H5MM_xmalloc (sizeof (H5H_free_t)); fl->offset = free_block; fl->prev = tail; @@ -221,14 +226,15 @@ H5H_load (hdf5_file_t *f, haddr_t addr, const void *udata) H5F_decode_offset (f, p, free_block); H5F_decode_length (f, p, fl->size); - if (fl->offset + fl->size > heap->disk_alloc) goto error; + if (fl->offset + fl->size > heap->disk_alloc) { + HGOTO_ERROR (H5E_HEAP, H5E_CANTLOAD, NULL); + } } - FUNC_LEAVE (heap); + ret_value = heap; - -error: - if (heap) { + done: + if (!ret_value && heap) { heap->chunk = H5MM_xfree (heap->chunk); H5MM_xfree (heap); for (fl=heap->freelist; fl; fl=tail) { @@ -236,7 +242,8 @@ error: H5MM_xfree (fl); } } - HRETURN_ERROR (H5E_HEAP, H5E_CANTLOAD, NULL); + + FUNC_LEAVE (ret_value); } @@ -462,9 +469,10 @@ H5H_peek (hdf5_file_t *f, haddr_t addr, off_t offset) /*------------------------------------------------------------------------- * Function: H5H_remove_free * - * Purpose: Removes free list element FL from the specified heap. + * Purpose: Removes free list element FL from the specified heap and + * frees it. * - * Return: void + * Return: NULL * * Programmer: Robb Matzke * matzke@llnl.gov @@ -474,13 +482,14 @@ H5H_peek (hdf5_file_t *f, haddr_t addr, off_t offset) * *------------------------------------------------------------------------- */ -static void +static H5H_free_t * H5H_remove_free (H5H_t *heap, H5H_free_t *fl) { if (fl->prev) fl->prev->next = fl->next; if (fl->next) fl->next->prev = fl->prev; if (!fl->prev) heap->freelist = fl->next; + return H5MM_xfree (fl); } @@ -545,7 +554,7 @@ H5H_insert (hdf5_file_t *f, haddr_t addr, size_t buf_size, const void *buf) break; } else if (fl->size==need) { offset = fl->offset; - H5H_remove_free (heap, fl); + fl = H5H_remove_free (heap, fl); break; } else if (!max_fl || max_fl->offset < fl->offset) { max_fl = fl; @@ -582,7 +591,7 @@ H5H_insert (hdf5_file_t *f, haddr_t addr, size_t buf_size, const void *buf) } } #endif - H5H_remove_free (heap, max_fl); + max_fl = H5H_remove_free (heap, max_fl); } } else { @@ -762,7 +771,7 @@ H5H_remove (hdf5_file_t *f, haddr_t addr, off_t offset, size_t size) if (fl2->offset + fl2->size == fl->offset) { fl->offset = fl2->offset; fl->size += fl2->size; - H5H_remove_free (heap, fl2); + fl2 = H5H_remove_free (heap, fl2); HRETURN (SUCCEED); } } @@ -774,7 +783,7 @@ H5H_remove (hdf5_file_t *f, haddr_t addr, off_t offset, size_t size) while (fl2) { if (fl->offset + fl->size == fl2->offset) { fl->size += fl2->size; - H5H_remove_free (heap, fl2); + fl2 = H5H_remove_free (heap, fl2); HRETURN (SUCCEED); } } diff --git a/src/H5MM.c b/src/H5MM.c index 39da6d7..eb9c76e 100644 --- a/src/H5MM.c +++ b/src/H5MM.c @@ -168,6 +168,16 @@ H5MM_xstrdup (const char *s) void * H5MM_xfree (const void *mem) { - if (mem) HDfree (mem); + /* + * free(3) takes a non-const pointer as an argument even though + * conceptually the argument could be a constant because by time + * free() mucks with it's contents, it should already be free :-) + * Instead of passing a const arg to free, which generates a + * compiler warning, we cast it to a non-const arg first. With + * gcc, this results in a warning only if -Wcast-qual is turned on. + */ + void *non_const_mem = mem; + + if (mem) HDfree (non_const_mem); return NULL; } diff --git a/src/H5O.c b/src/H5O.c index 75a5993..8509e41 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -27,7 +27,7 @@ /* PRIVATE PROTOTYPES */ static herr_t H5O_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5O_t *oh); -static H5O_t *H5O_load (hdf5_file_t *f, haddr_t addr, const void *_data); +static H5O_t *H5O_load (hdf5_file_t *f, haddr_t addr, void *_data); static intn H5O_find_in_ohdr (hdf5_file_t *f, haddr_t addr, const H5O_class_t **type_p, intn sequence); static intn H5O_alloc (hdf5_file_t *f, H5O_t *oh, const H5O_class_t *type, @@ -37,7 +37,7 @@ static intn H5O_alloc_new_chunk (hdf5_file_t *f, H5O_t *oh, size_t size); /* H5O inherits cache-like properties from H5AC */ static const H5AC_class_t H5AC_OHDR[1] = {{ - (void*(*)(hdf5_file_t*,haddr_t,const void*))H5O_load, + (void*(*)(hdf5_file_t*,haddr_t,void*))H5O_load, (herr_t(*)(hdf5_file_t*,hbool_t,haddr_t,void*))H5O_flush, }}; @@ -166,7 +166,7 @@ H5O_new (hdf5_file_t *f, intn nlink, size_t size_hint) *------------------------------------------------------------------------- */ static H5O_t * -H5O_load (hdf5_file_t *f, haddr_t addr, const void *_data) +H5O_load (hdf5_file_t *f, haddr_t addr, void *_data) { H5O_t *oh = NULL; H5O_t *ret_value = (void*)1; /*kludge for HGOTO_ERROR*/ @@ -509,8 +509,9 @@ H5O_link (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, intn adjust) /* check args */ assert (f); - assert (addr>=0); - + assert (addr>0 || (ent && ent->header>0)); + if (addr<=0) addr = ent->header; + /* get header */ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) { HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, FAIL); @@ -528,9 +529,11 @@ H5O_link (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, intn adjust) } } else { oh->nlink += adjust; - if (oh->nlink>1 && ent) ent->type = H5G_NOTHING_CACHED; + if (oh->nlink>1 && ent && H5G_NOTHING_CACHED!=ent->type) { + ent->dirty = TRUE; + ent->type = H5G_NOTHING_CACHED; + } } - oh->dirty = TRUE; FUNC_LEAVE (oh->nlink); @@ -570,7 +573,10 @@ H5O_read (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, /* check args */ assert (f); - assert (addr>=0); + if (addr<=0 && (!ent || ent->header<=0)) { + HRETURN_ERROR (H5E_OHDR, H5E_NOTFOUND, NULL); + } + if (addr<=0) addr = ent->header; assert (sequence>=0); /* can we get it from the symbol table? */ @@ -585,6 +591,10 @@ H5O_read (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, HRETURN_ERROR (H5E_OHDR, H5E_NOTFOUND, NULL); } +#ifdef LATER + /* should we cache it in ENT? */ +#endif + /* copy the message to the user-supplied buffer */ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) { HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, NULL); @@ -692,7 +702,7 @@ H5O_peek (hdf5_file_t *f, haddr_t addr, const H5O_class_t *type, /* check args */ assert (f); - assert (addr>=0); + assert (addr>0); if ((idx = H5O_find_in_ohdr (f, addr, &type, sequence))<0) { HRETURN_ERROR (H5E_OHDR, H5E_NOTFOUND, NULL); @@ -709,17 +719,20 @@ H5O_peek (hdf5_file_t *f, haddr_t addr, const H5O_class_t *type, * Function: H5O_modify * * Purpose: Modifies an existing message or creates a new message. - * The object header is at file address ADDR of file F. An + * The object header is at file address ADDR of file F (but if + * ENT is present then its `header' field is used instead). An * optional symbol table entry ENT can be supplied in which * case the cache fields in that symbol table are updated if - * appropriate. If the symbol table entry changes then the - * optional ENT_MODIFIED arg will point to a non-zero value, - * otherwise ENT_MODIFIED isn't changed. + * appropriate. * * The OVERWRITE argument is either a sequence number of a * message to overwrite (usually zero) or the constant * H5O_NEW_MESSAGE (-1) to indicate that a new message is to - * be created. + * be created. If the message to overwrite doesn't exist then + * it is created (but only if it can be inserted so its sequence + * number is OVERWRITE; that is, you can create a message with + * the sequence number 5 if there is no message with sequence + * number 4). * * Return: Success: The sequence number of the message that * was modified or created. @@ -736,8 +749,7 @@ H5O_peek (hdf5_file_t *f, haddr_t addr, const H5O_class_t *type, */ intn H5O_modify (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, - hbool_t *ent_modified, const H5O_class_t *type, - intn overwrite, const void *mesg) + const H5O_class_t *type, intn overwrite, const void *mesg) { H5O_t *oh = NULL; intn idx, sequence; @@ -747,10 +759,11 @@ H5O_modify (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, /* check args */ assert (f); - assert (addr>=0); + assert (addr>0 || (ent && ent->header>0)); assert (type); assert (mesg); - + if (addr<=0) addr = ent->header; + if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) { HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, FAIL); } @@ -764,7 +777,13 @@ H5O_modify (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, /* Was the right message found? */ if (overwrite>=0 && (idx>=oh->nmesgs || sequence!=overwrite)) { - HRETURN_ERROR (H5E_OHDR, H5E_NOTFOUND, FAIL); /*message not found*/ + + /* But can we insert a new one with this sequence number? */ + if (overwrite==sequence+1) { + overwrite = -1; + } else { + HRETURN_ERROR (H5E_OHDR, H5E_NOTFOUND, FAIL); /*message not found*/ + } } /* Allocate space for the new message */ @@ -787,7 +806,7 @@ H5O_modify (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, /* Copy into the symbol table entry */ if (oh->nlink<=1 && ent && type->cache) { hbool_t modified = (type->cache)(ent, mesg); - if (modified && ent_modified) *ent_modified = modified; + if (ent && !ent->dirty) ent->dirty = modified; } FUNC_LEAVE (sequence); @@ -826,7 +845,7 @@ H5O_modify (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, */ herr_t H5O_remove (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, - hbool_t *ent_modified, const H5O_class_t *type, intn sequence) + const H5O_class_t *type, intn sequence) { H5O_t *oh = NULL; intn i, seq; @@ -835,8 +854,9 @@ H5O_remove (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, /* check args */ assert (f); - assert (addr>=0); + assert (addr>0 || (ent && ent->header>0)); assert (type); + if (addr<=0) addr = ent->header; /* load the object header */ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) { @@ -848,9 +868,9 @@ H5O_remove (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, if (seq++ == sequence || H5O_ALL==sequence) { /* clear symbol table entry cache */ - if (ent && type->cache && H5G_NOTHING_CACHED!=ent->type) { + if (ent && type->cache && type->cache_type==ent->type) { ent->type = H5G_NOTHING_CACHED; - if (ent_modified) *ent_modified = TRUE; + ent->dirty = TRUE; } /* change message type to nil and zero it */ @@ -922,9 +942,14 @@ H5O_alloc_extend_chunk (H5O_t *oh, intn chunkno, size_t size) oh->mesg[idx].raw_size += delta; old_addr = oh->chunk[chunkno].image; - oh->chunk[chunkno].size += delta; + + /* Be careful not to indroduce garbage */ oh->chunk[chunkno].image = H5MM_xrealloc (old_addr, - oh->chunk[chunkno].size); + (oh->chunk[chunkno].size + + delta)); + HDmemset (oh->chunk[chunkno].image + oh->chunk[chunkno].size, + 0, delta); + oh->chunk[chunkno].size += delta; /* adjust raw addresses for messages of this chunk */ if (old_addr != oh->chunk[chunkno].image) { @@ -1071,7 +1096,7 @@ H5O_alloc_new_chunk (hdf5_file_t *f, H5O_t *oh, size_t size) oh->chunk[chunkno].dirty = TRUE; oh->chunk[chunkno].addr = H5O_NO_ADDR; oh->chunk[chunkno].size = size; - oh->chunk[chunkno].image = p = H5MM_xmalloc (size); + oh->chunk[chunkno].image = p = H5MM_xcalloc (1, size); /* * Make sure we have enough space for all possible new messages diff --git a/src/H5Ocont.c b/src/H5Ocont.c index 2f8bb58..2b01838 100644 --- a/src/H5Ocont.c +++ b/src/H5Ocont.c @@ -36,6 +36,7 @@ const H5O_class_t H5O_CONT[1] = {{ H5O_CONT_ID, /*message id number */ "hdr continuation", /*message name for debugging */ sizeof (H5O_cont_t), /*native message size */ + H5G_NOTHING_CACHED, /*symbol table type field */ H5O_cont_decode, /*decode message */ H5O_cont_encode, /*encode message */ NULL, /*no fast method */ diff --git a/src/H5Oname.c b/src/H5Oname.c index cec5d34..6224401 100644 --- a/src/H5Oname.c +++ b/src/H5Oname.c @@ -36,6 +36,7 @@ const H5O_class_t H5O_NAME[1] = {{ H5O_NAME_ID, /*message id number */ "name", /*message name for debugging */ sizeof (H5O_name_t), /*native message size */ + H5G_NOTHING_CACHED, /*symbol table entry type field */ H5O_name_decode, /*decode message */ H5O_name_encode, /*encode message */ NULL, /*no stab entry fields */ diff --git a/src/H5Onull.c b/src/H5Onull.c index 467e26a..25579f0 100644 --- a/src/H5Onull.c +++ b/src/H5Onull.c @@ -24,6 +24,7 @@ const H5O_class_t H5O_NULL[1] = {{ H5O_NULL_ID, /*message id number */ "null", /*message name for debugging */ 0, /*native message size */ + H5G_NOTHING_CACHED, /*symtab entry `type' field */ NULL, /*no decode method */ NULL, /*no encode method */ NULL, /*no fast method */ diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 4d11e9b..30b0af1 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -47,6 +47,7 @@ typedef struct H5O_class_t { intn id; /*message type ID on disk */ const char *name; /*message name for debugging */ size_t native_size; /*size of native message */ + H5G_type_t cache_type; /*type field in symbol table */ void *(*decode)(hdf5_file_t*,size_t,const uint8*); herr_t (*encode)(hdf5_file_t*,size_t,uint8*,const void*); void *(*fast)(const H5G_entry_t*, void*); /*get from stab ent*/ @@ -163,11 +164,9 @@ void *H5O_read (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, const void *H5O_peek (hdf5_file_t *f, haddr_t addr, const H5O_class_t *type, intn sequence); intn H5O_modify (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, - hbool_t *ent_modified, const H5O_class_t *type, - intn overwrite, const void *mesg); + const H5O_class_t *type, intn overwrite, const void *mesg); herr_t H5O_remove (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, - hbool_t *ent_modified, const H5O_class_t *type, - intn sequence); + const H5O_class_t *type, intn sequence); herr_t H5O_reset (const H5O_class_t *type, void *native); herr_t H5O_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, intn fwidth); diff --git a/src/H5Osdim.c b/src/H5Osdim.c index 80b9735..923ceea 100644 --- a/src/H5Osdim.c +++ b/src/H5Osdim.c @@ -53,6 +53,7 @@ const H5O_class_t H5O_SIM_DIM[1] = {{ H5O_SIM_DIM_ID, /* message id number */ "sim_dim", /* message name for debugging */ sizeof (H5O_sim_dim_t), /* native message size */ + H5G_CACHED_SDATA, /* symtab entry `type' field */ H5O_sim_dim_decode, /* decode message */ H5O_sim_dim_encode, /* encode message */ H5O_sim_dim_fast, /* get message from stab entry */ diff --git a/src/H5Osdtyp.c b/src/H5Osdtyp.c index 19af66b..8920625 100644 --- a/src/H5Osdtyp.c +++ b/src/H5Osdtyp.c @@ -50,16 +50,17 @@ static herr_t H5O_sim_dtype_debug (hdf5_file_t *f, const void *_mesg, /* This message derives from H5O */ const H5O_class_t H5O_SIM_DTYPE[1] = {{ - H5O_SIM_DTYPE_ID, /* message id number */ - "sim_dtype", /* message name for debugging */ - sizeof (H5O_sim_dtype_t), /* native message size */ + H5O_SIM_DTYPE_ID, /* message id number */ + "sim_dtype", /* message name for debugging */ + sizeof (H5O_sim_dtype_t), /* native message size */ + H5G_CACHED_SDATA, /* symtab entry `type' field */ H5O_sim_dtype_decode, /* decode message */ H5O_sim_dtype_encode, /* encode message */ H5O_sim_dtype_fast, /* get message from stab entry */ H5O_sim_dtype_cache, /* put message into stab entry */ H5O_sim_dtype_copy, /* copy the native value */ H5O_sim_dtype_size, /* size of symbol table entry */ - NULL, /* default reset method */ + NULL, /* default reset method */ H5O_sim_dtype_debug, /* debug the message */ }}; diff --git a/src/H5Ostab.c b/src/H5Ostab.c index 1710fe3..0b67a73 100644 --- a/src/H5Ostab.c +++ b/src/H5Ostab.c @@ -38,6 +38,7 @@ const H5O_class_t H5O_STAB[1] = {{ H5O_STAB_ID, /*message id number */ "stab", /*message name for debugging */ sizeof (H5O_stab_t), /*native message size */ + H5G_CACHED_STAB, /*symtab entry `type' field */ H5O_stab_decode, /*decode message */ H5O_stab_encode, /*encode message */ H5O_stab_fast, /*get message from stab entry */ diff --git a/src/H5Ostdst.c b/src/H5Ostdst.c index 85da813..0186b44 100644 --- a/src/H5Ostdst.c +++ b/src/H5Ostdst.c @@ -51,6 +51,7 @@ const H5O_class_t H5O_STD_STORE[1] = {{ H5O_STD_STORE_ID, /* message id number */ "std_store", /* message name for debugging */ sizeof (H5O_std_store_t),/* native message size */ + H5G_NOTHING_CACHED, /* symtab entry `type' field */ H5O_std_store_decode, /* decode message */ H5O_std_store_encode, /* encode message */ NULL, /* get message from stab entry */ diff --git a/src/H5private.h b/src/H5private.h index 070dca9..f13ff59 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -101,6 +101,7 @@ * File offsets. */ typedef off_t haddr_t; +#define NO_ADDR (-1) /* * Some compilers have problems declaring auto variables that point @@ -402,7 +403,7 @@ typedef off_t haddr_t; extern hbool_t library_initialize_g; /*good thing C's lazy about extern!*/ extern hbool_t thread_initialize_g; /*don't decl interface_initialize_g */ -#define FUNC_ENTER(func_name,interface_init_func,err) \ +#define FUNC_ENTER(func_name,interface_init_func,err) { \ CONSTR (FUNC, #func_name); \ PABLO_SAVE (ID_ ## func_name); \ \ @@ -428,8 +429,8 @@ extern hbool_t thread_initialize_g; /*don't decl interface_initialize_g */ ((herr_t(*)(void))interface_init_func)()<0) { \ HRETURN_ERROR (H5E_FUNC, H5E_CANTINIT, err); \ } \ - } - + } \ + { /*------------------------------------------------------------------------- @@ -447,7 +448,7 @@ extern hbool_t thread_initialize_g; /*don't decl interface_initialize_g */ * *------------------------------------------------------------------------- */ -#define FUNC_LEAVE(return_value) HRETURN(return_value) +#define FUNC_LEAVE(return_value) HRETURN(return_value)}} /* * The FUNC_ENTER() and FUNC_LEAVE() macros make calls to Pablo functions diff --git a/src/Makefile.in b/src/Makefile.in index d77a356..0a66e9d 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -15,8 +15,9 @@ PROGS=debug # Source and object files for the library (lexicographically)... LIB_SRC=H5.c H5A.c H5AC.c H5B.c H5C.c H5D.c H5Dconv.c H5E.c H5F.c H5G.c \ - H5Gnode.c H5H.c H5M.c H5MF.c H5MM.c H5O.c H5Ocont.c H5Oname.c \ - H5Onull.c H5Osdtyp.c H5Osdim.c H5Ostab.c H5Ostdst.c H5P.c H5T.c + H5Gnode.c H5Gshad.c H5H.c H5M.c H5MF.c H5MM.c H5O.c H5Ocont.c \ + H5Oname.c H5Onull.c H5Osdtyp.c H5Osdim.c H5Ostab.c H5Ostdst.c H5P.c \ + H5T.c LIB_OBJ=$(LIB_SRC:.c=.o) diff --git a/test/Makefile.in b/test/Makefile.in index 339ebc3..8a7d4f0 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -22,6 +22,6 @@ PRIVATE_HDR=testhdf5.h # How to build the programs... testhdf5: $(PROG_OBJ) ../src/libhdf5.a - $(CC) $(CFLAGS) -o $@ $(PROG_OBJ) ../src/libhdf5.a + $(CC) $(CFLAGS) -o $@ $(PROG_OBJ) ../src/libhdf5.a $(LIBS) @CONCLUDE@ diff --git a/test/th5d.c b/test/th5d.c index 604aaef..90e1234 100644 --- a/test/th5d.c +++ b/test/th5d.c @@ -107,7 +107,7 @@ static void test_h5d_basic_write(void) CHECK(ret,FAIL,"H5Tset_type"); did1=H5Mcreate(fid1,H5_DATASET,DATA1_NAME); - CHECK(sid1,FAIL,"H5Mcreate"); + CHECK(did1,FAIL,"H5Mcreate"); ret=H5Dset_info(did1,tid1,sid1); CHECK(ret,FAIL,"H5Dset_info"); diff --git a/test/tohdr.c b/test/tohdr.c index fc19d4e..b3a0b10 100644 --- a/test/tohdr.c +++ b/test/tohdr.c @@ -48,7 +48,6 @@ test_ohdr (void) herr_t status; void *ptr; H5G_entry_t ent; - hbool_t ent_mod; int i; MESSAGE (5, ("Testing Object Headers\n")); @@ -69,7 +68,7 @@ test_ohdr (void) MESSAGE (8, ("Creating new message...\n")); stab.btree_addr = 11111111; stab.heap_addr = 22222222; - status = H5O_modify (f, oh, NULL, NULL, H5O_STAB, H5O_NEW_MESG, &stab); + status = H5O_modify (f, oh, NULL, H5O_STAB, H5O_NEW_MESG, &stab); VERIFY (status, 0, "H5O_modify"); H5AC_flush (f, NULL, 0, TRUE); @@ -85,7 +84,7 @@ test_ohdr (void) MESSAGE (8, ("Modifying message...\n")); stab.btree_addr = 33333333; stab.heap_addr = 44444444; - status = H5O_modify (f, oh, NULL, NULL, H5O_STAB, 0, &stab); + status = H5O_modify (f, oh, NULL, H5O_STAB, 0, &stab); VERIFY (status, 0, "H5O_modify"); H5AC_flush (f, NULL, 0, TRUE); @@ -102,11 +101,12 @@ test_ohdr (void) MESSAGE (8, ("Creating a duplicate message...\n")); ent.header = 0; ent.type = H5G_NOTHING_CACHED; + ent.dirty = FALSE; stab.btree_addr = 55555555; stab.heap_addr = 66666666; - status = H5O_modify (f, oh, &ent, &ent_mod, H5O_STAB, H5O_NEW_MESG, &stab); + status = H5O_modify (f, oh, &ent, H5O_STAB, H5O_NEW_MESG, &stab); VERIFY (status, 1, "H5O_modify"); - VERIFY (ent_mod, TRUE, "H5O_modify"); + VERIFY (ent.dirty, TRUE, "H5O_modify"); VERIFY (ent.type, H5G_CACHED_STAB, "H5O_modify"); VERIFY (ent.cache.stab.heap_addr, stab.heap_addr, "H5O_modify"); VERIFY (ent.cache.stab.btree_addr, stab.btree_addr, "H5O_modify"); @@ -122,11 +122,12 @@ test_ohdr (void) * Test modification of the second message with a symbol table. */ MESSAGE (8, ("Modifying the duplicate message...\n")); + ent.dirty = FALSE; stab.btree_addr = 77777777; stab.heap_addr = 88888888; - status = H5O_modify (f, oh, &ent, &ent_mod, H5O_STAB, 1, &stab); + status = H5O_modify (f, oh, &ent, H5O_STAB, 1, &stab); VERIFY (status, 1, "H5O_modify"); - VERIFY (ent_mod, TRUE, "H5O_modify"); + VERIFY (ent.dirty, TRUE, "H5O_modify"); VERIFY (ent.type, H5G_CACHED_STAB, "H5O_modify"); VERIFY (ent.cache.stab.heap_addr, stab.heap_addr, "H5O_modify"); VERIFY (ent.cache.stab.btree_addr, stab.btree_addr, "H5O_modify"); @@ -146,7 +147,7 @@ test_ohdr (void) for (i=0; i<40; i++) { stab.btree_addr = (i+1)*1000 + 1; stab.heap_addr = (i+1)*1000 + 2; - status = H5O_modify (f, oh, NULL, NULL, H5O_STAB, H5O_NEW_MESG, &stab); + status = H5O_modify (f, oh, NULL, H5O_STAB, H5O_NEW_MESG, &stab); VERIFY (status, 2+i, "H5O_modify"); } H5AC_flush (f, NULL, 0, TRUE); @@ -159,7 +160,7 @@ test_ohdr (void) for (i=0; i<10; i++) { stab.btree_addr = (i+1)*1000 + 10; stab.heap_addr = (i+1)*1000 + 20; - status = H5O_modify (f, oh, NULL, NULL, H5O_STAB, H5O_NEW_MESG, &stab); + status = H5O_modify (f, oh, NULL, H5O_STAB, H5O_NEW_MESG, &stab); VERIFY (status, 42+i, "H5O_modify"); H5AC_flush (f, NULL, 0, TRUE); } @@ -167,7 +168,7 @@ test_ohdr (void) /* * Delete all symbol table messages. */ - status = H5O_remove (f, oh, NULL, NULL, H5O_STAB, H5O_ALL); + status = H5O_remove (f, oh, NULL, H5O_STAB, H5O_ALL); CHECK_I (status, "H5O_remove"); /* close the file */ diff --git a/test/tstab.c b/test/tstab.c index 4e6c21e..d525758 100644 --- a/test/tstab.c +++ b/test/tstab.c @@ -65,6 +65,7 @@ test_1 (void) CHECK (f, NULL, "H5Aatom_object"); /* create the object */ + memset (&ent, 0, sizeof(ent)); ent.header = H5O_new (f, 0, 64); CHECK_I (ent.header, "H5O_new"); ent.type = H5G_NOTHING_CACHED; @@ -152,7 +153,7 @@ test_1 (void) CHECK_PTR (status_ptr, "H5O_read"); CHECK_PTR (name_mesg.s, "H5O_read"); VERIFY (strcmp(name_mesg.s, "foo"), 0, "H5O_read"); - + if (status_ptr) H5O_reset (H5O_NAME, &name_mesg); /*free message data*/ /* -- cgit v0.12