diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/H5AC.c | 19 | ||||
-rw-r--r-- | src/H5D.c | 54 | ||||
-rw-r--r-- | src/H5F.c | 39 | ||||
-rw-r--r-- | src/H5Fprivate.h | 2 | ||||
-rw-r--r-- | src/H5G.c | 1126 | ||||
-rw-r--r-- | src/H5Gent.c | 488 | ||||
-rw-r--r-- | src/H5Gnode.c | 156 | ||||
-rw-r--r-- | src/H5Gpkg.h | 39 | ||||
-rw-r--r-- | src/H5Gprivate.h | 60 | ||||
-rw-r--r-- | src/H5Gshad.c | 387 | ||||
-rw-r--r-- | src/H5Gstab.c | 345 | ||||
-rw-r--r-- | src/H5O.c | 53 | ||||
-rw-r--r-- | src/H5Oprivate.h | 6 | ||||
-rw-r--r-- | src/H5Osdim.c | 72 | ||||
-rw-r--r-- | src/H5Osdtyp.c | 57 | ||||
-rw-r--r-- | src/H5Ostab.c | 54 | ||||
-rw-r--r-- | src/Makefile.in | 6 |
17 files changed, 1778 insertions, 1185 deletions
@@ -310,7 +310,8 @@ H5AC_compare (const void *_a, const void *_b) * * Return: Success: SUCCEED * - * Failure: FAIL + * Failure: FAIL if there was a request to flush all + * items and something was protected. * * Programmer: Robb Matzke * matzke@llnl.gov @@ -374,6 +375,14 @@ H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, } map = H5MM_xfree (map); + /* + * If there are protected object then fail. However, everything + * else should have been flushed. + */ + if (f->cache->nprots>0) { + HRETURN_ERROR (H5E_CACHE, H5E_PROTECT, FAIL); + } + } else if ((!type || f->cache->slot[i].type==type) && f->cache->slot[i].addr==addr) { /* @@ -389,14 +398,6 @@ H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, } - /* - * If there are protected objects then fail. However, everything - * else should have been flushed. - */ - if (f->cache->nprots>0) { - HRETURN_ERROR (H5E_CACHE, H5E_PROTECT, FAIL); - } - FUNC_LEAVE (SUCCEED); } @@ -130,7 +130,6 @@ 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; - H5G_entry_t tmp_ent; FUNC_ENTER(H5D_create, H5D_init_interface, FAIL); @@ -153,33 +152,11 @@ hatom_t H5D_create(hatom_t owner_id, hobjtype_t type, const char *name) new_dset->data_addr = -1; /* No data yet */ 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*/ + /* Open (and create) a new file object */ + if (NULL==(new_dset->ent = H5G_create (file, name, H5D_MINHDR_SIZE))) { + HGOTO_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); } - /* - * 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) HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL); @@ -236,22 +213,10 @@ hatom_t H5D_find_name(hatom_t grp_id, hobjtype_t type, const char *name) dset->file = file; 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))) { + /* Open the dataset object */ + if (NULL==(dset->ent=H5G_open (file, 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) @@ -422,7 +387,7 @@ done: herr_t H5Dread(hatom_t oid, hatom_t did, VOIDP buf) { H5D_t *dataset; /* dataset object to do I/O on */ - void *readbuf; /* pointer to buffer to write out */ + void *readbuf=NULL; /* pointer to buffer to write out */ uintn free_buf=0; /* if temporary conversion buffer needs to be free'd */ uintn toread; /* number of bytes to read in */ herr_t ret_value = SUCCEED; @@ -507,7 +472,7 @@ herr_t H5Dwrite(hatom_t oid, hatom_t did, VOIDP buf) { H5D_t *dataset; /* dataset object to do I/O on */ uintn towrite; /* number of bytes to write out */ - void *writebuf; /* pointer to buffer to write out */ + void *writebuf=NULL; /* pointer to buffer to write out */ uintn free_buf=0; /* if temporary conversion buffer needs to be free'd */ herr_t ret_value = SUCCEED; @@ -649,11 +614,6 @@ herr_t H5D_flush(hatom_t oid) } } - /* 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); - } - dataset->dirty = FALSE; /*it's clean now*/ } @@ -395,11 +395,15 @@ H5F_new (void) { hdf5_file_t *f = H5MM_xcalloc (1, sizeof(hdf5_file_t)); - /* Create a cache */ + /* Create a main cache */ H5AC_new (f, H5AC_NSLOTS); + /* Create the shadow hash table */ + f->nshadows = H5G_NSHADOWS; + f->shadow = H5MM_xcalloc (f->nshadows, sizeof(struct H5G_hash_t*)); + /* Create a root symbol slot */ - f->root_sym = H5G_new_entry (); + f->root_sym = H5G_ent_calloc (); return f; } @@ -434,6 +438,8 @@ H5F_dest (hdf5_file_t *f) f->dir = H5MM_xfree (f->dir); f->filename = H5MM_xfree (f->filename); f->root_sym = H5MM_xfree (f->root_sym); + f->nshadows = 0; + f->shadow = H5MM_xfree (f->shadow); H5MM_xfree (f); } return NULL; @@ -777,7 +783,7 @@ hatom_t H5Fopen(const char *filename, uintn flags, hatom_t access_temp) H5F_decode_length(new_file,p,new_file->logical_len); /* Decode logical length of file */ /* Decode the root symbol table entry */ - if (H5G_decode (new_file, &p, new_file->root_sym)<0) { + if (H5G_ent_decode (new_file, &p, new_file->root_sym)<0) { /*can't decode root symbol table entry */ HGOTO_ERROR (H5E_IO, H5E_READERROR, FAIL); } @@ -870,6 +876,8 @@ H5Fflush (hatom_t fid, hbool_t invalidate) * Return: Success: SUCCEED * * Failure: FAIL + * -2 if the there are open objects and + * INVALIDATE was non-zero. * * Programmer: Robb Matzke * robb@maya.nuance.com @@ -883,12 +891,19 @@ static herr_t H5F_flush (hdf5_file_t *f, hbool_t invalidate) { uint8 buf[2048], *p=buf; + herr_t shadow_flush; FUNC_ENTER (H5F_flush, H5F_init_interface, FAIL); /* nothing to do if the file is read only */ if (0==(H5ACC_WRITE & f->acc_perm)) HRETURN (SUCCEED); + /* + * Flush all open object info. If this fails just remember it and return + * failure at the end. At least that way we get a consistent file. + */ + shadow_flush = H5G_shadow_flush (f, invalidate); + /* flush (and invalidate) the entire cache */ if (H5AC_flush (f, NULL, 0, invalidate)<0) { HRETURN_ERROR (H5E_CACHE, H5E_CANTFLUSH, FAIL); /*can't flush cache*/ @@ -912,7 +927,7 @@ H5F_flush (hdf5_file_t *f, hbool_t invalidate) H5F_encode_offset (f, p, f->smallobj_off); H5F_encode_offset (f, p, f->freespace_off); H5F_encode_length (f, p, f->logical_len); - H5G_encode (f, &p, f->root_sym); + H5G_ent_encode (f, &p, f->root_sym); /* write the boot block to disk */ if (H5F_block_write (f, 0, p-buf, buf)<0) { @@ -922,6 +937,11 @@ H5F_flush (hdf5_file_t *f, hbool_t invalidate) /* update file length if necessary */ if (f->logical_len<=0) f->logical_len = p-buf; + /* Did shadow flush fail above? */ + if (shadow_flush<0) { + HRETURN_ERROR (H5E_CACHE, H5E_CANTFLUSH, -2);/*object are still open*/ + } + FUNC_LEAVE (SUCCEED); } @@ -978,7 +998,9 @@ herr_t H5Fclose(hatom_t fid) if((--file->ref_count)==0) { if(file->file_handle!=H5F_INVALID_FILE) { - if (H5F_flush (file, TRUE)<0) { + if (-2==(ret_value=H5F_flush (file, TRUE))) { + /*objects are still open*/ + } else if (ret_value<0) { /*can't flush cache*/ HGOTO_ERROR (H5E_CACHE, H5E_CANTFLUSH, FAIL); } @@ -990,6 +1012,11 @@ herr_t H5Fclose(hatom_t fid) } } /* end if */ + /* Did the H5F_flush() fail because of open objects? */ + if (ret_value<0) { + HGOTO_ERROR (H5E_SYM, H5E_CANTFLUSH, FAIL); + } + done: if(ret_value == FAIL) { /* Error condition cleanup */ @@ -1180,7 +1207,7 @@ H5F_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, (unsigned)(f->file_create_parms.sharedheader_ver)); fprintf (stream, "%*sRoot symbol table entry:\n", indent, ""); - H5G_debug (f, f->root_sym, stream, indent+3, MAX(0, fwidth-3)); + H5G_ent_debug (f, f->root_sym, stream, indent+3, MAX(0, fwidth-3)); FUNC_LEAVE (SUCCEED); } diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index f1c7b59..08cfd8f 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -352,6 +352,8 @@ typedef struct { file_access_temp_t file_access_parms; /* File-access template */ #endif struct H5G_entry_t *root_sym; /* Root symbol table entry */ + uintn nshadows; /* Size of shadow hash table */ + struct H5G_hash_t **shadow; /* The shadow hash table */ } hdf5_file_t; @@ -47,11 +47,10 @@ #define H5G_INIT_HEAP 8192 #define PABLO_MASK H5G_mask -static herr_t H5G_mkroot (hdf5_file_t *f, size_t size_hint); - /* Is the interface initialized? */ static hbool_t interface_initialize_g = FALSE; + /*------------------------------------------------------------------------- * Function: H5G_component @@ -315,6 +314,8 @@ H5G_namei (hdf5_file_t *f, H5G_entry_t *cwd, const char *name, * is removed). If the root object doesn't have a name message * then the name `Root Object' is used. * + * Warning: This function has a few subtleties. Be warned! + * * Errors: * DIRECTORY CANTINIT Can't create root. * DIRECTORY CANTINIT Can't insert old root object in @@ -323,7 +324,9 @@ H5G_namei (hdf5_file_t *f, H5G_entry_t *cwd, const char *name, * * Return: Success: SUCCEED * - * Failure: FAIL + * Failure: FAIL. This function returns -2 if the + * failure is because a root directory already + * exists. * * Programmer: Robb Matzke * robb@maya.nuance.com @@ -336,104 +339,103 @@ H5G_namei (hdf5_file_t *f, H5G_entry_t *cwd, const char *name, static herr_t H5G_mkroot (hdf5_file_t *f, size_t size_hint) { + H5G_entry_t *handle=NULL; /*handle to open object */ + herr_t ret_value=FAIL; /*return value */ + H5O_name_t name={NULL}; /*object name */ H5O_stab_t stab; /*symbol table message */ - H5O_name_t name={0}; /*object name message */ - H5G_entry_t root; /*old root entry */ - const char *root_name=NULL; /*name of old root object */ - intn nlinks; /*number of links */ - H5G_entry_t *handle; /*handle for open object */ + H5G_entry_t *ent_ptr=NULL; /*pointer to a symbol table entry*/ + const char *obj_name=NULL; /*name of old root object */ FUNC_ENTER (H5G_mkroot, NULL, FAIL); /* - * Make sure we have the latest info since someone might have the root - * object open for modifications. + * Make sure that the file descriptor has the latest info -- someone might + * have the root object open. */ 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 we already have a root object, then open it and get it's name. The + * root object had better not already be a directory. Once the old root + * object is opened and we have a HANDLE, set the dirty bit on the handle. + * This causes the handle data to be written back into f->root_sym by + * H5G_close() if something goes wrong before the old root object is + * re-inserted back into the directory hierarchy. We might leak file + * memory, but at least we don't loose the original root object. */ if (f->root_sym->header>0) { 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)) { - root_name = name.s; /*dont reset name until root_name is done!*/ - root = *(f->root_sym); - + HGOTO_ERROR (H5E_DIRECTORY, H5E_EXISTS, -2); + } else if (NULL==(handle=H5G_shadow_open (f, NULL, f->root_sym))) { + /* can't open root object */ + HGOTO_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); + } else if (NULL==H5O_read (f, NO_ADDR, handle, H5O_NAME, 0, &name)) { + obj_name = "Root Object"; } else { - root = *(f->root_sym); - root_name = "Root Object"; + obj_name = name.s; /*don't reset message until the end!*/ } + handle->dirty = TRUE; } /* - * Create the root directory. + * Create the new root directory directly into the file descriptor. If + * something goes wrong at this step, closing the `handle' will rewrite + * info back into f->root_sym because we set the dirty bit. */ if (H5G_stab_new (f, f->root_sym, size_hint)<0) { - H5O_reset (H5O_NAME, &name); - HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*can't create root*/ + HGOTO_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*cant create root*/ + } + if (1!=H5O_link (f, f->root_sym, 1)) { + HGOTO_ERROR (H5E_DIRECTORY, H5E_LINK, FAIL); } /* - * Increase the link count for the root symbol table! - */ - nlinks = H5O_link (f, f->root_sym->header, f->root_sym, 1); - assert (1==nlinks); - - /* - * Insert the old root object. It should already have a link count - * of 1. + * If there was a previous root object then insert it into the new root + * symbol table with the specified name. Inserting the object will update + * the handle to point to the new symbol table slot instead of f->root_sym. */ - if (root_name) { - -#ifndef NDEBUG - nlinks = H5O_link (f, root.header, &root, 0); - assert (1==nlinks); -#endif - 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 (obj_name) { + if (1!=H5O_link (f, handle, 0)) { + HGOTO_ERROR (H5E_DIRECTORY, H5E_LINK, FAIL); } - - /* 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; + if (NULL==(ent_ptr=H5G_stab_insert (f, f->root_sym, obj_name, + handle))) { + HGOTO_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); } - H5ECLEAR; + + /* + * Remove all `name' messages from the old root object. The only time + * a name message should ever appear is to give the root object a name, + * but the old root object is no longer the root object. + */ + H5O_remove (f, NO_ADDR, handle, H5O_NAME, H5O_ALL); + H5ECLEAR; /*who really cares?*/ } - + + ret_value = SUCCEED; + + done: + /* + * If the handle is closed before the H5G_stab_insert() call that + * reinserts the root object into the directory hierarchy, then + * H5G_close() will reset f->root_sym to point to the old root symbol and + * the new root directory (if it was created) will be unlinked from the + * directory hierarchy (and memory leaked). + */ + if (handle) H5G_close (f, handle); H5O_reset (H5O_NAME, &name); - FUNC_LEAVE (SUCCEED); + + FUNC_LEAVE (ret_value); } /*------------------------------------------------------------------------- - * Function: H5G_new + * Function: H5G_mkdir * - * Purpose: Creates a new empty directory with the specified name. The - * name is either an absolute name or is relative to the - * directory whose symbol table entry is CWD. On return, the - * optional DIR_ENT pointer is initialized with the symbol - * table entry for the new directory's parent and ENT will - * contain the symbol table entry for the new directory. + * Purpose: Creates a new empty directory with the specified name, + * opening it as an object. The name is either an absolute name + * or is relative to the current working directory. * * A root directory is created implicitly by this function * when necessary. Calling this function with the name "/" @@ -448,12 +450,10 @@ H5G_mkroot (hdf5_file_t *f, size_t size_hint) * DIRECTORY EXISTS Already exists. * DIRECTORY NOTFOUND Missing component. * - * Return: Success: SUCCEED, if DIR_ENT is not the null pointer - * then it will be initialized with the - * symbol table entry for the new directory. + * Return: Success: A handle to the open directory. Please call + * H5G_close() when you're done with it. * - * Failure: FAIL, the memory pointed to by CWD is - * not modified. + * Failure: NULL * * Programmer: Robb Matzke * robb@maya.nuance.com @@ -463,31 +463,43 @@ H5G_mkroot (hdf5_file_t *f, size_t size_hint) * *------------------------------------------------------------------------- */ -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_mkdir (hdf5_file_t *f, const char *name, size_t size_hint) { - const char *rest=NULL; - H5G_entry_t _parent, _child; - char _comp[1024]; - size_t nchars; + const char *rest=NULL; /*the base name */ + H5G_entry_t *cwd=NULL; /*current working directory */ + H5G_entry_t dir_ent; /*directory containing new dir */ + H5G_entry_t ent; /*new directory entry */ + H5G_entry_t *ent_ptr=NULL; /*ptr to new directory entry */ + H5G_entry_t *ret_value=NULL; /*handle return value */ + char _comp[1024]; /*name component */ + size_t nchars; /*number of characters in compon*/ + herr_t status; /*function return status */ - FUNC_ENTER (H5G_new, NULL, FAIL); + FUNC_ENTER (H5G_mkdir, NULL, NULL); /* check args */ assert (f); assert (name && *name); +#ifndef LATER + /* Get current working directory */ + H5G_shadow_sync (f->root_sym); + cwd = f->root_sym; +#endif assert (cwd || '/'==*name); - if (!dir_ent) dir_ent = &_parent; - if (!ent) ent = &_child; - /* Create root directory if necessary */ - H5G_mkroot (f, H5G_SIZE_HINT); + /* + * Try to create the root directory. Ignore the error if this function + * fails because the root directory already exists. + */ + if ((status=H5G_mkroot (f, H5G_SIZE_HINT))<0 && -2!=status) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); + } H5ECLEAR; /* lookup name */ - if (H5G_namei (f, cwd, name, &rest, dir_ent)) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, FAIL); /*already exists*/ + if (H5G_namei (f, cwd, name, &rest, &dir_ent)) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, NULL); /*already exists*/ } H5ECLEAR; /*it's OK that we didn't find it*/ @@ -497,10 +509,10 @@ H5G_new (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, if (rest[nchars]) { if (H5G_component (rest+nchars, NULL)) { /* missing component */ - HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, NULL); } else if (nchars+1 > sizeof _comp) { /* component is too long */ - HRETURN_ERROR (H5E_DIRECTORY, H5E_COMPLEN, FAIL); + HRETURN_ERROR (H5E_DIRECTORY, H5E_COMPLEN, NULL); } else { /* null terminate */ HDmemcpy (_comp, rest, nchars); @@ -510,266 +522,165 @@ H5G_new (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, } /* create directory */ - if (H5G_stab_new (f, ent, size_hint)<0) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*can't create dir*/ + if (H5G_stab_new (f, &ent, size_hint)<0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); /*can't create dir*/ } /* insert child name into parent */ - if (H5G_stab_insert (f, dir_ent, rest, ent)<0) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*can't insert*/ + if (NULL==(ent_ptr=H5G_stab_insert (f, &dir_ent, rest, &ent))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); /*can't insert*/ } - FUNC_LEAVE (SUCCEED); -} - - -/*------------------------------------------------------------------------- - * 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); + /* open the directory */ + if (NULL==(ret_value=H5G_shadow_open (f, &dir_ent, ent_ptr))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); /*can't open*/ } - FUNC_LEAVE (handle); + FUNC_LEAVE (ret_value); } /*------------------------------------------------------------------------- - * Function: H5G_close + * Function: H5G_pushd * - * Purpose: Closes an object that was open for modification. + * Purpose: Pushes a new current working directory onto the stack. * * Return: Success: SUCCEED * * Failure: FAIL * * Programmer: Robb Matzke - * Thursday, September 18, 1997 + * Friday, September 19, 1997 * * Modifications: * *------------------------------------------------------------------------- */ herr_t -H5G_close (hdf5_file_t *f, H5G_entry_t *ent) +H5G_pushd (hdf5_file_t *f, const char *name) { - FUNC_ENTER (H5G_close, NULL, FAIL); + FUNC_ENTER (H5G_pushd, NULL, FAIL); - if (H5G_shadow_close (f, ent)<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTFLUSH, FAIL); +#ifndef LATER + /* + * Current working directories are not implemented yet. + */ + if (strcmp (name, "/")) { + HRETURN_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, FAIL); } +#endif FUNC_LEAVE (SUCCEED); } /*------------------------------------------------------------------------- - * Function: H5G_find - * - * Purpose: Finds an object with the specified NAME in file F. If - * the name is relative then it is interpretted relative - * to CWD, a symbol table entry for a symbol table. On - * successful return, DIR_ENT (if non-null) will be - * initialized with the symbol table information for the - * directory in which the object appears (or all zero if - * the returned object is the root object) and ENT will - * be initialized with the symbol table entry for the - * object (ENT is optional when the caller is interested - * only in the existence of the object). + * Function: H5G_popd * - * This function will fail if the root object is - * requested and there is none. - * - * Errors: - * DIRECTORY NOTFOUND Object not found. + * Purpose: Pops the top current working directory off the stack. * - * 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. + * Return: Success: SUCCEED * * Failure: FAIL * * Programmer: Robb Matzke - * robb@maya.nuance.com - * Aug 12 1997 + * Friday, September 19, 1997 * * Modifications: * *------------------------------------------------------------------------- */ 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_popd (hdf5_file_t *f) { - H5G_entry_t *ent_p = NULL; - FUNC_ENTER (H5G_find, NULL, FAIL); - - /* check args */ - assert (f); - assert (name && *name); - assert (cwd || '/'==*name); - - if (f->root_sym->header<=0) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); /*object not found*/ - } + FUNC_ENTER (H5G_popd, NULL, FAIL); - if (NULL==(ent_p=H5G_namei (f, cwd, name, NULL, dir_ent))) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); /*object not found*/ - } +#ifndef LATER + /* CWD is not implemented yet. */ +#endif - if (ent) *ent = *ent_p; FUNC_LEAVE (SUCCEED); } /*------------------------------------------------------------------------- - * Function: H5G_insert - * - * Purpose: Inserts symbol table ENT into the directory hierarchy - * giving it the specified NAME. 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 (or all - * zero if the new ENT is the root object). - * - * This function attempts to use a non-directory file if - * the file contains just one object. The one object - * will be the root object. - * - * Inserting an object entry into the symbol table increments - * the link counter for that object. + * Function: H5G_create * - * Errors: - * DIRECTORY CANTINIT Can't insert. - * DIRECTORY CANTINIT Cannot add/change name message. - * DIRECTORY CANTINIT Lookup failed. - * DIRECTORY COMPLEN Component is too long. - * DIRECTORY EXISTS Already exists. - * DIRECTORY EXISTS Root exists. - * DIRECTORY LINK Bad link count. - * DIRECTORY LINK Link inc failure. - * DIRECTORY NOTFOUND Component not found. + * Purpose: Creates a new empty object header, gives it a name, opens + * the object for modification, and returns a handle to the + * object. The initial size of the object header can be + * supplied with the OHDR_HINT argument. * - * Return: Success: SUCCEED with optional DIR_ENT initialized with - * the symbol table entry for the directory - * which contains the new ENT. + * Return: Success: A handle for the object. Be sure to + * eventually close it. * - * Failure: FAIL (DIR_ENT is not modified). + * Failure: FAIL * * Programmer: Robb Matzke - * robb@maya.nuance.com - * Aug 11 1997 + * Friday, September 19, 1997 * * Modifications: * *------------------------------------------------------------------------- */ -herr_t -H5G_insert (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, - const char *name, H5G_entry_t *ent) +H5G_entry_t * +H5G_create (hdf5_file_t *f, const char *name, size_t ohdr_hint) { - const char *rest=NULL; - H5G_entry_t _parent; - size_t nchars; - char _comp[1024]; - H5O_stab_t stab; + H5G_entry_t ent; /*entry data for the new object */ + H5G_entry_t *ent_ptr; /*ptr into symbol node for entry*/ + H5G_entry_t *cwd=NULL; /*ptr to CWD handle */ + const char *rest = NULL; /*part of name not existing yet */ + H5G_entry_t dir; /*entry for dir to contain obj */ + H5G_entry_t *ret_value=NULL; /*the object handle */ + size_t nchars; /*number of characters in name */ + char _comp[1024]; /*name component */ - FUNC_ENTER (H5G_insert, NULL, FAIL); + FUNC_ENTER (H5G_create, NULL, NULL); - /* check args */ + /* Check args. */ assert (f); assert (name && *name); - assert (cwd || '/'==*name); - assert (ent); - assert (!ent->shadow); - if (!dir_ent) dir_ent = &_parent; - + HDmemset (&ent, 0, sizeof(H5G_entry_t)); + /* - * 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 - * the symbol table message from its header. H5G_mkroot() fails if - * the root object is already a directory, but we don't care. + * Get the current working directory. */ - if (f->root_sym->header>0 || - H5O_read (f, ent->header, ent, H5O_STAB, 0, &stab)) { - H5G_mkroot (f, H5G_SIZE_HINT); - H5ECLEAR; - } +#ifndef LATER + H5G_shadow_sync (f->root_sym); + cwd = f->root_sym; +#endif /* * Look up the name -- it shouldn't exist yet. */ - if (H5G_namei (f, cwd, name, &rest, dir_ent)) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, FAIL); /*already exists*/ + if (H5G_namei (f, cwd, name, &rest, &dir)) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, NULL); /*already exists*/ } H5ECLEAR; /*it's OK that we didn't find it*/ - - /* - * The caller may be attempting to insert a root object that either - * doesn't have a name or we shouldn't interfere with the name - * it already has. - */ rest = H5G_component (rest, &nchars); + if (!rest || !*rest) { + /* + * The caller is attempting to insert a root object that either + * doesn't have a name or we shouldn't interfere with the name + * it already has as a message. + */ if (f->root_sym->header>0) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, FAIL); /*root exists*/ + HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, NULL); /*root exists*/ + } + if ((ent.header = H5O_new (f, 0, ohdr_hint))<0) { + /* can't create header */ + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); } - HDmemset (dir_ent, 0, sizeof(H5G_entry_t)); - if (1!=H5O_link (f, ent->header, ent, 1)) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_LINK, FAIL); /*bad link count*/ + if (1!=H5O_link (f, &ent, 1)) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_LINK, NULL); /*bad link count*/ } - *(f->root_sym) = *ent; - HRETURN (SUCCEED); + *(f->root_sym) = ent; + if (NULL==(ret_value=H5G_shadow_open (f, &dir, f->root_sym))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); + } + HRETURN (ret_value); } /* @@ -779,10 +690,10 @@ H5G_insert (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, if (rest[nchars]) { if (H5G_component (rest+nchars, NULL)) { /* component not found */ - HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, NULL); } else if (nchars+1 > sizeof _comp) { /* component is too long */ - HRETURN_ERROR (H5E_DIRECTORY, H5E_COMPLEN, FAIL); + HRETURN_ERROR (H5E_DIRECTORY, H5E_COMPLEN, NULL); } else { /* null terminate */ HDmemcpy (_comp, rest, nchars); @@ -792,654 +703,219 @@ 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). We don't have to worry about it being open. + * Create the object header. */ + if ((ent.header = H5O_new (f, 0, ohdr_hint))<0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); + } + + if (f->root_sym->header<=0) { + /* + * This will be the only object in the file. Insert it as the root + * object and add a name messaage to the object header (or modify + * the first one we find). Although the header exists we can guarantee + * that it isn't open since it has no name. + */ H5O_name_t name_mesg; name_mesg.s = rest; - if (H5O_modify (f, NO_ADDR, ent, H5O_NAME, 0, &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); + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); } - if (1!=H5O_link (f, ent->header, ent, 1)) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_LINK, FAIL); /*bad link count*/ + if (1!=H5O_link (f, &ent, 1)) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_LINK, NULL); /*bad link count*/ } - *(f->root_sym) = *ent; - HRETURN (SUCCEED); - } - - /* increment the link count */ - if (H5O_link (f, ent->header, ent, 1)<0) { - HRETURN_ERROR (H5E_DIRECTORY, H5E_LINK, FAIL); /*link inc failure*/ - } - - /* insert entry into parent */ - if (H5G_stab_insert (f, dir_ent, rest, ent)<0) { - H5O_link (f, ent->header, ent, -1); /*don't care if it fails*/ - HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*can't insert*/ - } - - FUNC_LEAVE (SUCCEED); -} - - -/*------------------------------------------------------------------------- - * Function: H5G_stab_new - * - * Purpose: Creates a new empty symbol table (object header, name heap, - * and B-tree). The caller can specify an initial size for the - * name heap. - * - * In order for the B-tree to operate correctly, the first - * item in the heap is the empty string, and must appear at - * heap offset zero. - * - * Errors: - * INTERNAL CANTINIT B-tree's won't work if the first - * name isn't at the beginning of the - * heap. - * SYM CANTINIT Can't create B-tree. - * SYM CANTINIT Can't create header. - * SYM CANTINIT Can't create heap. - * SYM CANTINIT Can't create message. - * SYM CANTINIT Can't initialize heap. - * - * Return: Success: Address of new symbol table header. If - * the caller supplies a symbol table entry - * SELF then it will be initialized to point to - * this symbol table. - * - * Failure: FAIL - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 1 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -haddr_t -H5G_stab_new (hdf5_file_t *f, H5G_entry_t *self, size_t init) -{ - off_t name; /*offset of "" name */ - haddr_t addr; /*object header address */ - H5O_stab_t stab; /*symbol table message */ - - FUNC_ENTER (H5G_stab_new, NULL, FAIL); - - /* - * Check arguments. - */ - assert (f); - init = MAX(init, H5H_SIZEOF_FREE(f)+2); - - /* Create symbol table private heap */ - if ((stab.heap_addr = H5H_new (f, H5H_LOCAL, init))<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't create heap*/ - } - if ((name = H5H_insert (f, stab.heap_addr, 1, "")<0)) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't initialize heap*/ - } - if (0!=name) { + *(f->root_sym) = ent; + if (NULL==(ret_value=H5G_shadow_open (f, &dir, f->root_sym))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); + } + HRETURN (ret_value); + } else { /* - * B-tree's won't work if the first name isn't at the beginning - * of the heap. + * Make sure the root directory exists. Ignore the failure if it's + * because the directory already exists. */ - HRETURN_ERROR (H5E_INTERNAL, H5E_CANTINIT, FAIL); - } - - /* Create the B-tree */ - if ((stab.btree_addr = H5B_new (f, H5B_SNODE))<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't create B-tree*/ + hbool_t update_dir = (dir.header==f->root_sym->header); + herr_t status = H5G_mkroot (f, H5G_SIZE_HINT); + if (status<0 && -2!=status) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); + } + H5ECLEAR; + if (update_dir) dir = *(f->root_sym); } - + /* - * Create symbol table object header. It has a zero link count - * since nothing refers to it yet. The link count will be - * incremented if the object is added to the directory hierarchy. + * This is the normal case. The object is just being inserted as a normal + * entry into a symbol table. */ - if ((addr = H5O_new (f, 0, 4+2*H5F_SIZEOF_OFFSET(f)))<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't create header*/ + if (H5O_link (f, &ent, 1)<0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_LINK, NULL); /*link inc failure*/ } - - /* insert the symbol table message */ - if (self) { - memset (self, 0, sizeof(H5G_entry_t)); - self->header = addr; + if (NULL==(ent_ptr=H5G_stab_insert (f, &dir, rest, &ent))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); /*can't insert*/ } - if (H5O_modify(f, addr, self, H5O_STAB, H5O_NEW_MESG, &stab)<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't create message*/ + if (NULL==(ret_value=H5G_shadow_open (f, &dir, ent_ptr))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, NULL); /*can't open object*/ } - - FUNC_LEAVE (addr); + FUNC_LEAVE (ret_value); } /*------------------------------------------------------------------------- - * Function: H5G_stab_find - * - * Purpose: Finds a symbol named NAME in the symbol table whose - * description is stored in SELF in file F and returns a - * pointer to the symbol table entry. SELF is optional if the - * symbol table address is supplied through ADDR. + * Function: H5G_open * - * Errors: - * SYM BADMESG Can't read message. - * SYM NOTFOUND Not found. + * 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: 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. + * Return: Success: Ptr to a handle for the object. * * Failure: NULL * * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 1 1997 + * Wednesday, September 17, 1997 * * Modifications: * *------------------------------------------------------------------------- */ H5G_entry_t * -H5G_stab_find (hdf5_file_t *f, haddr_t addr, H5G_entry_t *self, - const char *name) +H5G_open (hdf5_file_t *f, const char *name) { - H5G_bt_ud1_t udata; /*data to pass through B-tree */ - H5O_stab_t stab; /*symbol table message */ - - FUNC_ENTER (H5G_stab_find, NULL, NULL); + H5G_entry_t *ent=NULL; + H5G_entry_t *ret_value=NULL; + H5G_entry_t dir; + H5G_entry_t *cwd=NULL; + + FUNC_ENTER (H5G_open, NULL, NULL); - /* Check arguments */ + /* check args */ assert (f); - if (addr<=0 && (!self || self->header<=0)) { - HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); - } if (!name || !*name) { - HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); + HRETURN_ERROR (H5E_DIRECTORY, H5E_BADVALUE, NULL); } - if (addr<=0) addr = self->header; - /* set up the udata */ - 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; + /* Get CWD */ +#ifndef LATER + H5G_shadow_sync (f->root_sym); + cwd = f->root_sym; +#endif + assert (cwd || '/'==*name); - /* search the B-tree */ - if (H5B_find (f, H5B_SNODE, stab.btree_addr, &udata)<0) { - HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); /*not found*/ + if (f->root_sym->header<=0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, NULL); /*object not found*/ } - - /* return the result */ - FUNC_LEAVE (udata.entry_ptr); -} - - -/*------------------------------------------------------------------------- - * Function: H5G_stab_insert - * - * Purpose: Insert a new symbol into the table described by SELF in - * file F. The name of the new symbol is NAME and its symbol - * table entry is ENT. - * - * Errors: - * SYM BADMESG Can't read message. - * SYM CANTINSERT Can't insert entry. - * - * Return: Success: SUCCEED - * - * Failure: FAIL - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 1 1997 - * - * 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 -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_bt_ud1_t udata; /*data to pass through B-tree */ - - FUNC_ENTER (H5G_stab_insert, NULL, FAIL); - - /* check arguments */ - assert (f); - assert (self && self->header>=0); - assert (name && *name); - assert (ent); - - /* initialize data to pass through B-tree */ - 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==(ent=H5G_namei (f, cwd, name, NULL, &dir))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, NULL); /*object not found*/ } - - 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) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINSERT, FAIL); /*can't insert entry*/ + if (NULL==(ret_value=H5G_shadow_open (f, &dir, ent))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTOPENOBJ, NULL); } - /* update the name offset in the entry */ - ent->name_off = udata.entry.name_off; - FUNC_LEAVE (SUCCEED); + FUNC_LEAVE (ret_value); } - -/*------------------------------------------------------------------------- - * Function: H5G_stab_list - * - * Purpose: Returns a list of all the symbols in a symbol table. - * The caller allocates an array of pointers which this - * function will fill in with malloc'd names. The caller - * also allocates an array of symbol table entries which will - * be filled in with data from the symbol table. Each of these - * arrays should have at least MAXENTRIES elements. - * - * Errors: - * SYM BADMESG Not a symbol table. - * SYM CANTLIST B-tree list failure. - * - * Return: Success: The total number of symbols in the - * symbol table. This may exceed MAXENTRIES, - * but at most MAXENTRIES values are copied - * into the NAMES and ENTRIES arrays. - * - * Failure: FAIL, the pointers in NAMES are undefined but - * no memory is allocated. The values in - * ENTRIES are undefined. - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 1 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -intn -H5G_stab_list (hdf5_file_t *f, H5G_entry_t *self, intn maxentries, - char *names[], H5G_entry_t entries[]) -{ - H5G_bt_ud2_t udata; - H5O_stab_t stab; - intn i; - - FUNC_ENTER (H5G_stab_list, NULL, FAIL); - - /* check args */ - assert (f); - assert (self && self->header>=0); - assert (maxentries>=0); - - /* initialize data to pass through B-tree */ - if (NULL==H5O_read (f, self->header, self, H5O_STAB, 0, &stab)) { - HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL); /*not a symbol table*/ - } - udata.entry = entries; - udata.name = names; - udata.dir_addr = self->header; - udata.heap_addr = stab.heap_addr; - udata.maxentries = maxentries; - udata.nsyms = 0; - if (names) HDmemset (names, 0, maxentries); - - /* list */ - if (H5B_list (f, H5B_SNODE, stab.btree_addr, &udata)<0) { - if (names) { - for (i=0; i<maxentries; i++) H5MM_xfree (names[i]); - } - HRETURN_ERROR (H5E_SYM, H5E_CANTLIST, FAIL); /*B-tree list failure*/ - } - FUNC_LEAVE (udata.nsyms); -} - /*------------------------------------------------------------------------- - * Function: H5G_decode_vec - * - * Purpose: Same as H5G_decode() except it does it for an array of - * symbol table entries. + * Function: H5G_close * - * Errors: - * SYM CANTDECODE Can't decode. + * Purpose: Closes an object that was open for modification. * - * Return: Success: SUCCEED, with *pp pointing to the first byte - * after the last symbol. + * Return: Success: SUCCEED * * Failure: FAIL * * Programmer: Robb Matzke - * matzke@llnl.gov - * Jul 18 1997 + * Thursday, September 18, 1997 * * Modifications: * *------------------------------------------------------------------------- */ herr_t -H5G_decode_vec (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent, intn n) +H5G_close (hdf5_file_t *f, H5G_entry_t *ent) { - intn i; - - FUNC_ENTER (H5G_decode_vec, NULL, FAIL); + FUNC_ENTER (H5G_close, NULL, FAIL); - /* check arguments */ assert (f); - assert (pp); - assert (ent); - assert (n>=0); - /* decode entries */ - for (i=0; i<n; i++) { - if (H5G_decode (f, pp, ent+i)<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTDECODE, FAIL); /*can't decode*/ - } + if (ent && H5G_shadow_close (f, ent)<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTFLUSH, FAIL); } - + FUNC_LEAVE (SUCCEED); } /*------------------------------------------------------------------------- - * Function: H5G_decode - * - * Purpose: Decodes a symbol table entry pointed to by `*pp'. - * - * Errors: - * - * Return: Success: SUCCEED with *pp pointing to the first byte - * following the symbol table entry. - * - * Failure: FAIL - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Jul 18 1997 - * - * Modifications: + * Function: H5G_find * - *------------------------------------------------------------------------- - */ -herr_t -H5G_decode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent) -{ - uint8 *p_ret = *pp; - - FUNC_ENTER (H5G_decode, NULL, FAIL); - - /* check arguments */ - assert (f); - assert (pp); - assert (ent); - - /* decode header */ - H5F_decode_offset (f, *pp, ent->name_off); - H5F_decode_offset (f, *pp, ent->header); - UINT32DECODE (*pp, ent->type); - - /* decode scratch-pad */ - switch (ent->type) { - case H5G_NOTHING_CACHED: - break; - - case H5G_CACHED_SDATA: - ent->cache.sdata.nt.length= *(*pp)++; - ent->cache.sdata.nt.arch= *(*pp)++; - UINT16DECODE (*pp, ent->cache.sdata.nt.type); - UINT32DECODE (*pp, ent->cache.sdata.ndim); - UINT32DECODE (*pp, ent->cache.sdata.dim[0]); - UINT32DECODE (*pp, ent->cache.sdata.dim[1]); - UINT32DECODE (*pp, ent->cache.sdata.dim[2]); - UINT32DECODE (*pp, ent->cache.sdata.dim[3]); - break; - - case H5G_CACHED_STAB: - UINT32DECODE (*pp, ent->cache.stab.btree_addr); - UINT32DECODE (*pp, ent->cache.stab.heap_addr); - break; - - default: - HDabort(); - } - - *pp = p_ret + H5G_SIZEOF_ENTRY(f); - FUNC_LEAVE (SUCCEED); -} - - -/*------------------------------------------------------------------------- - * Function: H5G_encode_vec + * Purpose: Finds an object with the specified NAME in file F. If + * the name is relative then it is interpretted relative + * to CWD, a symbol table entry for a symbol table. On + * successful return, DIR_ENT (if non-null) will be + * initialized with the symbol table information for the + * directory in which the object appears (or all zero if + * the returned object is the root object) and ENT will + * be initialized with the symbol table entry for the + * object (ENT is optional when the caller is interested + * only in the existence of the object). * - * Purpose: Same as H5G_encode() except it does it for an array of - * symbol table entries. + * This function will fail if the root object is + * requested and there is none. * * Errors: - * SYM CANTENCODE Can't encode. + * DIRECTORY NOTFOUND Object not found. * - * Return: Success: SUCCEED, with *pp pointing to the first byte - * after the last symbol. + * 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 * * Programmer: Robb Matzke - * matzke@llnl.gov - * Jul 18 1997 + * robb@maya.nuance.com + * Aug 12 1997 * * Modifications: * *------------------------------------------------------------------------- */ herr_t -H5G_encode_vec (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent, intn n) +H5G_find (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, + const char *name, H5G_entry_t *ent) { - intn i; - - FUNC_ENTER (H5G_encode_vec, NULL, FAIL); + H5G_entry_t *ent_p = NULL; + FUNC_ENTER (H5G_find, NULL, FAIL); - /* check arguments */ + /* check args */ assert (f); - assert (pp); - assert (ent); - assert (n>=0); + assert (name && *name); + assert (cwd || '/'==*name); - /* encode entries */ - for (i=0; i<n; i++) { - if (H5G_encode (f, pp, ent+i)<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTENCODE, FAIL); /*can't encode*/ - } + if (f->root_sym->header<=0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); /*object not found*/ } - FUNC_LEAVE (SUCCEED); -} - - -/*------------------------------------------------------------------------- - * Function: H5G_encode - * - * Purpose: Encodes the specified symbol table entry into the buffer - * pointed to by *pp. - * - * Errors: - * - * Return: Success: SUCCEED, with *pp pointing to the first byte - * after the symbol table entry. - * - * Failure: FAIL - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Jul 18 1997 - * - * Modifications: - * - * Robb Matzke, 8 Aug 1997 - * Writes zeros for the bytes that aren't used so the file doesn't - * contain junk. - * - *------------------------------------------------------------------------- - */ -herr_t -H5G_encode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent) -{ - uint8 *p_ret = *pp + H5G_SIZEOF_ENTRY(f); - - FUNC_ENTER (H5G_encode, NULL, FAIL); - - /* check arguments */ - assert (f); - assert (pp); - assert (ent); - - /* encode header */ - H5F_encode_offset (f, *pp, ent->name_off); - H5F_encode_offset (f, *pp, ent->header); - UINT32ENCODE (*pp, ent->type); - - /* encode scratch-pad */ - switch (ent->type) { - case H5G_NOTHING_CACHED: - break; - - case H5G_CACHED_SDATA: - *(*pp)++= ent->cache.sdata.nt.length; - *(*pp)++= ent->cache.sdata.nt.arch; - UINT16ENCODE (*pp, ent->cache.sdata.nt.type); - UINT32ENCODE (*pp, ent->cache.sdata.ndim); - UINT32ENCODE (*pp, ent->cache.sdata.dim[0]); - UINT32ENCODE (*pp, ent->cache.sdata.dim[1]); - UINT32ENCODE (*pp, ent->cache.sdata.dim[2]); - UINT32ENCODE (*pp, ent->cache.sdata.dim[3]); - break; - - case H5G_CACHED_STAB: - UINT32ENCODE (*pp, ent->cache.stab.btree_addr); - UINT32ENCODE (*pp, ent->cache.stab.heap_addr); - break; - - default: - HDabort(); + if (NULL==(ent_p=H5G_namei (f, cwd, name, NULL, dir_ent))) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); /*object not found*/ } - /* fill with zero */ - while (*pp<p_ret) *(*pp)++ = 0; - - *pp = p_ret; + if (ent) *ent = *ent_p; FUNC_LEAVE (SUCCEED); } - -/*------------------------------------------------------------------------- - * Function: H5G_debug - * - * Purpose: Prints debugging information about a symbol table entry. - * - * Errors: - * - * Return: Success: SUCCEED - * - * Failure: FAIL - * - * Programmer: Robb Matzke - * robb@maya.nuance.com - * Aug 29 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5G_debug (hdf5_file_t *f, H5G_entry_t *ent, FILE *stream, intn indent, - intn fwidth) -{ - int i; - char buf[64]; - - FUNC_ENTER (H5G_debug, NULL, FAIL); - - fprintf (stream, "%*s%-*s %lu\n", indent, "", fwidth, - "Name offset into private heap:", - (unsigned long)(ent->name_off)); - 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:"); - switch (ent->type) { - case H5G_NOTHING_CACHED: - fprintf (stream, "Nothing Cached\n"); - break; - - case H5G_CACHED_SDATA: - fprintf (stream, "S-data\n"); - fprintf (stream, "%*s%-*s %u\n", indent, "", fwidth, - "Number type length:", - (unsigned)(ent->cache.sdata.nt.length)); - fprintf (stream, "%*s%-*s %u\n", indent, "", fwidth, - "Number type architecture:", - (unsigned)(ent->cache.sdata.nt.arch)); - fprintf (stream, "%*s%-*s %u\n", indent, "", fwidth, - "Number type type:", - (unsigned)(ent->cache.sdata.nt.type)); - fprintf (stream, "%*s%-*s %u\n", indent, "", fwidth, - "Dimensionality:", - (unsigned)(ent->cache.sdata.ndim)); - for (i=0; i<ent->cache.sdata.ndim && i<4; i++) { - sprintf (buf, "Dimension %d", i); - fprintf (stream, "%*s%-*s %u\n", indent, "", fwidth, - buf, - (unsigned)(ent->cache.sdata.dim[i])); - } - break; - - case H5G_CACHED_STAB: - fprintf (stream, "Symbol Table\n"); - fprintf (stream, "%*s%-*s %lu\n", indent, "", fwidth, - "B-tree address:", - (unsigned long)(ent->cache.stab.btree_addr)); - fprintf (stream, "%*s%-*s %lu\n", indent, "", fwidth, - "Heap address:", - (unsigned long)(ent->cache.stab.heap_addr)); - break; - - default: - fprintf (stream, "*** Unknown symbol type %d\n", ent->type); - break; - } - - FUNC_LEAVE (SUCCEED); -} diff --git a/src/H5Gent.c b/src/H5Gent.c new file mode 100644 index 0000000..bc54161 --- /dev/null +++ b/src/H5Gent.c @@ -0,0 +1,488 @@ +/* + * Copyright (C) 1997 National Center for Supercomputing Applications. + * All rights reserved. + * + * Programmer: Robb Matzke <matzke@llnl.gov> + * Friday, September 19, 1997 + */ +#define H5G_PACKAGE + +#include <H5private.h> +#include <H5Eprivate.h> +#include <H5Gpkg.h> +#include <H5MMprivate.h> + +#define PABLO_MASK H5G_ent_mask + +static hbool_t interface_initialize_g = FALSE; + + +/*------------------------------------------------------------------------- + * Function: H5G_ent_calloc + * + * Purpose: Returns a pointer to a malloc'd, zeroed symbol table entry. + * + * Return: Success: Ptr to entry + * + * Failure: never fails + * + * Programmer: Robb Matzke + * Friday, September 19, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +H5G_entry_t * +H5G_ent_calloc (void) +{ + return H5MM_xcalloc (1, sizeof(H5G_entry_t)); +} + + + +/*------------------------------------------------------------------------- + * Function: H5G_ent_invalidate + * + * Purpose: Invalidates the cache in a symbol table entry. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, September 19, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_ent_invalidate (H5G_entry_t *ent) +{ + FUNC_ENTER (H5G_ent_invalidate, NULL, FAIL); + + if (ent && H5G_NOTHING_CACHED!=ent->type) { + ent->dirty = TRUE; + ent->type = H5G_NOTHING_CACHED; + } + + FUNC_LEAVE (SUCCEED); +} + + + +/*------------------------------------------------------------------------- + * Function: H5G_ent_addr + * + * Purpose: Returns the header address associated with a symbol table + * entry. + * + * Return: Success: Address + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, September 19, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +haddr_t +H5G_ent_addr (H5G_entry_t *ent) +{ + FUNC_ENTER (H5G_ent_addr, NULL, FAIL); + assert (ent); + + FUNC_LEAVE (ent->header); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_ent_cache + * + * Purpose: Returns a pointer to the cache associated with the symbol + * table entry. You should modify the cache directly, then call + * H5G_modified() with the new cache type (even if the type is + * still the same). + * + * Return: Success: Ptr to the cache in the symbol table entry. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Friday, September 19, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +H5G_cache_t * +H5G_ent_cache (H5G_entry_t *ent, H5G_type_t *cache_type) +{ + FUNC_ENTER (H5G_ent_cache, NULL, NULL); + if (!ent) { + HRETURN_ERROR (H5E_SYM, H5E_BADVALUE, NULL); + } + if (cache_type) *cache_type = ent->type; + + FUNC_LEAVE (&(ent->cache)); +} + + + +/*------------------------------------------------------------------------- + * Function: H5G_ent_modified + * + * Purpose: This function should be called after you make any + * modifications to a symbol table entry cache. Supply the new + * type for the cache. If CACHE_TYPE is the constant + * H5G_NO_CHANGE then the cache type isn't changed--just the + * dirty bit is set. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, September 19, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_ent_modified (H5G_entry_t *ent, H5G_type_t cache_type) +{ + FUNC_ENTER (H5G_ent_modified, NULL, FAIL); + assert (ent); + if (H5G_NO_CHANGE!=ent->type) ent->type = cache_type; + ent->dirty = TRUE; + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_ent_decode_vec + * + * Purpose: Same as H5G_ent_decode() except it does it for an array of + * symbol table entries. + * + * Errors: + * SYM CANTDECODE Can't decode. + * + * Return: Success: SUCCEED, with *pp pointing to the first byte + * after the last symbol. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 18 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_ent_decode_vec (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent, intn n) +{ + intn i; + + FUNC_ENTER (H5G_ent_decode_vec, NULL, FAIL); + + /* check arguments */ + assert (f); + assert (pp); + assert (ent); + assert (n>=0); + + /* decode entries */ + for (i=0; i<n; i++) { + if (H5G_ent_decode (f, pp, ent+i)<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTDECODE, FAIL); /*can't decode*/ + } + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_ent_decode + * + * Purpose: Decodes a symbol table entry pointed to by `*pp'. + * + * Errors: + * + * Return: Success: SUCCEED with *pp pointing to the first byte + * following the symbol table entry. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 18 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_ent_decode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent) +{ + uint8 *p_ret = *pp; + + FUNC_ENTER (H5G_ent_decode, NULL, FAIL); + + /* check arguments */ + assert (f); + assert (pp); + assert (ent); + + /* decode header */ + H5F_decode_offset (f, *pp, ent->name_off); + H5F_decode_offset (f, *pp, ent->header); + UINT32DECODE (*pp, ent->type); + + /* decode scratch-pad */ + switch (ent->type) { + case H5G_NOTHING_CACHED: + break; + + case H5G_CACHED_SDATA: + ent->cache.sdata.nt.length= *(*pp)++; + ent->cache.sdata.nt.arch= *(*pp)++; + UINT16DECODE (*pp, ent->cache.sdata.nt.type); + UINT32DECODE (*pp, ent->cache.sdata.ndim); + UINT32DECODE (*pp, ent->cache.sdata.dim[0]); + UINT32DECODE (*pp, ent->cache.sdata.dim[1]); + UINT32DECODE (*pp, ent->cache.sdata.dim[2]); + UINT32DECODE (*pp, ent->cache.sdata.dim[3]); + break; + + case H5G_CACHED_STAB: + UINT32DECODE (*pp, ent->cache.stab.btree_addr); + UINT32DECODE (*pp, ent->cache.stab.heap_addr); + break; + + default: + HDabort(); + } + + *pp = p_ret + H5G_SIZEOF_ENTRY(f); + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_ent_encode_vec + * + * Purpose: Same as H5G_ent_encode() except it does it for an array of + * symbol table entries. + * + * Errors: + * SYM CANTENCODE Can't encode. + * + * Return: Success: SUCCEED, with *pp pointing to the first byte + * after the last symbol. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 18 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_ent_encode_vec (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent, intn n) +{ + intn i; + + FUNC_ENTER (H5G_ent_encode_vec, NULL, FAIL); + + /* check arguments */ + assert (f); + assert (pp); + assert (ent); + assert (n>=0); + + /* encode entries */ + for (i=0; i<n; i++) { + if (H5G_ent_encode (f, pp, ent+i)<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTENCODE, FAIL); /*can't encode*/ + } + } + + FUNC_LEAVE (SUCCEED); +} + + + +/*------------------------------------------------------------------------- + * Function: H5G_ent_encode + * + * Purpose: Encodes the specified symbol table entry into the buffer + * pointed to by *pp. + * + * Errors: + * + * Return: Success: SUCCEED, with *pp pointing to the first byte + * after the symbol table entry. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 18 1997 + * + * Modifications: + * + * Robb Matzke, 8 Aug 1997 + * Writes zeros for the bytes that aren't used so the file doesn't + * contain junk. + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_ent_encode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent) +{ + uint8 *p_ret = *pp + H5G_SIZEOF_ENTRY(f); + + FUNC_ENTER (H5G_ent_encode, NULL, FAIL); + + /* check arguments */ + assert (f); + assert (pp); + assert (ent); + + /* encode header */ + H5F_encode_offset (f, *pp, ent->name_off); + H5F_encode_offset (f, *pp, ent->header); + UINT32ENCODE (*pp, ent->type); + + /* encode scratch-pad */ + switch (ent->type) { + case H5G_NOTHING_CACHED: + break; + + case H5G_CACHED_SDATA: + *(*pp)++= ent->cache.sdata.nt.length; + *(*pp)++= ent->cache.sdata.nt.arch; + UINT16ENCODE (*pp, ent->cache.sdata.nt.type); + UINT32ENCODE (*pp, ent->cache.sdata.ndim); + UINT32ENCODE (*pp, ent->cache.sdata.dim[0]); + UINT32ENCODE (*pp, ent->cache.sdata.dim[1]); + UINT32ENCODE (*pp, ent->cache.sdata.dim[2]); + UINT32ENCODE (*pp, ent->cache.sdata.dim[3]); + break; + + case H5G_CACHED_STAB: + UINT32ENCODE (*pp, ent->cache.stab.btree_addr); + UINT32ENCODE (*pp, ent->cache.stab.heap_addr); + break; + + default: + HDabort(); + } + + /* fill with zero */ + while (*pp<p_ret) *(*pp)++ = 0; + + *pp = p_ret; + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_ent_debug + * + * Purpose: Prints debugging information about a symbol table entry. + * + * Errors: + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 29 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_ent_debug (hdf5_file_t *f, H5G_entry_t *ent, FILE *stream, intn indent, + intn fwidth) +{ + int i; + char buf[64]; + + FUNC_ENTER (H5G_ent_debug, NULL, FAIL); + + fprintf (stream, "%*s%-*s %lu\n", indent, "", fwidth, + "Name offset into private heap:", + (unsigned long)(ent->name_off)); + 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:"); + switch (ent->type) { + case H5G_NOTHING_CACHED: + fprintf (stream, "Nothing Cached\n"); + break; + + case H5G_CACHED_SDATA: + fprintf (stream, "S-data\n"); + fprintf (stream, "%*s%-*s %u\n", indent, "", fwidth, + "Number type length:", + (unsigned)(ent->cache.sdata.nt.length)); + fprintf (stream, "%*s%-*s %u\n", indent, "", fwidth, + "Number type architecture:", + (unsigned)(ent->cache.sdata.nt.arch)); + fprintf (stream, "%*s%-*s %u\n", indent, "", fwidth, + "Number type type:", + (unsigned)(ent->cache.sdata.nt.type)); + fprintf (stream, "%*s%-*s %u\n", indent, "", fwidth, + "Dimensionality:", + (unsigned)(ent->cache.sdata.ndim)); + for (i=0; i<ent->cache.sdata.ndim && i<4; i++) { + sprintf (buf, "Dimension %d", i); + fprintf (stream, "%*s%-*s %u\n", indent, "", fwidth, + buf, + (unsigned)(ent->cache.sdata.dim[i])); + } + break; + + case H5G_CACHED_STAB: + fprintf (stream, "Symbol Table\n"); + fprintf (stream, "%*s%-*s %lu\n", indent, "", fwidth, + "B-tree address:", + (unsigned long)(ent->cache.stab.btree_addr)); + fprintf (stream, "%*s%-*s %lu\n", indent, "", fwidth, + "Heap address:", + (unsigned long)(ent->cache.stab.heap_addr)); + break; + + default: + fprintf (stream, "*** Unknown symbol type %d\n", ent->type); + break; + } + + FUNC_LEAVE (SUCCEED); +} diff --git a/src/H5Gnode.c b/src/H5Gnode.c index aa3175c..ffa1f86 100644 --- a/src/H5Gnode.c +++ b/src/H5Gnode.c @@ -60,7 +60,7 @@ static herr_t H5G_node_list (hdf5_file_t *f, haddr_t addr, void *_udata); 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] = {{ +const H5AC_class_t H5AC_SNODE[1] = {{ (void*(*)(hdf5_file_t*,haddr_t,void*))H5G_node_load, (herr_t(*)(hdf5_file_t*,hbool_t,haddr_t,void*))H5G_node_flush, }}; @@ -310,6 +310,7 @@ H5G_node_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5G_node_t *sym) if (H5G_shadow_sync (sym->entry+i)<0) { HRETURN_ERROR (H5E_SYM, H5E_CANTFLUSH, FAIL); } + if (sym->entry[i].dirty) sym->dirty = TRUE; } /* @@ -333,7 +334,7 @@ H5G_node_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5G_node_t *sym) UINT16ENCODE (p, sym->nsyms); /* entries */ - H5G_encode_vec (f, &p, sym->entry, sym->nsyms); + H5G_ent_encode_vec (f, &p, sym->entry, sym->nsyms); HDmemset (p, 0, size - (p-buf)); status = H5F_block_write (f, addr, size, buf); @@ -424,7 +425,7 @@ H5G_node_load (hdf5_file_t *f, haddr_t addr, void *_udata) UINT16DECODE (p, sym->nsyms); /* entries */ - if (H5G_decode_vec (f, &p, sym->entry, sym->nsyms)<0) { + if (H5G_ent_decode_vec (f, &p, sym->entry, sym->nsyms)<0) { HGOTO_ERROR (H5E_SYM, H5E_CANTLOAD, NULL); } buf = H5MM_xfree (buf); @@ -588,6 +589,8 @@ H5G_node_found (hdf5_file_t *f, haddr_t addr, const void *_lt_key, */ H5G_shadow_sync (sn->entry+idx); bt_udata->entry_ptr = sn->entry+idx; + bt_udata->node_addr = addr; + bt_udata->node_ptr = sn; break; default: @@ -597,9 +600,17 @@ H5G_node_found (hdf5_file_t *f, haddr_t addr, const void *_lt_key, ret_value = SUCCEED; done: - if (sn && H5AC_unprotect (f, H5AC_SNODE, addr, sn)<0) { - HRETURN_ERROR (H5E_SYM, H5E_PROTECT, FAIL); + /* + * Don't unprotect the symbol table entry if we're returning success since + * this might invalidate the bt_udata->entry_ptr and bt_udata->node_ptr + * pointers. Instead, we unprotect it in H5G_stab_find(). + */ + if (ret_value<0) { + if (sn && H5AC_unprotect (f, H5AC_SNODE, addr, sn)<0) { + HRETURN_ERROR (H5E_SYM, H5E_PROTECT, FAIL); + } } + FUNC_LEAVE (ret_value); } @@ -663,6 +674,8 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, intn i; haddr_t ret_value = FAIL; H5G_shadow_t *shadow = NULL; + H5G_node_t *insert_into=NULL; /*node that gets new entry*/ + haddr_t insert_addr=-1; /*address of that node */ FUNC_ENTER (H5G_node_insert, NULL, FAIL); @@ -675,6 +688,8 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, assert (md_key); assert (rt_key); assert (bt_udata); + bt_udata->node_addr = -1; + bt_udata->node_ptr = NULL; bt_udata->entry_ptr = NULL; /* @@ -757,90 +772,77 @@ H5G_node_insert (hdf5_file_t *f, haddr_t addr, intn *anchor, sn->nsyms = H5G_NODE_K (f); sn->dirty += 1; - /* Insert the new entry */ - if (idx<=H5G_NODE_K(f)) { - - /* Adjust shadows */ - for (i=idx; i<sn->nsyms; 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; - } + /* The middle key */ + md_key->offset = sn->entry[sn->nsyms-1].name_off; - /* Move entries */ - HDmemmove (sn->entry + idx + 1, - sn->entry + idx, - (H5G_NODE_K(f)-idx) * sizeof(H5G_entry_t)); - sn->entry[idx] = bt_udata->entry; - sn->entry[idx].name_off = offset; - sn->entry[idx].dirty = TRUE; - sn->nsyms += 1; - + /* Where to insert the new entry? */ + if (idx<=H5G_NODE_K(f)) { + insert_into = sn; + insert_addr = addr; + if (idx==H5G_NODE_K(f)) md_key->offset = offset; } else { idx -= H5G_NODE_K (f); - - /* Adjust shadows */ - for (i=idx; i<snrt->nsyms; 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] = bt_udata->entry; - snrt->entry[idx].name_off = offset; - snrt->entry[idx].dirty = TRUE; - snrt->nsyms += 1; - - if (idx+1 == sn->nsyms) { - rt_key->offset = offset; - *rt_key_changed = TRUE; - } + insert_into = snrt; + insert_addr = new_node; } - - /* The middle key */ - md_key->offset = sn->entry[sn->nsyms-1].name_off; + ret_value = new_node; } else { - /* - * Add the new symbol to the node. - */ + /* Where to insert the new entry? */ sn->dirty += 1; - for (i=idx; i<sn->nsyms; 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] = bt_udata->entry; - sn->entry[idx].name_off = offset; - sn->entry[idx].dirty = TRUE; - - if (idx+1==sn->nsyms) { + insert_into = sn; + insert_addr = addr; + if (idx==sn->nsyms) { rt_key->offset = offset; *rt_key_changed = TRUE; } + ret_value = 0; + } + + /* Adjust shadows */ + for (i=idx; i<insert_into->nsyms; i++) { + if (insert_into->entry[i].shadow) { + insert_into->entry[i].shadow->main = insert_into->entry + i + 1; + } + } + if (bt_udata->entry.shadow) { + H5G_shadow_move (f, bt_udata->entry.shadow, + bt_udata->name, + insert_into->entry + idx, + bt_udata->dir_addr); } - ret_value = new_node; /*successful return */ + /* Move entries */ + HDmemmove (insert_into->entry + idx + 1, + insert_into->entry + idx, + (insert_into->nsyms-idx) * sizeof(H5G_entry_t)); + insert_into->entry[idx] = bt_udata->entry; + insert_into->entry[idx].name_off = offset; + insert_into->entry[idx].dirty = TRUE; + insert_into->nsyms += 1; + + /* Update udata return values */ + bt_udata->node_addr = insert_addr; + bt_udata->node_ptr = insert_into; + bt_udata->entry_ptr = insert_into->entry + idx; done: - if (sn && H5AC_unprotect (f, H5AC_SNODE, addr, sn)<0) { - HRETURN_ERROR (H5E_SYM, H5E_PROTECT, FAIL); + if (ret_value<0) { + /* failing... */ + if (sn && H5AC_unprotect (f, H5AC_SNODE, addr, sn)<0) { + HRETURN_ERROR (H5E_SYM, H5E_PROTECT, FAIL); + } + } else if (insert_into!=sn) { + /* unprotect the first node and protect the return value */ + if (H5AC_unprotect (f, H5AC_SNODE, addr, sn)<0) { + HRETURN_ERROR (H5E_SYM, H5E_PROTECT, FAIL); + } + if (NULL==(sn=H5AC_protect (f, H5AC_SNODE, insert_addr, &ac_udata))) { + HGOTO_ERROR (H5E_SYM, H5E_CANTLOAD, FAIL); + } + assert (sn==bt_udata->node_ptr); + } else { + /* keep the node protected until we get back to H5G_stab_insert() */ } FUNC_LEAVE (ret_value); @@ -988,7 +990,7 @@ H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, * If we couldn't load the symbol table node, then try loading the * B-tree node. */ - if (NULL==(sn=H5AC_find(f, H5AC_SNODE, addr, NULL))) { + if (NULL==(sn=H5AC_find(f, H5AC_SNODE, addr, &ac_udata))) { H5ECLEAR; /*discard that error*/ status = H5B_debug (f, addr, stream, indent, fwidth, H5B_SNODE); if (status<0) HRETURN_ERROR (H5E_SYM, H5E_CANTLOAD, FAIL); @@ -1019,7 +1021,7 @@ H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, "Name:", s); } - H5G_debug (f, sn->entry+i, stream, indent, fwidth); + H5G_ent_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"); diff --git a/src/H5Gpkg.h b/src/H5Gpkg.h index c5ccae9..74881f7 100644 --- a/src/H5Gpkg.h +++ b/src/H5Gpkg.h @@ -16,6 +16,7 @@ #ifndef _H5Gpkg_H #define _H5Gpkg_H +#include <H5ACprivate.h> #include <H5Gprivate.h> #define H5G_NODE_VERS 1 /*symbol table node version number */ @@ -24,6 +25,20 @@ #define H5G_NODE_SIZEOF_HDR(F) (H5G_NODE_SIZEOF_MAGIC + 4) #define H5G_DEFAULT_ROOT_SIZE 32 +/* + * 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. + */ +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 */ + H5G_cache_t cache; /*cached data from object header */ + H5G_shadow_t *shadow; /*optional ptr to the shadow */ +}; /* * A shadow is a copy of a symbol table entry which corresponds to an @@ -68,7 +83,7 @@ typedef struct H5G_node_key_t { */ typedef enum H5G_oper_t { H5G_OPER_FIND =0, /*find a symbol */ - H5G_OPER_INSERT =1, /*insert a new symbol */ + H5G_OPER_INSERT =1 /*insert a new symbol */ } H5G_oper_t; /* @@ -87,7 +102,9 @@ typedef struct H5G_bt_ud1_t { /* downward for INSERT */ H5G_entry_t entry; /*entry to insert into table */ - /* upward for FIND */ + /* upward for FIND and INSERT */ + haddr_t node_addr; /*address of node for this entry */ + H5G_node_t *node_ptr; /*ptr to the node containing the entry */ H5G_entry_t *entry_ptr; /*ptr into cached symbol table node */ } H5G_bt_ud1_t; @@ -123,6 +140,9 @@ typedef struct H5G_ac_ud1_t { haddr_t dir_addr; } H5G_ac_ud1_t; +/* The cache subclass */ +extern const H5AC_class_t H5AC_SNODE[1]; + /* * Functions that understand symbol tables but not directories. The * functions that understand directories are exported to the rest of @@ -131,8 +151,8 @@ typedef struct H5G_ac_ud1_t { 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); +H5G_entry_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[]); @@ -147,12 +167,17 @@ 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_ac_ud1_t *ac_udata); -H5G_shadow_t *H5G_shadow_list (haddr_t stab_header_addr); +H5G_shadow_t *H5G_shadow_list (hdf5_file_t *f, haddr_t stab_header_addr); +herr_t H5G_shadow_move (hdf5_file_t *f, H5G_shadow_t *shadow, + const char *new_name, H5G_entry_t *new_entry, + haddr_t dir_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); +herr_t H5G_ent_decode_vec (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent, + intn n); +herr_t H5G_ent_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 dd26902..97355c2 100644 --- a/src/H5Gprivate.h +++ b/src/H5Gprivate.h @@ -25,7 +25,8 @@ #define H5G_NODE_MAGIC "SNOD" /*symbol table node magic number */ #define H5G_NODE_SIZEOF_MAGIC 4 /*sizeof symbol node magic number */ -#define H5G_new_entry() H5MM_xcalloc (1, sizeof(H5G_entry_t)) +#define H5G_NO_CHANGE (-1) /*see H5G_ent_modified() */ +#define H5G_NSHADOWS 10331 /*default size of shadow hash table */ /* * The disk size for a symbol table entry... @@ -75,41 +76,46 @@ typedef union H5G_cache_t { * important outside H5G. */ typedef struct H5G_shadow_t H5G_shadow_t; +typedef struct H5G_entry_t H5G_entry_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. + * Library prototypes... These are the ones that other packages routinely + * call. */ -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 */ - H5G_cache_t cache; /*cached data from object header */ - H5G_shadow_t *shadow; /*optional ptr to the shadow */ -} H5G_entry_t; - -/* - * Library prototypes... - */ -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); +H5G_entry_t *H5G_mkdir (hdf5_file_t *f, const char *name, size_t size_hint); +herr_t H5G_pushd (hdf5_file_t *f, const char *name); +herr_t H5G_popd (hdf5_file_t *f); +H5G_entry_t *H5G_create (hdf5_file_t *f, const char *name, size_t ohdr_hint); +H5G_entry_t *H5G_open (hdf5_file_t *f, 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_set_root (hdf5_file_t *f, const char *name, H5G_entry_t *ent); -herr_t H5G_encode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent); -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_ent_encode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent); +herr_t H5G_ent_decode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent); + +/* + * These functions operate on symbol table nodes. + */ herr_t H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, intn fwidth, haddr_t heap); +/* + * These functions operate on shadow entries. + */ +herr_t H5G_shadow_flush (hdf5_file_t *f, hbool_t invalidate); + +/* + * These functions operate on symbol table entries. They're used primarily + * in the H5O package where header messages are cached in symbol table + * entries. The subclasses of H5O probably don't need them though. + */ +H5G_entry_t *H5G_ent_calloc (void); +herr_t H5G_ent_invalidate (H5G_entry_t *ent); +haddr_t H5G_ent_addr (H5G_entry_t *ent); +H5G_cache_t *H5G_ent_cache (H5G_entry_t *ent, H5G_type_t *cache_type); +herr_t H5G_ent_modified (H5G_entry_t *ent, H5G_type_t cache_type); +herr_t H5G_ent_debug (hdf5_file_t *f, H5G_entry_t *ent, FILE *stream, + intn indent, intn fwidth); #endif diff --git a/src/H5Gshad.c b/src/H5Gshad.c index 6dc997f..315abed 100644 --- a/src/H5Gshad.c +++ b/src/H5Gshad.c @@ -15,13 +15,11 @@ #include <H5Oprivate.h> /*object header messages */ #define PABLO_MASK H5G_shadow_mask +#undef DEBUG_SHADOWS /* 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; @@ -29,8 +27,92 @@ typedef struct H5G_hash_t { struct H5G_hash_t *prev; } H5G_hash_t; -static H5G_hash_t *H5G_shadow_g[H5G_NSHADOWS]; - + +/*------------------------------------------------------------------------- + * Function: H5G_shadow_check + * + * Purpose: Checks the shadow data structures for validity. This is a + * debugging function only--it aborts on failure! + * + * Return: void + * + * Programmer: Robb Matzke + * Sunday, September 21, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +#ifdef DEBUG_SHADOWS +void +H5G_shadow_check (hdf5_file_t *f) +{ + H5G_hash_t *hash=NULL; + H5G_shadow_t *shadow=NULL, *prev_shadow=NULL; + uintn idx; + hbool_t shadow_error=FALSE; + uintn nerrors=0; + static int ncalls=0; + + ncalls++; + + for (idx=0; idx<f->nshadows; idx++) { + for (hash=f->shadow[idx]; hash; hash=hash->next) { + for (shadow=hash->head,prev_shadow=NULL; + shadow; + shadow=shadow->next) { + shadow_error = FALSE; + + /* Each shadow has a name and the names are in order */ + if (!shadow->name) { + fprintf (stderr, "name=NULL, "); + shadow_error = TRUE; + } + if (prev_shadow && strcmp (prev_shadow->name, shadow->name)>=0) { + fprintf (stderr, "names not sorted, "); + shadow_error = TRUE; + } + + /* Valid directory addresses */ + if (shadow->dir_addr<0 || (shadow->dir_addr==0 && idx!=0)) { + fprintf (stderr, "dir_addr=%lu, ", + (unsigned long)(shadow->dir_addr)); + shadow_error = TRUE; + } else if (shadow->dir_addr!=hash->dir_addr) { + fprintf (stderr, "dir_addr=%lu (not %lu), ", + (unsigned long)(shadow->dir_addr), + (unsigned long)(hash->dir_addr)); + } + + /* Linked to symbol table entry */ + if (shadow->main && shadow!=shadow->main->shadow) { + fprintf (stderr, "entry linkage problem, "); + shadow_error = TRUE; + } + + /* Shadow linked list is consistent */ + if (shadow->prev && prev_shadow!=shadow->prev) { + fprintf (stderr, "shadow linked list problem, "); + shadow_error = TRUE; + } + prev_shadow = shadow; + + /* If an error occurred then print other info */ + if (shadow_error) { + fprintf (stderr, "idx=%u, shadow=0x%08lx, dir_addr=%lu\n", + idx, (unsigned long)shadow, + (unsigned long)(shadow->dir_addr)); + nerrors++; + } + } + } + } + if (nerrors) { + fprintf (stderr, "Error in H5G_shadow_check, call %d\n", ncalls); + abort (); + } +} +#endif /*------------------------------------------------------------------------- @@ -171,14 +253,14 @@ H5G_shadow_sync (H5G_entry_t *ent) *------------------------------------------------------------------------- */ H5G_shadow_t * -H5G_shadow_list (haddr_t dir_addr) +H5G_shadow_list (hdf5_file_t *f, haddr_t dir_addr) { - uintn idx = dir_addr % H5G_NSHADOWS; + uintn idx = dir_addr % f->nshadows; H5G_hash_t *bucket = NULL; FUNC_ENTER (H5G_shadows, NULL, NULL); - for (bucket=H5G_shadow_g[idx]; bucket; bucket=bucket->next) { + for (bucket=f->shadow[idx]; bucket; bucket=bucket->next) { if (bucket->dir_addr==dir_addr) { HRETURN (bucket->head); } @@ -223,7 +305,11 @@ H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, H5G_ac_ud1_t *ac_udata) assert (sym); /* The symbol table node */ assert (ac_udata); /* The symbol table header info */ - if ((shadow=H5G_shadow_list (ac_udata->dir_addr))) { +#ifdef DEBUG_SHADOWS + H5G_shadow_check (f); +#endif + + if ((shadow=H5G_shadow_list (f, ac_udata->dir_addr))) { heap_addr = ac_udata->heap_addr; while (i<sym->nsyms && shadow) { @@ -240,6 +326,8 @@ H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, H5G_ac_ud1_t *ac_udata) if (i<sym->nsyms && s && shadow && !strcmp (s, shadow->name)) { shadow->main = sym->entry + i; sym->entry[i].shadow = shadow; + i++; + shadow = shadow->next; } } } @@ -247,7 +335,6 @@ H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, H5G_ac_ud1_t *ac_udata) FUNC_LEAVE (SUCCEED); } - /*------------------------------------------------------------------------- * Function: H5G_shadow_open @@ -257,6 +344,8 @@ H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, H5G_ac_ud1_t *ac_udata) * object, open the object (again) and return a handle * to it. * + * DIR can be the null pointer if `ent' is the root entry. + * * Return: Success: Handle to open object * * Failure: NULL @@ -275,89 +364,109 @@ H5G_shadow_open (hdf5_file_t *f, H5G_entry_t *dir, H5G_entry_t *ent) H5O_stab_t stab; const char *s = NULL; H5G_hash_t *hash = NULL; - H5G_shadow_t *hash_ent = NULL; + H5G_shadow_t *hash_ent = NULL, *prev_ent = NULL; uintn idx; H5O_name_t name_mesg = {NULL}; H5G_entry_t *ret_value = NULL; + haddr_t dir_addr; FUNC_ENTER (H5G_shadow_open, NULL, NULL); /* check args */ assert (f); - assert (dir); + assert (ent==f->root_sym || dir); assert (ent); + dir_addr = dir ? dir->header : 0; - if (ent->shadow) { + if ((shadow = 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"); - } + shadow->nrefs += 1; + HRETURN (&(shadow->entry)); + } - } 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); - } - + + shadow = H5MM_xcalloc (1, sizeof(H5G_shadow_t)); + if (ent==f->root_sym && 0==dir_addr) { /* - * Build the new shadow. + * We're opening the root entry. */ - ent->shadow = shadow; - shadow->main = ent; - shadow->nrefs = 1; - shadow->entry = *ent; - shadow->entry.dirty = FALSE; - shadow->dir_addr = dir->header; - + 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 { /* - * Link it into the shadow heap + * Some entry other than the root. */ - idx = dir->header % H5G_NSHADOWS; - for (hash=H5G_shadow_g[idx]; hash; hash=hash->next) { - if (hash->dir_addr==dir->header) break; + if (NULL==H5O_read (f, NO_ADDR, dir, H5O_STAB, 0, &stab)) { + HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); } - 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; + if (NULL==(s=H5H_peek (f, stab.heap_addr, ent->name_off))) { + HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); } - for (hash_ent=hash->head; hash_ent; hash_ent=hash_ent->next) { + 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_addr; + + /* + * Link it into the shadow heap + */ + idx = dir_addr % f->nshadows; + for (hash=f->shadow[idx]; hash; hash=hash->next) { + if (hash->dir_addr==dir_addr) break; + } + if (!hash) { + hash = H5MM_xcalloc (1, sizeof(H5G_hash_t)); + hash->dir_addr = dir_addr; + hash->next = f->shadow[idx]; + f->shadow[idx] = hash; + if (hash->next) hash->next->prev = hash; + } + if (hash->head) { + for (hash_ent=hash->head,prev_ent=NULL; + hash_ent; + hash_ent=hash_ent->next) { if (strcmp (shadow->name, hash_ent->name)<0) break; + prev_ent = hash_ent; } if (hash_ent) { + /* Insert SHADOW before 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; + /* Append SHADOW to list */ + assert (prev_ent && NULL==prev_ent->next); + prev_ent->next = shadow; + shadow->prev = prev_ent; } + } else { + /* Insert shadow at head of list */ + shadow->next = hash->head; + if (hash->head) hash->head->prev = shadow; + hash->head = shadow; } +#ifdef DEBUG_SHADOWS + H5G_shadow_check (f); +#endif + ret_value = &(shadow->entry); done: @@ -423,8 +532,8 @@ H5G_shadow_close (hdf5_file_t *f, H5G_entry_t *ent) H5G_shadow_dissociate (ent); /* find symtabs shadow list */ - idx = shadow->dir_addr % H5G_NSHADOWS; - for (hash=H5G_shadow_g[idx]; hash; hash=hash->next) { + idx = shadow->dir_addr % f->nshadows; + for (hash=f->shadow[idx]; hash; hash=hash->next) { if (hash->dir_addr==shadow->dir_addr) break; } assert (hash); @@ -445,7 +554,7 @@ H5G_shadow_close (hdf5_file_t *f, H5G_entry_t *ent) /* 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; + else f->shadow[idx] = hash->next; if (hash->next) hash->next->prev = hash->prev; H5MM_xfree (hash); } @@ -453,3 +562,153 @@ H5G_shadow_close (hdf5_file_t *f, H5G_entry_t *ent) FUNC_LEAVE (SUCCEED); } + + + +/*------------------------------------------------------------------------- + * Function: H5G_shadow_move + * + * Purpose: Moves the SHADOW for some entry to correspond to a + * NEW_ENTRY. The DIR_ADDR is the address for the directory + * which contains NEW_ENTRY. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, September 19, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_shadow_move (hdf5_file_t *f, H5G_shadow_t *shadow, const char *new_name, + H5G_entry_t *new_entry, haddr_t dir_addr) +{ + H5G_hash_t *hash; + uintn idx; + + FUNC_ENTER (H5G_shadow_move, NULL, FAIL); + + assert (shadow); + assert (new_entry); + assert (dir_addr>0); + + if (0==shadow->dir_addr) { + /* + * We're moving the shadow for the root object. This simplifies things + * greatly since it implies that this is the only shadow currently + * defined for the entire file. + */ + idx = dir_addr % f->nshadows; + assert (NULL==f->shadow[idx]); /*Nothing at new idx... */ + hash = f->shadow[0]; + assert (hash); /*..but root idx has something. */ + assert (0==hash->dir_addr); /*..and it's the root something */ + assert (NULL==hash->next); /*..and just that */ + assert (hash->head==shadow); /*..and exactly that */ + + /* Move root entry to new hash bucket */ + f->shadow[idx] = hash; + f->shadow[0] = NULL; + hash->dir_addr = dir_addr; + + /* Associate SHADOW with NEW_ENTRY */ + shadow->dir_addr = dir_addr; + shadow->main = new_entry; + new_entry->shadow = shadow; + + /* Give the shadow a new name */ + H5MM_xfree (shadow->name); + shadow->name = H5MM_xstrdup (new_name); + + } else { + /* + * Other shadows never move. + */ + assert (shadow->dir_addr==dir_addr); + shadow->main = new_entry; + new_entry->shadow = shadow; + } + + FUNC_LEAVE (SUCCEED); +} + + + +/*------------------------------------------------------------------------- + * Function: H5G_shadow_flush + * + * Purpose: Flush all open object information to the main cache. + * + * Return: Success: SUCCEED + * + * Failure: FAIL if INVALIDATE is non-zero and there are + * open objects. + * + * Programmer: Robb Matzke + * Friday, September 19, 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_shadow_flush (hdf5_file_t *f, hbool_t invalidate) +{ + uintn idx; + H5G_hash_t *hash = NULL; + H5G_shadow_t *shadow = NULL; + intn nfound=0; + + FUNC_ENTER (H5G_shadow_flush, NULL, FAIL); + + for (idx=0; idx<f->nshadows; idx++) { + for (hash=f->shadow[idx]; hash; hash=hash->next) { + for (shadow=hash->head; shadow; shadow=shadow->next) { + 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) = shadow->entry; + shadow->entry.dirty = FALSE; + nfound++; + +#ifndef NDEBUG + /* + * This is usually a bad thing--an hdf5 programmer forgot to + * close some object before closing the file. Since this is hard + * to debug, we'll be nice and print the names here. We don't + * know the full name, but we'll print the file address (relative + * to the boot block) of the object header for the directory that + * contains the open object. + */ + if (invalidate) { + fprintf (stderr, "Open object <%lu>/%s", + (unsigned long)(shadow->dir_addr), + shadow->name); + if (shadow->nrefs>1) { + fprintf (stderr, " (%d times)", shadow->nrefs); + } + fputc ('\n', stderr); + } +#endif + } + } + } + + if (invalidate && nfound) { + /* + * No clean easy way to do this, just leak the memory. If we free a + * shadow and then something else tries to access it (perhaps to close + * it) then they trample on freed memory. + */ + HRETURN_ERROR (H5E_SYM, H5E_UNSUPPORTED, FAIL); + } + + FUNC_LEAVE (SUCCEED); +} diff --git a/src/H5Gstab.c b/src/H5Gstab.c new file mode 100644 index 0000000..209cbc4 --- /dev/null +++ b/src/H5Gstab.c @@ -0,0 +1,345 @@ +/* + * Copyright (C) 1997 National Center for Supercomputing Applications + * All rights reserved. + * + * Programmer: Robb Matzke <matzke@llnl.gov> + * Friday, September 19, 1997 + * + */ +#define H5G_PACKAGE + +#include <H5private.h> +#include <H5ACprivate.h> +#include <H5Eprivate.h> +#include <H5Gpkg.h> +#include <H5Hprivate.h> +#include <H5MMprivate.h> +#include <H5Oprivate.h> + +#define PABLO_MASK H5G_stab_mask +static hbool_t interface_initialize_g = FALSE; + + +/*------------------------------------------------------------------------- + * Function: H5G_stab_new + * + * Purpose: Creates a new empty symbol table (object header, name heap, + * and B-tree). The caller can specify an initial size for the + * name heap. + * + * In order for the B-tree to operate correctly, the first + * item in the heap is the empty string, and must appear at + * heap offset zero. + * + * Errors: + * INTERNAL CANTINIT B-tree's won't work if the first + * name isn't at the beginning of the + * heap. + * SYM CANTINIT Can't create B-tree. + * SYM CANTINIT Can't create header. + * SYM CANTINIT Can't create heap. + * SYM CANTINIT Can't create message. + * SYM CANTINIT Can't initialize heap. + * + * Return: Success: Address of new symbol table header. If + * the caller supplies a symbol table entry + * SELF then it will be initialized to point to + * this symbol table. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 1 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +haddr_t +H5G_stab_new (hdf5_file_t *f, H5G_entry_t *self, size_t init) +{ + off_t name; /*offset of "" name */ + haddr_t addr; /*object header address */ + H5O_stab_t stab; /*symbol table message */ + + FUNC_ENTER (H5G_stab_new, NULL, FAIL); + + /* + * Check arguments. + */ + assert (f); + init = MAX(init, H5H_SIZEOF_FREE(f)+2); + + /* Create symbol table private heap */ + if ((stab.heap_addr = H5H_new (f, H5H_LOCAL, init))<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't create heap*/ + } + if ((name = H5H_insert (f, stab.heap_addr, 1, "")<0)) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't initialize heap*/ + } + if (0!=name) { + /* + * B-tree's won't work if the first name isn't at the beginning + * of the heap. + */ + HRETURN_ERROR (H5E_INTERNAL, H5E_CANTINIT, FAIL); + } + + /* Create the B-tree */ + if ((stab.btree_addr = H5B_new (f, H5B_SNODE))<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't create B-tree*/ + } + + /* + * Create symbol table object header. It has a zero link count + * since nothing refers to it yet. The link count will be + * incremented if the object is added to the directory hierarchy. + */ + if ((addr = H5O_new (f, 0, 4+2*H5F_SIZEOF_OFFSET(f)))<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't create header*/ + } + + /* insert the symbol table message */ + if (self) { + memset (self, 0, sizeof(H5G_entry_t)); + self->header = addr; + } + if (H5O_modify(f, addr, self, H5O_STAB, H5O_NEW_MESG, &stab)<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); /*can't create message*/ + } + + FUNC_LEAVE (addr); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_stab_find + * + * Purpose: Finds a symbol named NAME in the symbol table whose + * description is stored in SELF in file F and returns a + * 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: 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: NULL + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 1 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +H5G_entry_t * +H5G_stab_find (hdf5_file_t *f, haddr_t addr, H5G_entry_t *self, + const char *name) +{ + H5G_bt_ud1_t udata; /*data to pass through B-tree */ + H5O_stab_t stab; /*symbol table message */ + + FUNC_ENTER (H5G_stab_find, NULL, NULL); + + /* Check arguments */ + assert (f); + 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, 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; + udata.node_ptr = NULL; + + /* search the B-tree */ + if (H5B_find (f, H5B_SNODE, stab.btree_addr, &udata)<0) { + if (udata.node_ptr) { + H5AC_unprotect (f, H5AC_SNODE, udata.node_addr, udata.node_ptr); + } + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, NULL); /*not found*/ + } + + /* Unprotect the symbol table node */ + if (udata.node_ptr) { + if (H5AC_unprotect (f, H5AC_SNODE, udata.node_addr, udata.node_ptr)<0) { + HRETURN_ERROR (H5E_SYM, H5E_PROTECT, NULL); + } + } + + /* return the result */ + FUNC_LEAVE (udata.entry_ptr); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_stab_insert + * + * Purpose: Insert a new symbol into the table described by SELF in + * file F. The name of the new symbol is NAME and its symbol + * table entry is ENT. + * + * Errors: + * SYM BADMESG Can't read message. + * SYM CANTINSERT Can't insert entry. + * + * Return: Success: Pointer to the cached symbol table entry. + * This is a pointer directly into a symbol + * table node and will become invalid on the + * next call to the H5AC package. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 1 1997 + * + * 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. + * + *------------------------------------------------------------------------- + */ +H5G_entry_t * +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_bt_ud1_t udata; /*data to pass through B-tree */ + + FUNC_ENTER (H5G_stab_insert, NULL, NULL); + + /* check arguments */ + assert (f); + assert (self && self->header>=0); + assert (name && *name); + assert (ent); + + /* initialize data to pass through B-tree */ + if (NULL==H5O_read (f, self->header, self, H5O_STAB, 0, &stab)) { + HRETURN_ERROR (H5E_SYM, H5E_BADMESG, NULL); /*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; + udata.node_ptr = NULL; + + /* insert */ + if (H5B_insert (f, H5B_SNODE, stab.btree_addr, &udata)<0) { + if (udata.node_ptr) { + H5AC_unprotect (f, H5AC_SNODE, udata.node_addr, udata.node_ptr); + } + HRETURN_ERROR (H5E_SYM, H5E_CANTINSERT, NULL); /*can't insert entry*/ + } + + /* + * The H5G_node_insert() called H5AC_protect() for the node so that the + * udata.entry_ptr field didn't become invalid on the way back out of the + * B-tree code. We unprotect it now, but the pointer will remain valid + * until the next call to H5AC. + */ + if (H5AC_unprotect (f, H5AC_SNODE, udata.node_addr, udata.node_ptr)<0) { + HRETURN_ERROR (H5E_SYM, H5E_PROTECT, NULL); /*can't unprotect*/ + } + + /* update the name offset in the entry */ + ent->name_off = udata.entry.name_off; + FUNC_LEAVE (udata.entry_ptr); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_stab_list + * + * Purpose: Returns a list of all the symbols in a symbol table. + * The caller allocates an array of pointers which this + * function will fill in with malloc'd names. The caller + * also allocates an array of symbol table entries which will + * be filled in with data from the symbol table. Each of these + * arrays should have at least MAXENTRIES elements. + * + * Errors: + * SYM BADMESG Not a symbol table. + * SYM CANTLIST B-tree list failure. + * + * Return: Success: The total number of symbols in the + * symbol table. This may exceed MAXENTRIES, + * but at most MAXENTRIES values are copied + * into the NAMES and ENTRIES arrays. + * + * Failure: FAIL, the pointers in NAMES are undefined but + * no memory is allocated. The values in + * ENTRIES are undefined. + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 1 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +intn +H5G_stab_list (hdf5_file_t *f, H5G_entry_t *self, intn maxentries, + char *names[], H5G_entry_t entries[]) +{ + H5G_bt_ud2_t udata; + H5O_stab_t stab; + intn i; + + FUNC_ENTER (H5G_stab_list, NULL, FAIL); + + /* check args */ + assert (f); + assert (self && self->header>=0); + assert (maxentries>=0); + + /* initialize data to pass through B-tree */ + if (NULL==H5O_read (f, self->header, self, H5O_STAB, 0, &stab)) { + HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL); /*not a symbol table*/ + } + udata.entry = entries; + udata.name = names; + udata.dir_addr = self->header; + udata.heap_addr = stab.heap_addr; + udata.maxentries = maxentries; + udata.nsyms = 0; + if (names) HDmemset (names, 0, maxentries); + + /* list */ + if (H5B_list (f, H5B_SNODE, stab.btree_addr, &udata)<0) { + if (names) { + for (i=0; i<maxentries; i++) H5MM_xfree (names[i]); + } + HRETURN_ERROR (H5E_SYM, H5E_CANTLIST, FAIL); /*B-tree list failure*/ + } + + FUNC_LEAVE (udata.nsyms); +} + @@ -501,16 +501,17 @@ H5O_reset (const H5O_class_t *type, void *native) *------------------------------------------------------------------------- */ intn -H5O_link (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, intn adjust) +H5O_link (hdf5_file_t *f, H5G_entry_t *ent, intn adjust) { H5O_t *oh = NULL; + haddr_t addr; FUNC_ENTER (H5O_link, NULL, FAIL); /* check args */ assert (f); - assert (addr>0 || (ent && ent->header>0)); - if (addr<=0) addr = ent->header; + assert (ent && H5G_ent_addr (ent)>0); + addr = H5G_ent_addr (ent); /* get header */ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) { @@ -529,10 +530,7 @@ H5O_link (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, intn adjust) } } else { oh->nlink += adjust; - if (oh->nlink>1 && ent && H5G_NOTHING_CACHED!=ent->type) { - ent->dirty = TRUE; - ent->type = H5G_NOTHING_CACHED; - } + if (oh->nlink>1) H5G_ent_invalidate (ent); } oh->dirty = TRUE; @@ -568,22 +566,29 @@ H5O_read (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, H5O_t *oh = NULL; void *retval = NULL; intn idx; + H5G_cache_t *cache = NULL; + H5G_type_t cache_type; FUNC_ENTER (H5O_read, NULL, NULL); /* check args */ assert (f); - if (addr<=0 && (!ent || ent->header<=0)) { + if (addr<=0 && !ent) { + HRETURN_ERROR (H5E_OHDR, H5E_NOTFOUND, NULL); + } + if (addr<=0 && (addr=H5G_ent_addr (ent))<=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? */ - if (ent && H5G_NOTHING_CACHED!=ent->type && type && type->fast) { - retval = (type->fast)(ent, mesg); - if (retval) HRETURN (retval); - H5ECLEAR; + if (ent) { + cache = H5G_ent_cache (ent, &cache_type); + if (type && cache_type==type->cache_type && type->fast) { + retval = (type->fast)(cache, mesg); + if (retval) HRETURN (retval); + H5ECLEAR; + } } /* can we get it from the object header? */ @@ -759,10 +764,10 @@ H5O_modify (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, /* check args */ assert (f); - assert (addr>0 || (ent && ent->header>0)); + assert (addr>0 || (ent && H5G_ent_addr (ent)>0)); assert (type); assert (mesg); - if (addr<=0) addr = ent->header; + if (addr<=0) addr = H5G_ent_addr (ent); if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) { HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, FAIL); @@ -805,8 +810,11 @@ 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 (ent && !ent->dirty) ent->dirty = modified; + H5G_type_t cache_type; + H5G_cache_t *cache = H5G_ent_cache (ent, &cache_type); + hbool_t modified = (type->cache)(&cache_type, cache, mesg); + if (modified) H5G_ent_modified (ent, cache_type); + } FUNC_LEAVE (sequence); @@ -854,9 +862,9 @@ H5O_remove (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, /* check args */ assert (f); - assert (addr>0 || (ent && ent->header>0)); + assert (addr>0 || (ent && H5G_ent_addr (ent)>0)); assert (type); - if (addr<=0) addr = ent->header; + if (addr<=0) addr = H5G_ent_addr (ent); /* load the object header */ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) { @@ -866,11 +874,12 @@ H5O_remove (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, for (i=seq=0; i<oh->nmesgs; i++) { if (type->id != oh->mesg[i].type->id) continue; if (seq++ == sequence || H5O_ALL==sequence) { + H5G_type_t cache_type; + H5G_ent_cache (ent, &cache_type); /* clear symbol table entry cache */ - if (ent && type->cache && type->cache_type==ent->type) { - ent->type = H5G_NOTHING_CACHED; - ent->dirty = TRUE; + if (ent && type->cache && type->cache_type==cache_type) { + H5G_ent_invalidate (ent); } /* change message type to nil and zero it */ diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 30b0af1..d5666eb 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -50,8 +50,8 @@ typedef struct H5O_class_t { 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*/ - hbool_t (*cache)(H5G_entry_t*,const void*); /*put into entry */ + void *(*fast)(const H5G_cache_t*, void*);/*get from of entry */ + hbool_t (*cache)(H5G_type_t*, H5G_cache_t*,const void*); /*into entry*/ void *(*copy)(const void*,void*); /*copy native value */ size_t (*raw_size)(hdf5_file_t*,const void*); /*sizeof raw val */ herr_t (*reset)(void*); /*free nested data structures */ @@ -158,7 +158,7 @@ typedef struct H5O_stab_t { haddr_t H5O_new (hdf5_file_t *f, intn nlink, size_t size_hint); -intn H5O_link (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, intn adjust); +intn H5O_link (hdf5_file_t *f, H5G_entry_t *ent, intn adjust); void *H5O_read (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, const H5O_class_t *type, intn sequence, void *mesg); const void *H5O_peek (hdf5_file_t *f, haddr_t addr, const H5O_class_t *type, diff --git a/src/H5Osdim.c b/src/H5Osdim.c index 923ceea..312249b 100644 --- a/src/H5Osdim.c +++ b/src/H5Osdim.c @@ -41,8 +41,9 @@ static char RcsId[] = "@(#)$Revision$"; static void *H5O_sim_dim_decode (hdf5_file_t *f, size_t raw_size, const uint8 *p); static herr_t H5O_sim_dim_encode (hdf5_file_t *f, size_t size, uint8 *p, const void *_mesg); -static void *H5O_sim_dim_fast (const H5G_entry_t *ent, void *_mesg); -static hbool_t H5O_sim_dim_cache (H5G_entry_t *ent, const void *_mesg); +static void *H5O_sim_dim_fast (const H5G_cache_t *cache, void *_mesg); +static hbool_t H5O_sim_dim_cache (H5G_type_t *cache_type, H5G_cache_t *cache, + const void *_mesg); static void *H5O_sim_dim_copy (const void *_mesg, void *_dest); static size_t H5O_sim_dim_size (hdf5_file_t *f, const void *_mesg); static herr_t H5O_sim_dim_debug (hdf5_file_t *f, const void *_mesg, @@ -208,7 +209,7 @@ H5O_sim_dim_encode (hdf5_file_t *f, size_t raw_size, uint8 *p, const void *mesg) for simple dimensionality, as they can be cached in the symbol-table entry) --------------------------------------------------------------------------*/ static void * -H5O_sim_dim_fast (const H5G_entry_t *ent, void *mesg) +H5O_sim_dim_fast (const H5G_cache_t *cache, void *mesg) { H5O_sim_dim_t *sdim = (H5O_sim_dim_t *)mesg; uintn u; /* local counting variable */ @@ -216,19 +217,15 @@ H5O_sim_dim_fast (const H5G_entry_t *ent, void *mesg) FUNC_ENTER (H5O_sim_dim_fast, NULL, NULL); /* check args */ - assert (ent); - - if (H5G_CACHED_SDATA==ent->type) { - if (!sdim) sdim = H5MM_xcalloc (1, sizeof(H5O_sim_dim_t)); - sdim->rank = ent->cache.sdata.ndim; - assert (sdim->rank<=NELMTS (ent->cache.sdata.dim)); - sdim->dim_flags = 0; - sdim->size = H5MM_xmalloc (sizeof(uint32) * sdim->rank); - for (u=0; u<sdim->rank; u++) { - sdim->size[u] = ent->cache.sdata.dim[u]; - } - } else { - sdim = NULL; + assert (cache); + + if (!sdim) sdim = H5MM_xcalloc (1, sizeof(H5O_sim_dim_t)); + sdim->rank = cache->sdata.ndim; + assert (sdim->rank<=NELMTS (cache->sdata.dim)); + sdim->dim_flags = 0; + sdim->size = H5MM_xmalloc (sizeof(uint32) * sdim->rank); + for (u=0; u<sdim->rank; u++) { + sdim->size[u] = cache->sdata.dim[u]; } FUNC_LEAVE (sdim); @@ -246,6 +243,7 @@ H5O_sim_dim_fast (const H5G_entry_t *ent, void *mesg) const void *mesg; IN: Pointer to the simple dimensionality struct RETURNS BTRUE if symbol-table modified, BFALSE if not modified, BFAIL on failure. + The new cache type is returned through the CACHE_TYPE argument. DESCRIPTION This function is the opposite of the H5O_sim_dim_fast method, it copies a message into the cached portion of a symbol-table entry. (This @@ -253,7 +251,8 @@ H5O_sim_dim_fast (const H5G_entry_t *ent, void *mesg) the symbol-table entry) --------------------------------------------------------------------------*/ static hbool_t -H5O_sim_dim_cache (H5G_entry_t *ent, const void *mesg) +H5O_sim_dim_cache (H5G_type_t *cache_type, H5G_cache_t *cache, + const void *mesg) { const H5O_sim_dim_t *sdim = (const H5O_sim_dim_t *)mesg; uintn u; /* Local counting variable */ @@ -262,41 +261,42 @@ H5O_sim_dim_cache (H5G_entry_t *ent, const void *mesg) FUNC_ENTER (H5O_sim_dim_cache, NULL, BFAIL); /* check args */ - assert (ent); + assert (cache_type); + assert (cache); assert (sdim); - if (sdim->rank <= NELMTS (ent->cache.sdata.dim)) { - if (H5G_CACHED_SDATA != ent->type) { + if (sdim->rank <= NELMTS (cache->sdata.dim)) { + if (H5G_CACHED_SDATA != *cache_type) { modified = BTRUE; - ent->type = H5G_CACHED_SDATA; - ent->cache.sdata.ndim = sdim->rank; + *cache_type = H5G_CACHED_SDATA; + cache->sdata.ndim = sdim->rank; for (u=0; u<=sdim->rank; u++) { - ent->cache.sdata.dim[u] = sdim->size[u]; + cache->sdata.dim[u] = sdim->size[u]; } } else { - if(ent->cache.sdata.ndim!= sdim->rank) { + if(cache->sdata.ndim != sdim->rank) { modified = BTRUE; - ent->cache.sdata.ndim = sdim->rank; + cache->sdata.ndim = sdim->rank; } /* Check each dimension */ - if (NULL==ent->cache.sdata.dim) { + if (NULL==cache->sdata.dim) { modified = BTRUE; } else { for (u=0; u<sdim->rank; u++) { - if (ent->cache.sdata.dim[u] != sdim->size[u]) { + if (cache->sdata.dim[u] != sdim->size[u]) { modified = BTRUE; - ent->cache.sdata.dim[u] = sdim->size[u]; + cache->sdata.dim[u] = sdim->size[u]; } } } } - } else if (H5G_CACHED_SDATA == ent->type) { + } else if (H5G_CACHED_SDATA == *cache_type) { /* * Number of dimensions is too large to cache. */ modified = TRUE; - ent->type = H5G_NOTHING_CACHED; + *cache_type = H5G_NOTHING_CACHED; } FUNC_LEAVE (modified); @@ -330,25 +330,23 @@ H5O_sim_dim_copy (const void *mesg, void *dest) if (!dst) dst = H5MM_xcalloc (1, sizeof(H5O_sim_dim_t)); - /* copy */ + /* deep copy -- pointed-to values are copied also */ HDmemcpy(dst,src,sizeof(H5O_sim_dim_t)); + if (src->size) dst->size = H5MM_xcalloc (src->rank, sizeof(uint32)); + if (src->max) dst->max = H5MM_xcalloc (src->rank, sizeof(uint32)); + if (src->perm) dst->perm = H5MM_xcalloc (src->rank, sizeof(uint32)); + if(src->rank>0) { - if(dst->size==NULL) - dst->size = H5MM_xcalloc (src->rank, sizeof(uint32)); HDmemcpy(dst->size,src->size,src->rank*sizeof(uint32)); /* Check for maximum dimensions and copy those */ if((src->dim_flags&0x01)>0) { - if(dst->max==NULL) - dst->max = H5MM_xcalloc (src->rank, sizeof(uint32)); HDmemcpy(dst->max,src->max,src->rank*sizeof(uint32)); } /* end if */ /* Check for dimension permutation and copy those */ if((src->dim_flags&0x02)>0) { - if(dst->max==NULL) - dst->perm = H5MM_xcalloc (src->rank, sizeof(uint32)); HDmemcpy(dst->perm,src->perm,src->rank*sizeof(uint32)); } /* end if */ } /* end if */ diff --git a/src/H5Osdtyp.c b/src/H5Osdtyp.c index 8920625..08fbba4 100644 --- a/src/H5Osdtyp.c +++ b/src/H5Osdtyp.c @@ -41,8 +41,9 @@ static char RcsId[] = "@(#)$Revision$"; static void *H5O_sim_dtype_decode (hdf5_file_t *f, size_t raw_size, const uint8 *p); static herr_t H5O_sim_dtype_encode (hdf5_file_t *f, size_t size, uint8 *p, const void *_mesg); -static void *H5O_sim_dtype_fast (const H5G_entry_t *ent, void *_mesg); -static hbool_t H5O_sim_dtype_cache (H5G_entry_t *ent, const void *_mesg); +static void *H5O_sim_dtype_fast (const H5G_cache_t *cache, void *_mesg); +static hbool_t H5O_sim_dtype_cache (H5G_type_t *cache_type, H5G_cache_t *cache, + const void *_mesg); static void *H5O_sim_dtype_copy (const void *_mesg, void *_dest); static size_t H5O_sim_dtype_size (hdf5_file_t *f, const void *_mesg); static herr_t H5O_sim_dtype_debug (hdf5_file_t *f, const void *_mesg, @@ -166,25 +167,21 @@ H5O_sim_dtype_encode (hdf5_file_t *f, size_t raw_size, uint8 *p, const void *mes for simple datatypes, as they can be cached in the symbol-table entry) --------------------------------------------------------------------------*/ static void * -H5O_sim_dtype_fast (const H5G_entry_t *ent, void *mesg) +H5O_sim_dtype_fast (const H5G_cache_t *cache, void *mesg) { H5O_sim_dtype_t *sdtype = (H5O_sim_dtype_t *)mesg; FUNC_ENTER (H5O_sim_dtype_fast, NULL, NULL); /* check args */ - assert (ent); + assert (cache); - if (H5G_CACHED_SDATA==ent->type) { - if (!sdtype) sdtype = H5MM_xcalloc (1, sizeof(H5O_sim_dtype_t)); - sdtype->len = ent->cache.sdata.nt.length; - sdtype->arch = ent->cache.sdata.nt.arch; + if (!sdtype) sdtype = H5MM_xcalloc (1, sizeof(H5O_sim_dtype_t)); + sdtype->len = cache->sdata.nt.length; + sdtype->arch = cache->sdata.nt.arch; - /* Convert into atomic base type. */ - sdtype->base = MAKE_ATOM (H5_DATATYPE, ent->cache.sdata.nt.type); - } else { - sdtype = NULL; - } + /* Convert into atomic base type. */ + sdtype->base = MAKE_ATOM (H5_DATATYPE, cache->sdata.nt.type); FUNC_LEAVE (sdtype); } /* end H5O_sim_dtype_fast() */ @@ -201,50 +198,54 @@ H5O_sim_dtype_fast (const H5G_entry_t *ent, void *mesg) const void *mesg; IN: Pointer to the simple datatype struct RETURNS BTRUE if symbol-table modified, BFALSE if not modified, BFAIL on failure. + The new cache type is returned through the CACHE_TYPE argument. DESCRIPTION This function is the opposite of the H5O_sim_dtype_fast method, it copies a message into the cached portion of a symbol-table entry. (This method is required for simple datatypes, as they can be cached in the symbol-table entry) --------------------------------------------------------------------------*/ -static hbool_t -H5O_sim_dtype_cache (H5G_entry_t *ent, const void *mesg) +static herr_t +H5O_sim_dtype_cache (H5G_type_t *cache_type, H5G_cache_t *cache, + const void *mesg) { const H5O_sim_dtype_t *sdtype = (const H5O_sim_dtype_t *)mesg; hbool_t modified = BFALSE; - + FUNC_ENTER (H5O_sim_dtype_cache, NULL, BFAIL); /* check args */ - assert (ent); + assert (cache_type); + assert (cache); assert (sdtype); - if (H5G_CACHED_SDATA != ent->type) { + if (H5G_CACHED_SDATA != *cache_type) { /* * No sdata cached yet. */ modified = BTRUE; - ent->type = H5G_CACHED_SDATA; - ent->cache.sdata.nt.length = sdtype->len; - ent->cache.sdata.nt.arch = sdtype->arch; - ent->cache.sdata.nt.type = sdtype->base; + *cache_type = H5G_CACHED_SDATA; + cache->sdata.nt.length = sdtype->len; + cache->sdata.nt.arch = sdtype->arch; + cache->sdata.nt.type = sdtype->base; + } else { /* * Some sdata already cached. */ - if (ent->cache.sdata.nt.length != sdtype->len) { + if (cache->sdata.nt.length != sdtype->len) { modified = BTRUE; - ent->cache.sdata.nt.length = sdtype->len; + cache->sdata.nt.length = sdtype->len; } - if (ent->cache.sdata.nt.arch != sdtype->arch) { + if (cache->sdata.nt.arch != sdtype->arch) { modified = BTRUE; - ent->cache.sdata.nt.arch = sdtype->arch; + cache->sdata.nt.arch = sdtype->arch; } - if (ent->cache.sdata.nt.type != (uint16)sdtype->base) { + if (cache->sdata.nt.type != (uint16)sdtype->base) { modified = BTRUE; - ent->cache.sdata.nt.type = (uint16)sdtype->base; + cache->sdata.nt.type = (uint16)sdtype->base; } } diff --git a/src/H5Ostab.c b/src/H5Ostab.c index 0b67a73..c4bb67c 100644 --- a/src/H5Ostab.c +++ b/src/H5Ostab.c @@ -26,8 +26,9 @@ static void *H5O_stab_decode (hdf5_file_t *f, size_t raw_size, const uint8 *p); static herr_t H5O_stab_encode (hdf5_file_t *f, size_t size, uint8 *p, const void *_mesg); -static void *H5O_stab_fast (const H5G_entry_t *ent, void *_mesg); -static hbool_t H5O_stab_cache (H5G_entry_t *ent, const void *_mesg); +static void *H5O_stab_fast (const H5G_cache_t *cache, void *_mesg); +static hbool_t H5O_stab_cache (H5G_type_t *cache_type, H5G_cache_t *cache, + const void *_mesg); static void *H5O_stab_copy (const void *_mesg, void *_dest); static size_t H5O_stab_size (hdf5_file_t *f, const void *_mesg); static herr_t H5O_stab_debug (hdf5_file_t *f, const void *_mesg, @@ -133,8 +134,8 @@ H5O_stab_encode (hdf5_file_t *f, size_t raw_size, uint8 *p, const void *_mesg) /*------------------------------------------------------------------------- * Function: H5O_stab_fast * - * Purpose: Initializes a new message struct with info from a symbol - * table entry. + * Purpose: Initializes a new message struct with info from the cache of + * a symbol table entry. * * Return: Success: Ptr to message struct, allocated if none * supplied. @@ -150,22 +151,18 @@ H5O_stab_encode (hdf5_file_t *f, size_t raw_size, uint8 *p, const void *_mesg) *------------------------------------------------------------------------- */ static void * -H5O_stab_fast (const H5G_entry_t *ent, void *_mesg) +H5O_stab_fast (const H5G_cache_t *cache, void *_mesg) { H5O_stab_t *stab = (H5O_stab_t *)_mesg; FUNC_ENTER (H5O_stab_fast, NULL, NULL); /* check args */ - assert (ent); + assert (cache); - if (H5G_CACHED_STAB==ent->type) { - if (!stab) stab = H5MM_xcalloc (1, sizeof(H5O_stab_t)); - stab->btree_addr = ent->cache.stab.btree_addr; - stab->heap_addr = ent->cache.stab.heap_addr; - } else { - stab = NULL; - } + if (!stab) stab = H5MM_xcalloc (1, sizeof(H5O_stab_t)); + stab->btree_addr = cache->stab.btree_addr; + stab->heap_addr = cache->stab.heap_addr; FUNC_LEAVE (stab); } @@ -177,8 +174,9 @@ H5O_stab_fast (const H5G_entry_t *ent, void *_mesg) * Purpose: Copies a message into the cache portion of a symbol table * entry. * - * Return: Success: TRUE if modified. - * FALSE if not modified. + * Return: Success: TRUE if modified; FALSE if not modified. + * In either case, the new cache type is + * returned through the CACHE_TYPE argument. * * Failure: FAIL * @@ -191,7 +189,7 @@ H5O_stab_fast (const H5G_entry_t *ent, void *_mesg) *------------------------------------------------------------------------- */ static hbool_t -H5O_stab_cache (H5G_entry_t *ent, const void *_mesg) +H5O_stab_cache (H5G_type_t *cache_type, H5G_cache_t *cache, const void *_mesg) { const H5O_stab_t *stab = (const H5O_stab_t *)_mesg; hbool_t modified = FALSE; @@ -199,28 +197,24 @@ H5O_stab_cache (H5G_entry_t *ent, const void *_mesg) FUNC_ENTER (H5O_stab_cache, NULL, FAIL); /* check args */ - assert (ent); + assert (cache_type); + assert (cache); assert (stab); - /* - * We do this in two steps so Purify doesn't complain about - * uninitialized memory reads even though they don't bother - * anything. - */ - if (H5G_CACHED_STAB != ent->type) { + if (H5G_CACHED_STAB != *cache_type) { modified = TRUE; - ent->type = H5G_CACHED_STAB; - ent->cache.stab.btree_addr = stab->btree_addr; - ent->cache.stab.heap_addr = stab->heap_addr; + *cache_type = H5G_CACHED_STAB; + cache->stab.btree_addr = stab->btree_addr; + cache->stab.heap_addr = stab->heap_addr; } else { - if (ent->cache.stab.btree_addr != stab->btree_addr) { + if (cache->stab.btree_addr != stab->btree_addr) { modified = TRUE; - ent->cache.stab.btree_addr = stab->btree_addr; + cache->stab.btree_addr = stab->btree_addr; } - if (ent->cache.stab.heap_addr != stab->heap_addr) { + if (cache->stab.heap_addr != stab->heap_addr) { modified = TRUE; - ent->cache.stab.heap_addr = stab->heap_addr; + cache->stab.heap_addr = stab->heap_addr; } } diff --git a/src/Makefile.in b/src/Makefile.in index 9308965..cebf3c1 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -15,9 +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 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 + H5Gent.c H5Gnode.c H5Gshad.c H5Gstab.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) |