diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2005-07-21 14:49:11 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2005-07-21 14:49:11 (GMT) |
commit | 1e2ddfc8b1847c4b1f67c764d4920c5d1e0c538d (patch) | |
tree | 60e8d8ee4b4fa77ef7a01ebf106d53b9d7675a32 | |
parent | c9b45e24d5f1935d5356cf90f0521d1e82efc4e3 (diff) | |
download | hdf5-1e2ddfc8b1847c4b1f67c764d4920c5d1e0c538d.zip hdf5-1e2ddfc8b1847c4b1f67c764d4920c5d1e0c538d.tar.gz hdf5-1e2ddfc8b1847c4b1f67c764d4920c5d1e0c538d.tar.bz2 |
[svn-r11094] Purpose:
Bug fix
Description:
Rewrite code for mounting files to clean up layers of kludges and implement
a much cleaner and more maintainable design.
Platforms tested:
FreeBSD 4.11 (sleipnir)
Linux 2.4
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | release_docs/RELEASE.txt | 8 | ||||
-rw-r--r-- | src/H5.c | 84 | ||||
-rw-r--r-- | src/H5D.c | 17 | ||||
-rw-r--r-- | src/H5F.c | 714 | ||||
-rw-r--r-- | src/H5Fmount.c | 195 | ||||
-rw-r--r-- | src/H5Fpkg.h | 9 | ||||
-rw-r--r-- | src/H5Fprivate.h | 4 | ||||
-rw-r--r-- | src/H5G.c | 90 | ||||
-rw-r--r-- | src/H5Gpkg.h | 3 | ||||
-rw-r--r-- | src/H5Gprivate.h | 2 | ||||
-rw-r--r-- | src/H5I.c | 37 | ||||
-rw-r--r-- | src/H5Iprivate.h | 1 | ||||
-rw-r--r-- | src/H5Ipublic.h | 1 | ||||
-rw-r--r-- | src/H5O.c | 31 | ||||
-rw-r--r-- | test/Makefile.in | 10 | ||||
-rw-r--r-- | test/filename.c | 154 | ||||
-rw-r--r-- | test/mount.c | 715 | ||||
-rw-r--r-- | test/testhdf5.h | 15 | ||||
-rw-r--r-- | test/tfile.c | 155 |
20 files changed, 1507 insertions, 739 deletions
@@ -1267,7 +1267,6 @@ ./test/family_v1.7_00002.h5 ./test/family_v1.7_00003.h5 ./test/file_handle.c -./test/filename.c ./test/fill_old.h5 ./test/fillval.c ./test/flush1.c diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 50a08ce..982345c 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -72,6 +72,14 @@ Bug Fixes since HDF5-1.6.4 release Library ------- + - Made H5Fget_name() be consistent and always return name of actual + file the ID is in. (Instead of the name of the top file in a + file mounting hierarchy). QAK - 2005/07/19 + - Reworked internal file mounting semantics to hopefully eliminate + mounting problems. We now require that files that are mounting + together all have the same "file close degree". QAK - 2005/07/19 + - More bug fixes on holding open files that are mounted and have + IDs open. QAK - 2005/07/14 - More bug fixes on holding open files that are mounted and have IDs open. QAK - 2005/07/14 - Dataset sieve buffer cache was inadvertantly disabled - re-enable @@ -2054,9 +2054,6 @@ H5_trace (const double *returning, const char *func, const char *type, ...) case H5I_FILE: fprintf(out, "%ld (file)", (long)obj); break; - case H5I_FILE_CLOSING: - fprintf(out, "%ld (file closing)", (long)obj); - break; case H5I_GROUP: fprintf(out, "%ld (group)", (long)obj); break; @@ -2247,48 +2244,45 @@ H5_trace (const double *returning, const char *func, const char *type, ...) } else { H5I_type_t id_type = va_arg (ap, H5I_type_t); /*lint !e64 Type mismatch not really occuring */ switch (id_type) { - case H5I_BADID: - fprintf (out, "H5I_BADID"); - break; - case H5I_FILE: - fprintf (out, "H5I_FILE"); - break; - case H5I_FILE_CLOSING: - fprintf (out, "H5I_FILE_CLOSING"); - break; - case H5I_GROUP: - fprintf (out, "H5I_GROUP"); - break; - case H5I_DATATYPE: - fprintf (out, "H5I_DATATYPE"); - break; - case H5I_DATASPACE: - fprintf (out, "H5I_DATASPACE"); - break; - case H5I_DATASET: - fprintf (out, "H5I_DATASET"); - break; - case H5I_ATTR: - fprintf (out, "H5I_ATTR"); - break; - case H5I_REFERENCE: - fprintf (out, "H5I_REFERENCE"); - break; - case H5I_VFL: - fprintf (out, "H5I_VFL"); - break; - case H5I_GENPROP_CLS: - fprintf (out, "H5I_GENPROP_CLS"); - break; - case H5I_GENPROP_LST: - fprintf (out, "H5I_GENPROP_LST"); - break; - case H5I_NGROUPS: - fprintf (out, "H5I_NGROUPS"); - break; - default: - fprintf (out, "%ld", (long)id_type); - break; + case H5I_BADID: + fprintf (out, "H5I_BADID"); + break; + case H5I_FILE: + fprintf (out, "H5I_FILE"); + break; + case H5I_GROUP: + fprintf (out, "H5I_GROUP"); + break; + case H5I_DATATYPE: + fprintf (out, "H5I_DATATYPE"); + break; + case H5I_DATASPACE: + fprintf (out, "H5I_DATASPACE"); + break; + case H5I_DATASET: + fprintf (out, "H5I_DATASET"); + break; + case H5I_ATTR: + fprintf (out, "H5I_ATTR"); + break; + case H5I_REFERENCE: + fprintf (out, "H5I_REFERENCE"); + break; + case H5I_VFL: + fprintf (out, "H5I_VFL"); + break; + case H5I_GENPROP_CLS: + fprintf (out, "H5I_GENPROP_CLS"); + break; + case H5I_GENPROP_LST: + fprintf (out, "H5I_GENPROP_LST"); + break; + case H5I_NGROUPS: + fprintf (out, "H5I_NGROUPS"); + break; + default: + fprintf (out, "%ld", (long)id_type); + break; } } break; @@ -3989,8 +3989,6 @@ done: * * Date: August 14, 2002 * - * Comments: Just flushing the compact data information currently. - * * Modifications: * *------------------------------------------------------------------------- @@ -3998,11 +3996,11 @@ done: herr_t H5D_flush(const H5F_t *f, hid_t dxpl_id, unsigned flags) { - int num_dsets; /* Number of datasets in file */ + unsigned num_dsets; /* Number of datasets in file */ hid_t *id_list=NULL; /* list of dataset IDs */ H5D_t *dataset=NULL; /* Dataset pointer */ + unsigned u; /* Index variable */ herr_t ret_value = SUCCEED; /* Return value */ - int j; /* Index variable */ FUNC_ENTER_NOAPI(H5D_flush, FAIL) @@ -4010,18 +4008,17 @@ H5D_flush(const H5F_t *f, hid_t dxpl_id, unsigned flags) assert(f); /* Update layout message for compact dataset */ - if((num_dsets=H5F_get_obj_count(f, H5F_OBJ_DATASET))<0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to get dataset count") + num_dsets=H5F_get_obj_count(f, H5F_OBJ_DATASET); /* Check for something to do */ if(num_dsets>0) { - H5_CHECK_OVERFLOW(num_dsets,int,size_t); + H5_CHECK_OVERFLOW(num_dsets,unsigned,size_t); if(NULL==(id_list=H5MM_malloc((size_t)num_dsets*sizeof(hid_t)))) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to allocate memory for ID list") - if(H5F_get_obj_ids(f, H5F_OBJ_DATASET, -1, id_list)<0) + if(H5F_get_obj_ids(f, H5F_OBJ_DATASET, -1, id_list) != num_dsets) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to get dataset ID list") - for(j=0; j<num_dsets; j++) { - if(NULL==(dataset=H5I_object_verify(id_list[j], H5I_DATASET))) + for(u = 0; u < num_dsets; u++) { + if(NULL==(dataset=H5I_object_verify(id_list[u], H5I_DATASET))) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to get dataset object") /* Flush the raw data buffer, if we have a dirty one */ @@ -61,6 +61,12 @@ typedef struct H5F_olist_t { int max_index; /* Maximum # of IDs to put into array */ } H5F_olist_t; +/* Struct for tracking "shared" file structs */ +typedef struct H5F_sfile_node_t { + H5F_file_t *shared; /* Pointer to "shared" struct */ + struct H5F_sfile_node_t *next; /* Pointer to next node */ +} H5F_sfile_node_t; + /* PRIVATE PROTOTYPES */ static H5F_t *H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t dxpl_id); @@ -70,19 +76,31 @@ static herr_t H5F_flush_all(hbool_t invalidate); static int H5F_flush_all_cb(void *f, hid_t fid, void *_invalidate); #endif /* NOT_YET */ +static herr_t H5F_close(H5F_t *f); static H5F_t *H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id); static herr_t H5F_dest(H5F_t *f, hid_t dxpl_id); static herr_t H5F_flush(H5F_t *f, hid_t dxpl_id, H5F_scope_t scope, unsigned flags); -static int H5F_get_objects(const H5F_t *f, unsigned types, int max_objs, hid_t *obj_id_list); +static unsigned H5F_get_objects(const H5F_t *f, unsigned types, int max_objs, hid_t *obj_id_list); static int H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key); static herr_t H5F_get_vfd_handle(const H5F_t *file, hid_t fapl, void** file_handle); +/* Routines to operate on the shared file list */ +static herr_t H5F_shared_add(H5F_file_t *shared); +static H5F_file_t * H5F_shared_search(H5FD_t *lf); +static herr_t H5F_shared_remove(H5F_file_t *shared); + /* Declare a free list to manage the H5F_t struct */ H5FL_DEFINE_STATIC(H5F_t); /* Declare a free list to manage the H5F_file_t struct */ H5FL_DEFINE_STATIC(H5F_file_t); +/* Declare a free list to manage the H5F_sfile_node_t struct */ +H5FL_DEFINE_STATIC(H5F_sfile_node_t); + +/* Declare a local variable to track the shared file information */ +H5F_sfile_node_t *H5F_sfile_head_g = NULL; + /*------------------------------------------------------------------------- * Function: H5F_init @@ -222,8 +240,7 @@ H5F_init_interface(void) * which are pending completion because there are object headers still * open within the file. */ - if (H5I_init_group(H5I_FILE, (size_t)H5I_FILEID_HASHSIZE, 0, (H5I_free_t)H5F_close)<0 || - H5I_init_group(H5I_FILE_CLOSING, (size_t)H5I_FILEID_HASHSIZE, 0, (H5I_free_t)H5F_close)<0) + if (H5I_init_group(H5I_FILE, (size_t)H5I_FILEID_HASHSIZE, 0, (H5I_free_t)H5F_close)<0) HGOTO_ERROR (H5E_FILE, H5E_CANTINIT, FAIL, "unable to initialize interface") /* ========== File Creation Property Class Initialization ============*/ @@ -424,13 +441,11 @@ H5F_term_interface(void) if (H5_interface_initialize_g) { if ((n=H5I_nmembers(H5I_FILE))!=0) { H5I_clear_group(H5I_FILE, FALSE); - } else if ((n=H5I_nmembers(H5I_FILE_CLOSING))!=0) { - /* Attempt to unmount any child files from files that are closing */ - (void)H5I_search(H5I_FILE_CLOSING, H5F_term_unmount_cb, NULL); - } - else { + } else { + /* Make certain we've cleaned up all the shared file objects */ + HDassert(H5F_sfile_head_g == NULL); + H5I_destroy_group(H5I_FILE); - H5I_destroy_group(H5I_FILE_CLOSING); H5_interface_initialize_g = 0; n = 1; /*H5I*/ } @@ -899,17 +914,15 @@ done: * *------------------------------------------------------------------------- */ -int +unsigned H5F_get_obj_count(const H5F_t *f, unsigned types) { - int ret_value; /* Return value */ + unsigned ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5F_get_obj_count) + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_obj_count) - if((ret_value=H5F_get_objects(f, types, -1, NULL)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get counts of opened file IDs and object IDs in the file") + ret_value=H5F_get_objects(f, types, -1, NULL); -done: FUNC_LEAVE_NOAPI(ret_value) } @@ -951,7 +964,7 @@ done: /*------------------------------------------------------------------------- - * Function: H5F_get_object_ids + * Function: H5F_get_obj_ids * * Purpose: Private function to return a list of opened object IDs. * @@ -964,17 +977,15 @@ done: * *------------------------------------------------------------------------- */ -int +unsigned H5F_get_obj_ids(const H5F_t *f, unsigned types, int max_objs, hid_t *oid_list) { - int ret_value; /* Return value */ + unsigned ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5F_get_obj_ids) + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_obj_ids) - if((ret_value=H5F_get_objects(f, types, max_objs, oid_list)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get object IDs opened in the file") + ret_value = H5F_get_objects(f, types, max_objs, oid_list); -done: FUNC_LEAVE_NOAPI(ret_value) } @@ -994,12 +1005,12 @@ done: * *--------------------------------------------------------------------------- */ -static int +static unsigned H5F_get_objects(const H5F_t *f, unsigned types, int max_index, hid_t *obj_id_list) { unsigned obj_id_count=0; /* Number of open IDs */ H5F_olist_t olist; /* Structure to hold search results */ - int ret_value; /* Return value */ + unsigned ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_objects) @@ -1021,45 +1032,42 @@ H5F_get_objects(const H5F_t *f, unsigned types, int max_index, hid_t *obj_id_lis /* Search through file IDs to count the number, and put their * IDs on the object list */ - if( (types & H5F_OBJ_FILE) && H5I_nmembers(H5I_FILE) > 0 ) { + if(types & H5F_OBJ_FILE) { olist.obj_type = H5I_FILE; (void)H5I_search(H5I_FILE, H5F_get_objects_cb, &olist); - } + } /* end if */ /* Search through dataset IDs to count number of datasets, and put their * IDs on the object list */ - if( (max_index<0 || (int)olist.list_index< max_index) && (types & H5F_OBJ_DATASET) && H5I_nmembers(H5I_DATASET) > 0 ) { + if( (max_index < 0 || (int)olist.list_index < max_index) && (types & H5F_OBJ_DATASET) ) { olist.obj_type = H5I_DATASET; (void)H5I_search(H5I_DATASET, H5F_get_objects_cb, &olist); } /* Search through group IDs to count number of groups, and put their * IDs on the object list */ - if( (max_index<0 || (int)olist.list_index< max_index) && (types & H5F_OBJ_GROUP) && H5I_nmembers(H5I_GROUP) > 0 ) { + if( (max_index < 0 || (int)olist.list_index < max_index) && (types & H5F_OBJ_GROUP) ) { olist.obj_type = H5I_GROUP; (void)H5I_search(H5I_GROUP, H5F_get_objects_cb, &olist); } /* Search through datatype IDs to count number of named datatypes, and put their * IDs on the object list */ - if( (max_index<0 || (int)olist.list_index< max_index) && (types & H5F_OBJ_DATATYPE) && H5I_nmembers(H5I_DATATYPE) > 0 ) { + if( (max_index < 0 || (int)olist.list_index < max_index) && (types & H5F_OBJ_DATATYPE) ) { olist.obj_type = H5I_DATATYPE; (void)H5I_search(H5I_DATATYPE, H5F_get_objects_cb, &olist); } /* Search through attribute IDs to count number of attributes, and put their * IDs on the object list */ - if( (max_index<0 || (int)olist.list_index< max_index) && (types & H5F_OBJ_ATTR) && H5I_nmembers(H5I_ATTR) > 0 ) { + if( (max_index < 0 || (int)olist.list_index < max_index) && (types & H5F_OBJ_ATTR) ) { olist.obj_type = H5I_ATTR; (void)H5I_search(H5I_ATTR, H5F_get_objects_cb, &olist); } /* Set the number of objects currently open */ - H5_ASSIGN_OVERFLOW(ret_value,obj_id_count,unsigned,int); + ret_value = obj_id_count; -#ifdef LATER -done: -#endif /* LATER */ FUNC_LEAVE_NOAPI(ret_value) } @@ -1233,39 +1241,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5F_equal - * - * Purpose: Compares NEEDLE to a file from the HAYSTACK. - * - * Return: Success: Returns positive if two files are equal, - * zero otherwise. - * - * Failure: Negative - * - * Programmer: Robb Matzke - * Monday, August 2, 1999 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -/* ARGSUSED */ -static int -H5F_equal(void *_haystack, hid_t UNUSED id, void *_needle) -{ - H5F_t *haystack = (H5F_t*)_haystack; - const H5FD_t *needle = (const H5FD_t*)_needle; - int retval; - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_equal) - - retval = (0==H5FD_cmp(haystack->shared->lf, needle)); - - FUNC_LEAVE_NOAPI(retval) -} - - -/*------------------------------------------------------------------------- * Function: H5F_locate_signature * * Purpose: Finds the HDF5 super block signature in a file. The signature @@ -1415,7 +1390,6 @@ static H5F_t * H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id) { H5F_t *f=NULL, *ret_value; - int n; H5P_genplist_t *plist; /* Property list */ FUNC_ENTER_NOAPI_NOINIT(H5F_new) @@ -1426,6 +1400,8 @@ H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id) if (shared) { f->shared = shared; } else { + int n; + f->shared = H5FL_CALLOC(H5F_file_t); f->shared->super_addr = HADDR_UNDEF; f->shared->base_addr = HADDR_UNDEF; @@ -1498,11 +1474,14 @@ H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id) /* Create the file's "open object" information */ if(H5FO_create(f)<0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create open object TBBT") + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create open object data structure") + + /* Add new "shared" struct to list of open files */ + if(H5F_shared_add(f->shared) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to append to list of open files") } /* end else */ f->shared->nrefs++; - f->nrefs = 1; /* Set return value */ ret_value = f; @@ -1559,77 +1538,83 @@ H5F_dest(H5F_t *f, hid_t dxpl_id) FUNC_ENTER_NOAPI_NOINIT(H5F_dest) - if (f && 1==f->nrefs) { - if (1==f->shared->nrefs) { - /* - * Do not close the root group since we didn't count it, but free - * the memory associated with it. - */ - if (f->shared->root_grp) { - /* Free the ID to name buffer */ - if(H5G_free_grp_name(f->shared->root_grp)<0) { - HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); - ret_value = FAIL; /*but keep going*/ - } /* end if */ - - /* Free the memory for the root group */ - if(H5G_free(f->shared->root_grp)<0) { - HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); - ret_value = FAIL; /*but keep going*/ - } /* end if */ - f->shared->root_grp=NULL; - } - if (H5AC_dest(f, dxpl_id)) { - HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); - ret_value = FAIL; /*but keep going*/ - } - if (H5FO_dest(f)<0) { + /* Sanity check */ + HDassert(f); + + if (1==f->shared->nrefs) { + /* Remove shared file struct from list of open files */ + if(H5F_shared_remove(f->shared) < 0) { + HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); + ret_value = FAIL; /*but keep going*/ + } /* end if */ + + /* + * Do not close the root group since we didn't count it, but free + * the memory associated with it. + */ + if (f->shared->root_grp) { + /* Free the ID to name buffer */ + if(H5G_free_grp_name(f->shared->root_grp)<0) { HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); ret_value = FAIL; /*but keep going*/ - } /* end if */ - f->shared->cwfs = H5MM_xfree (f->shared->cwfs); - if (H5G_node_close(f)<0) { + } /* end if */ + + /* Free the memory for the root group */ + if(H5G_free(f->shared->root_grp)<0) { HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); ret_value = FAIL; /*but keep going*/ - } /* end if */ - - /* Destroy file creation properties */ - if(H5I_GENPROP_LST != H5I_get_type(f->shared->fcpl_id)) - HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a property list") - if((ret_value=H5I_dec_ref(f->shared->fcpl_id)) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "can't close property list") - - /* Destroy shared file struct */ - if (H5FD_close(f->shared->lf)<0) { - HERROR(H5E_FILE, H5E_CANTINIT, "problems closing file"); - ret_value = FAIL; /*but keep going*/ - } - f->shared = H5FL_FREE(H5F_file_t,f->shared); - - } else if (f->shared->nrefs>0) { - /* - * There are other references to the shared part of the file. - * Only decrement the reference count. - */ - --f->shared->nrefs; - } + } /* end if */ + f->shared->root_grp=NULL; + } + if (H5AC_dest(f, dxpl_id)) { + HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); + ret_value = FAIL; /*but keep going*/ + } + if (H5FO_dest(f)<0) { + HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); + ret_value = FAIL; /*but keep going*/ + } /* end if */ + f->shared->cwfs = H5MM_xfree (f->shared->cwfs); + if (H5G_node_close(f)<0) { + HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); + ret_value = FAIL; /*but keep going*/ + } /* end if */ - /* Free the non-shared part of the file */ - f->name = H5MM_xfree(f->name); - f->mtab.child = H5MM_xfree(f->mtab.child); - f->mtab.nalloc = 0; - H5FL_FREE(H5F_t,f); - } else if (f && f->nrefs>0) { - /* - * There are other references to this file. Only decrement the - * reference count. - */ - --f->nrefs; + /* Destroy file creation properties */ + if(H5I_GENPROP_LST != H5I_get_type(f->shared->fcpl_id)) { + HERROR(H5E_PLIST, H5E_BADTYPE, "not a property list"); + ret_value = FAIL; /*but keep going*/ + } /* end if */ + if((ret_value=H5I_dec_ref(f->shared->fcpl_id)) < 0) { + HERROR(H5E_PLIST, H5E_CANTFREE, "can't close property list"); + ret_value = FAIL; /*but keep going*/ + } /* end if */ + + /* Close low-level file */ + if (H5FD_close(f->shared->lf)<0) { + HERROR(H5E_FILE, H5E_CANTINIT, "problems closing file"); + ret_value = FAIL; /*but keep going*/ + } + + /* Destroy shared file struct */ + f->shared = H5FL_FREE(H5F_file_t,f->shared); + + } else if (f->shared->nrefs>0) { + /* + * There are other references to the shared part of the file. + * Only decrement the reference count. + */ + --f->shared->nrefs; } -done: + /* Free the non-shared part of the file */ + f->name = H5MM_xfree(f->name); + f->mtab.child = H5MM_xfree(f->mtab.child); + f->mtab.nalloc = 0; + H5FL_FREE(H5F_t,f); + FUNC_LEAVE_NOAPI(ret_value) -} +} /* end H5F_dest() */ /*------------------------------------------------------------------------- @@ -1767,8 +1752,7 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t d } /* end if */ /* Is the file already open? */ - if ((file=H5I_search(H5I_FILE, H5F_equal, lf))!=NULL || - (file=H5I_search(H5I_FILE_CLOSING, H5F_equal, lf))!=NULL) { + if ((shared = H5F_shared_search(lf)) != NULL) { /* * The file is already open, so use that one instead of the one we * just opened. We only one one H5FD_t* per file so one doesn't @@ -1778,24 +1762,17 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t d * exists), or if the new request adds write access (since the * readers don't expect the file to change under them). */ - if(H5FD_close(lf)<0) { - file = NULL; /*to prevent destruction of wrong file*/ + if(H5FD_close(lf)<0) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to close low-level file info") - } /* end if */ - if (flags & H5F_ACC_TRUNC) { - file = NULL; /*to prevent destruction of wrong file*/ + if (flags & H5F_ACC_TRUNC) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to truncate a file which is already open") - } - if (flags & H5F_ACC_EXCL) { - file = NULL; /*to prevent destruction of wrong file*/ + if (flags & H5F_ACC_EXCL) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file exists") - } - if ((flags & H5F_ACC_RDWR) && 0==(file->intent & H5F_ACC_RDWR)) { - file = NULL; /*to prevent destruction of wrong file*/ + if ((flags & H5F_ACC_RDWR) && 0 == (shared->flags & H5F_ACC_RDWR)) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file is already open for read-only") - } - if ((file = H5F_new(file->shared, fcpl_id, fapl_id)) == NULL) + /* Allocate new "high-level" file struct */ + if ((file = H5F_new(shared, fcpl_id, fapl_id)) == NULL) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to create new file object") lf = file->shared->lf; @@ -2384,26 +2361,58 @@ H5F_close(H5F_t *f) FUNC_ENTER_NOAPI_NOINIT(H5F_close) - assert(f->nrefs>0); + /* Sanity check */ + HDassert(f); + HDassert(f->file_id > 0); /* This routine should only be called when a file ID's ref count drops to zero */ - /* - * If this file is referenced more than once then just decrement the - * count and return. - */ - if (f->nrefs>1) { - /* Decrement reference counts */ - if (H5F_dest(f, H5AC_dxpl_id)<0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file") - HGOTO_DONE(SUCCEED) - } /* end if */ + /* Reset the file ID for this file */ + f->file_id = -1; - /* Double-check that this file should be closed */ - assert(1==f->nrefs); - - /* if close degree if "semi" and there are objects left open and we are - * holding open the file with this file ID, fail now */ - if(f->shared->fc_degree==H5F_CLOSE_SEMI && f->nopen_objs>0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file, there are objects still open") + /* Attempt to close the file/mount hierarchy */ + if(H5F_try_close(f) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F_close() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_try_close + * + * Purpose: Attempts to close a file due to one of several actions: + * - The reference count on the file ID dropped to zero + * - The last open object was closed in the file + * - The file was unmounted + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, July 19, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_try_close(H5F_t *f) +{ + unsigned nopen_files = 0; /* Number of open files in file/mount hierarchy */ + unsigned nopen_objs = 0; /* Number of open objects in file/mount hierarchy */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5F_try_close) + + /* Sanity check */ + HDassert(f); + + /* Check if this file is already in the process of closing */ + if(f->closing) + HGOTO_DONE(SUCCEED) + + /* Get the number of open objects and open files on this file/mount hierarchy */ + if(H5F_mount_count_ids(f, &nopen_files, &nopen_objs) < 0) + HGOTO_ERROR(H5E_SYM, H5E_MOUNT, FAIL, "problem checking mount hierarchy") /* * Close file according to close degree: @@ -2418,138 +2427,84 @@ H5F_close(H5F_t *f) switch(f->shared->fc_degree) { case H5F_CLOSE_WEAK: /* - * If object headers are still open then delay deletion of + * If file or object IDS are still open then delay deletion of * resources until they have all been closed. Flush all - * caches and update the object eader anyway so that failing toi - * close all objects isn't a major problem. If the file is on - * the H5I_FILE list then move it to the H5I_FILE_CLOSING list - * instead. + * caches and update the object header anyway so that failing to + * close all objects isn't a major problem. */ - if (f->nopen_objs>0) { -#ifdef H5F_DEBUG - if (H5DEBUG(F)) { - fprintf(H5DEBUG(F), "H5F: H5F_close(%s): %u object header%s still " - "open (file close will complete when %s closed)\n", - f->name, - f->nopen_objs, - 1 == f->nopen_objs?" is":"s are", - 1 == f->nopen_objs?"that header is":"those headers are"); - } -#endif - /* If the only open objects are the groups that are mount points, */ - /* allow the file to close and shut things down */ - if(f->nopen_objs == f->mtab.nmounts) { - unsigned u; /* Local index variable */ - hbool_t really_close; /* Whether to delay the file close by going to a "closing" state */ - - /* Check for open groups on mount points */ - really_close = TRUE; - for(u = 0; u < f->mtab.nmounts; u++) { - if(H5G_get_shared_count(f->mtab.child[u].group) > 1) { - really_close = FALSE; - break; - } /* end if */ - } /* end for */ - - /* If we really want to close this file now */ - if(really_close) - break; - } /* end if */ - - /* Register an ID for closing the file later */ - if (!f->closing) - f->closing = H5I_register(H5I_FILE_CLOSING, f); - - /* Invalidate file ID */ - f->file_id = -1; - + if ((nopen_files + nopen_objs) > 0) HGOTO_DONE(SUCCEED) - } else { - if (f->closing) { - -#ifdef H5F_DEBUG - if (H5DEBUG(F)) - fprintf(H5DEBUG(F), "H5F: H5F_close: operation completing\n"); -#endif - } /* end if */ - } /* end else */ break; case H5F_CLOSE_SEMI: + /* Can leave safely if file IDs are still open on this file */ + if (nopen_files > 0) + HGOTO_DONE(SUCCEED) + + /* Sanity check: If close degree if "semi" and we have gotten this + * far and there are objects left open, bail out now */ + HDassert(nopen_files == 0 && nopen_objs == 0); + /* If we've gotten this far (ie. there are no open objects in the file), fall through to flush & close */ break; case H5F_CLOSE_STRONG: - /* Force to close all opened objects in file */ - while(f->nopen_objs > 0) { - int obj_count; /* # of open objects */ - hid_t objs[128]; /* Array of objects to close */ - int i; /* Local index variable */ - - /* Get the list of IDs of open dataset objects */ - while((obj_count=H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_DATASET, (int)(sizeof(objs)/sizeof(objs[0])), objs))!=0) { - - /* Try to close all the open objects */ - for(i=0; i<obj_count; i++) - if(H5I_dec_ref(objs[i]) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") - } /* end while */ - - /* Get the list of IDs of open group objects */ - while((obj_count=H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_GROUP, (int)(sizeof(objs)/sizeof(objs[0])), objs))!=0) { - - /* Try to close all the open objects */ - for(i=0; i<obj_count; i++) - if(H5I_dec_ref(objs[i]) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") - } /* end while */ - - /* Get the list of IDs of open named datatype objects */ - while((obj_count=H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_DATATYPE, (int)(sizeof(objs)/sizeof(objs[0])), objs))!=0) { - - /* Try to close all the open objects */ - for(i=0; i<obj_count; i++) - if(H5I_dec_ref(objs[i]) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") - } /* end while */ - - /* Get the list of IDs of open attribute objects */ - while((obj_count=H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_ATTR, (int)(sizeof(objs)/sizeof(objs[0])), objs))!=0) { - - /* Try to close all the open objects */ - for(i=0; i<obj_count; i++) - if(H5I_dec_ref(objs[i]) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") - } /* end while */ - } /* end while */ + /* If there are other open files in the hierarchy, we can leave now */ + if(nopen_files > 0) + HGOTO_DONE(SUCCEED) + + /* If we've gotten this far (ie. there are no open file IDs in the file/mount hierarchy), fall through to flush & close */ break; default: HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file, unknown file close degree") } /* end switch */ - /* - * Unmount and close each child before closing the current file. - */ - assert(NULL==f->mtab.parent); - if(H5F_close_mounts(f) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't unmount child file") + /* Mark this file as closing (prevents re-entering file shutdown code below) */ + f->closing = TRUE; - /* Invalidate file ID */ - f->file_id = -1; + /* If the file close degree is "strong", close all the open objects in this file */ + if(f->shared->fc_degree == H5F_CLOSE_STRONG) { + HDassert(nopen_files == 0); - /* Flush at this point since the file will be closed */ + /* Forced close of all opened objects in this file */ + if(f->nopen_objs > 0) { + unsigned obj_count; /* # of open objects */ + hid_t objs[128]; /* Array of objects to close */ + unsigned u; /* Local index variable */ + + /* Get the list of IDs of open dataset, group, named datatype & attribute objects */ + while((obj_count = H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_DATASET|H5F_OBJ_GROUP|H5F_OBJ_DATATYPE|H5F_OBJ_ATTR, (int)(sizeof(objs)/sizeof(objs[0])), objs)) != 0) { + + /* Try to close all the open objects in this file */ + for(u = 0; u < obj_count; u++) + if(H5I_dec_ref(objs[u]) < 0) + HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") + } /* end while */ + } /* end if */ + } /* end if */ + + /* Check if this is a child file in a mounting hierarchy & proceed up the + * hierarchy if so. + */ + if(f->mtab.parent) + if(H5F_try_close(f->mtab.parent) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close parent file") + + /* Unmount and close each child before closing the current file. */ + if(H5F_close_mounts(f) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't unmount child files") - /* Dump debugging info */ #if H5AC_DUMP_STATS_ON_CLOSE + /* Dump debugging info */ H5AC_stats(f); #endif /* H5AC_DUMP_STATS_ON_CLOSE */ - /* Only try to flush the file if it was opened with write access */ + /* Flush at this point since the file will be closed */ + /* (Only try to flush the file if it was opened with write access) */ if(f->intent&H5F_ACC_RDWR) { /* Flush and destroy all caches */ - if (H5F_flush(f, H5AC_dxpl_id, H5F_SCOPE_LOCAL, - H5F_FLUSH_INVALIDATE | H5F_FLUSH_CLOSING) < 0) + if (H5F_flush(f, H5AC_dxpl_id, H5F_SCOPE_LOCAL, H5F_FLUSH_INVALIDATE | H5F_FLUSH_CLOSING) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache") } /* end if */ @@ -2558,12 +2513,12 @@ H5F_close(H5F_t *f) * shared H5F_file_t struct. If the reference count for the H5F_file_t * struct reaches zero then destroy it also. */ - if (H5F_dest(f,H5AC_dxpl_id)<0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file") + if (H5F_dest(f, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5F_close() */ +} /* end H5F_try_close() */ /*------------------------------------------------------------------------- @@ -2590,14 +2545,42 @@ done: herr_t H5Fclose(hid_t file_id) { + H5F_t *f; herr_t ret_value = SUCCEED; FUNC_ENTER_API(H5Fclose, FAIL) H5TRACE1("e","i",file_id); /* Check/fix arguments. */ - if (NULL==H5I_object_verify(file_id,H5I_FILE)) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file atom") + if (NULL == (f = H5I_object_verify(file_id,H5I_FILE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file ID") + + /* Perform checks for "semi" file close degree here, since closing the + * file ID will mess things up if we need to return FAIL */ + if(f->shared->fc_degree == H5F_CLOSE_SEMI) { + int ref_count; /* Reference count for file's ID */ + + /* Get the reference count for this ID */ + if((ref_count = H5I_get_ref(file_id)) < 0) + HGOTO_ERROR (H5E_ATOM, H5E_CANTGET, FAIL, "can't get ID ref count") + + /* If we will be decrementing the reference count to zero, check for objects open */ + if(ref_count == 1) { + unsigned nopen_files = 0; /* Number of open files in file/mount hierarchy */ + unsigned nopen_objs = 0; /* Number of open objects in file/mount hierarchy */ + + /* Get the number of open objects and open files on this file/mount hierarchy */ + if(H5F_mount_count_ids(f, &nopen_files, &nopen_objs) < 0) + HGOTO_ERROR(H5E_SYM, H5E_MOUNT, FAIL, "problem checking mount hierarchy") + + /* If there are no other file IDs open on this file/mount hier., but + * there are still open objects, issue an error and bail out now, + * before decrementing the file ID's reference count and triggering + * a "real" attempt at closing the file */ + if(nopen_files == 1 && nopen_objs > 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file, there are objects still open") + } /* end if */ + } /* end if */ /* * Decrement reference count on atom. When it reaches zero the file will @@ -2653,6 +2636,9 @@ H5Freopen(hid_t file_id) /* Keep old file's read/write intent in new file */ new_file->intent=old_file->intent; + /* Duplicate old file's name */ + new_file->name = H5MM_xstrdup(old_file->name); + if ((ret_value=H5I_register(H5I_FILE, new_file))<0) HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file handle") @@ -2661,7 +2647,7 @@ H5Freopen(hid_t file_id) done: if (ret_value<0 && new_file) - if(H5F_close(new_file)<0) + if(H5F_dest(new_file, H5AC_dxpl_id)<0) HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file") FUNC_LEAVE_API(ret_value) } @@ -3047,15 +3033,9 @@ H5F_get_id(H5F_t *file) assert(file); if(file->file_id == -1) { - if(H5I_remove(file->closing)==NULL) - HGOTO_ERROR(H5E_ATOM, H5E_READERROR, FAIL, "unable to remove from closing list") - /* Get an atom for the file */ if ((file->file_id = H5I_register(H5I_FILE, file))<0) HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file") - - /* Indicate file is not closing */ - file->closing = 0; } else { /* Increment reference count on atom. */ if (H5I_inc_ref(file->file_id)<0) @@ -3615,21 +3595,33 @@ done: ssize_t H5Fget_name(hid_t obj_id, char *name/*out*/, size_t size) { - H5G_entry_t *ent; /*symbol table entry */ + H5G_entry_t *ent; /*symbol table entry */ + H5F_t *f; /* Top file in mount hierarchy */ size_t len=0; ssize_t ret_value; FUNC_ENTER_API (H5Fget_name, FAIL) H5TRACE3("Zs","ixz",obj_id,name,size); - /* get symbol table entry */ - if((ent = H5G_loc(obj_id))==NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid object ID") + /* For file IDs, get the file object directly */ + /* (This prevents the H5G_loc() call from returning the file pointer for + * the top file in a mount hierarchy) + */ + if(H5I_get_type(obj_id) == H5I_FILE ) { + if (NULL==(f=H5I_object(obj_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") + } /* end if */ + else { + /* Get symbol table entry */ + if((ent = H5G_loc(obj_id))==NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid object ID") + f = ent->file; + } /* end else */ - len = HDstrlen(ent->file->name); + len = HDstrlen(f->name); if(name) { - HDstrncpy(name, ent->file->name, MIN(len+1,size)); + HDstrncpy(name, f->name, MIN(len+1,size)); if(len >= size) name[size-1]='\0'; } /* end if */ @@ -3640,3 +3632,143 @@ H5Fget_name(hid_t obj_id, char *name/*out*/, size_t size) done: FUNC_LEAVE_API(ret_value) } /* end H5Fget_name() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_shared_add + * + * Purpose: Add a "shared" file struct to the list of open files + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * Monday, July 18, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F_shared_add(H5F_file_t *shared) +{ + H5F_sfile_node_t *new; /* New shared file node */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5F_shared_add) + + /* Sanity check */ + HDassert(shared); + + /* Allocate new shared file node */ + if (NULL == (new = H5FL_CALLOC(H5F_sfile_node_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Set shared file value */ + new->shared = shared; + + /* Prepend to list of shared files open */ + new->next = H5F_sfile_head_g; + H5F_sfile_head_g = new; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F_shared_add() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_shared_search + * + * Purpose: Search for a "shared" file with low-level file info that + * matches + * + * Return: Non-NULL on success / NULL on failure + * + * Programmer: Quincey Koziol + * Monday, July 18, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static H5F_file_t * +H5F_shared_search(H5FD_t *lf) +{ + H5F_sfile_node_t *curr; /* Current shared file node */ + H5F_file_t *ret_value = NULL; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_shared_search) + + /* Sanity check */ + HDassert(lf); + + /* Iterate through low-level files for matching low-level file info */ + curr = H5F_sfile_head_g; + while(curr) { + /* Check for match */ + if(0==H5FD_cmp(curr->shared->lf, lf)) + HGOTO_DONE(curr->shared) + + /* Advance to next shared file node */ + curr = curr->next; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F_shared_search() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_shared_remove + * + * Purpose: Remove a "shared" file struct from the list of open files + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * Monday, July 18, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F_shared_remove(H5F_file_t *shared) +{ + H5F_sfile_node_t *curr; /* Current shared file node */ + H5F_sfile_node_t *last; /* Last shared file node */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5F_shared_remove) + + /* Sanity check */ + HDassert(shared); + + /* Locate shared file node with correct shared file */ + last = NULL; + curr = H5F_sfile_head_g; + while(curr && curr->shared != shared) { + /* Advance to next node */ + last = curr; + curr = curr->next; + } /* end while */ + + /* Indicate error if the node wasn't found */ + if(curr == NULL) + HGOTO_ERROR(H5E_FILE, H5E_NOTFOUND, FAIL, "can't find shared file info") + + /* Remove node found from list */ + if(last != NULL) + /* Removing middle or tail node in list */ + last->next = curr->next; + else + /* Removing head node in list */ + H5F_sfile_head_g = curr->next; + + /* Release the shared file node struct */ + /* (the shared file info itself is freed elsewhere) */ + H5FL_FREE(H5F_sfile_node_t, curr); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F_shared_remove() */ + diff --git a/src/H5Fmount.c b/src/H5Fmount.c index 5714415..7e234a5 100644 --- a/src/H5Fmount.c +++ b/src/H5Fmount.c @@ -86,7 +86,7 @@ H5F_close_mounts(H5F_t *f) HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "can't close child group") /* Close the child file */ - if(H5F_close(f->mtab.child[u].file) < 0) + if(H5F_try_close(f->mtab.child[u].file) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close child file") } /* end if */ f->mtab.nmounts = 0; @@ -97,46 +97,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5F_term_unmount_cb - * - * Purpose: H5F_term_interface' callback function. This routine - * unmounts child files from files that are in the "closing" - * state. - * - * Programmer: Quincey Koziol - * Thursday, Jun 30, 2005 - * - * Modification: - * - *------------------------------------------------------------------------- - */ -int -H5F_term_unmount_cb(void *obj_ptr, hid_t obj_id, void UNUSED *key) -{ - H5F_t *f = (H5F_t *)obj_ptr; /* Alias for search info */ - int ret_value = FALSE; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5F_term_unmount_cb) - - assert(f); - - if(f->mtab.nmounts) { - /* Unmount all child files */ - if(H5F_close_mounts(f) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't unmount child file") - - /* Decrement reference count for file */ - H5I_dec_ref(obj_id); - } /* end if */ - else - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "no files to unmount") - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5F_term_unmount_cb() */ - - -/*------------------------------------------------------------------------- * Function: H5F_mount * * Purpose: Mount file CHILD onto the group specified by LOC and NAME, @@ -181,7 +141,8 @@ H5F_mount(H5G_entry_t *loc, const char *name, H5F_t *child, assert(TRUE==H5P_isa_class(plist_id,H5P_MOUNT)); /* - * Check that the child isn't mounted, that the mount point exists, and + * Check that the child isn't mounted, that the mount point exists, that + * the parent & child files have the same file close degree, and * that the mount wouldn't introduce a cycle in the mount tree. */ if (child->mtab.parent) @@ -197,6 +158,9 @@ H5F_mount(H5G_entry_t *loc, const char *name, H5F_t *child, if (ancestor==child) HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount would introduce a cycle") } + + if(parent->shared->fc_degree != child->shared->fc_degree) + HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mounted file has different file close degree than parent") /* * Use a binary search to locate the position that the child should be @@ -239,7 +203,10 @@ H5F_mount(H5G_entry_t *loc, const char *name, H5F_t *child, parent->mtab.child[md].group = mount_point; parent->mtab.child[md].file = child; child->mtab.parent = parent; - child->nrefs++; + + /* Set the group's mountpoint flag */ + if(H5G_mount(parent->mtab.child[md].group)<0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to set group mounted flag") /* Search the open IDs and replace names for mount operation */ /* We pass H5G_UNKNOWN as object type; search all IDs */ @@ -317,8 +284,7 @@ H5F_unmount(H5G_entry_t *loc, const char *name, hid_t dxpl_id) mnt_ent = H5G_entof(mounted); ent = H5G_entof(child->shared->root_grp); - if (child->mtab.parent && - H5F_addr_eq(mnt_ent->header, ent->header)) { + if (child->mtab.parent && H5F_addr_eq(mnt_ent->header, ent->header)) { /* * We've been given the root group of the child. We do a reverse * lookup in the parent's mount table to find the correct entry. @@ -332,18 +298,21 @@ H5F_unmount(H5G_entry_t *loc, const char *name, hid_t dxpl_id) /* Unmount the child */ parent->mtab.nmounts -= 1; + if(H5G_unmount(parent->mtab.child[md].group)<0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to reset group mounted flag") if(H5G_close(parent->mtab.child[i].group)<0) HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close unmounted group") child->mtab.parent = NULL; - if(H5F_close(child)<0) + if(H5F_try_close(child)<0) HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close unmounted file") + + /* Eliminate the mount point from the table */ HDmemmove(parent->mtab.child+i, parent->mtab.child+i+1, (parent->mtab.nmounts-i)* sizeof(parent->mtab.child[0])); ret_value = SUCCEED; } } - assert(ret_value>=0); - + HDassert(ret_value>=0); } else { /* * We've been given the mount point in the parent. We use a binary @@ -368,11 +337,15 @@ H5F_unmount(H5G_entry_t *loc, const char *name, hid_t dxpl_id) /* Unmount the child */ parent->mtab.nmounts -= 1; + if(H5G_unmount(parent->mtab.child[md].group)<0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to reset group mounted flag") if(H5G_close(parent->mtab.child[md].group)<0) HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close unmounted group") parent->mtab.child[md].file->mtab.parent = NULL; - if(H5F_close(parent->mtab.child[md].file)<0) + if(H5F_try_close(parent->mtab.child[md].file)<0) HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close unmounted file") + + /* Eliminate the mount point from the table */ HDmemmove(parent->mtab.child+md, parent->mtab.child+md+1, (parent->mtab.nmounts-md)*sizeof(parent->mtab.child[0])); ret_value = SUCCEED; @@ -621,109 +594,89 @@ done: /*------------------------------------------------------------------------- - * Function: H5F_check_mounts_recurse + * Function: H5F_mount_count_ids_recurse * - * Purpose: Helper routine for checking for file mounting hierarchies to - * close. + * Purpose: Helper routine for counting number of open IDs in mount + * hierarchy. * - * Return: TRUE if entire hierarchy can be closed / FALSE otherwise + * Return: <none> * * Programmer: Quincey Koziol - * Saturday, July 2, 2005 + * Tuesday, July 19, 2005 * * Modifications: * *------------------------------------------------------------------------- */ -static hbool_t -H5F_check_mounts_recurse(H5F_t *f) +static void +H5F_mount_count_ids_recurse(H5F_t *f, unsigned *nopen_files, unsigned *nopen_objs) { - hbool_t ret_value = FALSE; /* Return value */ + unsigned u; /* Local index value */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_check_mounts_recurse) + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_mount_count_ids_recurse) - /* Check if this file is closing and if the only objects left open are - * the mount points */ - if((f->closing || (f->nrefs == 1 && f->mtab.parent)) && f->nopen_objs == f->mtab.nmounts) { - unsigned u; + /* Sanity check */ + HDassert(f); + HDassert(nopen_files); + HDassert(nopen_objs); - /* Iterate over files mounted in this file and check if all can be closed */ - for(u = 0; u < f->mtab.nmounts; u++) { - if(H5G_get_shared_count(f->mtab.child[u].group) > 1 - || !H5F_check_mounts_recurse(f->mtab.child[u].file)) - HGOTO_DONE(FALSE) - } /* end for */ + /* If this file is still open, increment number of file IDs open */ + if(f->file_id > 0) + *nopen_files += 1; - /* Set return value */ - ret_value = TRUE; - } /* end if */ + /* Increment number of open objects in file + * (Reduced by number of mounted files, we'll add back in the mount point's + * groups later, if they are open) + */ + *nopen_objs += (f->nopen_objs - f->mtab.nmounts); -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5F_check_mounts_recurse() */ + /* Iterate over files mounted in this file and add in their open ID counts also */ + for(u = 0; u < f->mtab.nmounts; u++) { + /* Increment the open object count if the mount point group has an open ID */ + if(H5G_get_shared_count(f->mtab.child[u].group) > 1) + *nopen_objs += 1; + + H5F_mount_count_ids_recurse(f->mtab.child[u].file, nopen_files, nopen_objs); + } /* end for */ + + FUNC_LEAVE_NOAPI_VOID +} /* end H5F_mount_count_ids_recurse() */ /*------------------------------------------------------------------------- - * Function: H5F_check_mounts + * Function: H5F_mount_count_ids * - * Purpose: Check for file mounting hierarchies that have been created - * and that now are composed completely of files that are closing - * and have no more open objects in them. + * Purpose: Count the number of open file & object IDs in a mount hierarchy * - * When such a mounting hierarchy is detected, unmount and close - * all the files involved. - * - * Return: Non-negative on success/Negative on failure + * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol - * Saturday, July 2, 2005 + * Tues, July 19, 2005 * * Modifications: * *------------------------------------------------------------------------- */ herr_t -H5F_check_mounts(H5F_t *f) +H5F_mount_count_ids(H5F_t *f, unsigned *nopen_files, unsigned *nopen_objs) { - herr_t ret_value=SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(H5F_check_mounts, FAIL) -#ifdef QAK -HDfprintf(stderr, "%s: f->name=%s\n", FUNC, f->name); -HDfprintf(stderr, "%s: f->nrefs=%u\n", FUNC, f->nrefs); -HDfprintf(stderr, "%s: f->shared->nrefs=%u\n", FUNC, f->shared->nrefs); -HDfprintf(stderr, "%s: f->mtab.parent=%p\n", FUNC, f->mtab.parent); -HDfprintf(stderr, "%s: f->mtab.nmounts=%u\n", FUNC, f->mtab.nmounts); -HDfprintf(stderr, "%s: f->nopen_objs=%u\n", FUNC, f->nopen_objs); -HDfprintf(stderr, "%s: f->closing=%x\n", FUNC, f->closing); -#endif /* QAK */ - - /* Only try to close files for files involved in a mounting hierarchy */ - if(f->mtab.parent || f->mtab.nmounts) { - H5F_t *top = f; /* Pointer to the top file in the hierarchy */ - - /* Find the top file in the mounting hierarchy */ - while(top->mtab.parent) { - /* Get out early if we detect that this hierarchy won't close */ - if(top->nopen_objs != top->mtab.nmounts || !top->closing) - HGOTO_DONE(SUCCEED) - - /* Advance toward the top of the hierarchy */ - top = top->mtab.parent; - } /* end while */ - - /* Check for closing the hierarchy */ - if(H5F_check_mounts_recurse(top)) { - /* Unmount all child files */ - if(H5F_close_mounts(top) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't unmount child file") - - if(H5I_dec_ref(top->closing) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "can't decrement file closing ID") - } /* end if */ - } /* end if */ + FUNC_ENTER_NOAPI(H5F_mount_count_ids, FAIL) + + /* Sanity check */ + HDassert(f); + HDassert(nopen_files); + HDassert(nopen_objs); + + /* Find the top file in the mounting hierarchy */ + while(f->mtab.parent) + f = f->mtab.parent; + + /* Count open IDs in the hierarchy */ + H5F_mount_count_ids_recurse(f, nopen_files, nopen_objs); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5F_check_mounts() */ +} /* end H5F_mount_count_ids() */ diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index 1c91b8e..4a2c128 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -96,8 +96,8 @@ typedef struct H5F_file_t { unsigned super_chksum; /* Superblock checksum */ unsigned drvr_chksum; /* Driver info block checksum */ H5AC_t *cache; /* The object cache */ - hid_t fcpl_id; /* File creation property list ID */ int mdc_nelmts; /* Size of meta data cache (elements) */ + hid_t fcpl_id; /* File creation property list ID */ H5F_close_degree_t fc_degree; /* File close behavior degree */ size_t rdcc_nelmts; /* Size of raw data chunk cache (elmts) */ size_t rdcc_nbytes; /* Size of raw data chunk cache (bytes) */ @@ -139,13 +139,12 @@ typedef struct H5F_mtab_t { * indicate that the file is mounted on some other file). */ struct H5F_t { - unsigned nrefs; /* Reference count */ unsigned intent; /* The flags passed to H5F_open()*/ char *name; /* Name used to open file */ H5F_file_t *shared; /* The shared file info */ unsigned nopen_objs; /* Number of open object headers*/ hid_t file_id; /* ID of this file */ - hid_t closing; /* H5I_FILE_CLOSING ID or zero */ + hbool_t closing; /* File is in the process of being closed */ H5F_mtab_t mtab; /* File mount table */ }; @@ -160,14 +159,14 @@ H5_DLL void H5F_encode_length_unusual(const H5F_t *f, uint8_t **p, uint8_t *l); #endif /* NOT_YET */ /* General routines */ -H5_DLL herr_t H5F_close(H5F_t *f); +H5_DLL herr_t H5F_try_close(H5F_t *f); H5_DLL haddr_t H5F_locate_signature(H5FD_t *file, hid_t dxpl_id); /* File mount related routines */ H5_DLL herr_t H5F_mountpoint(struct H5G_entry_t *find/*in,out*/); H5_DLL herr_t H5F_close_mounts(H5F_t *f); H5_DLL int H5F_term_unmount_cb(void *obj_ptr, hid_t obj_id, void *key); -H5_DLL herr_t H5F_check_mounts(H5F_t *f); +H5_DLL herr_t H5F_mount_count_ids(H5F_t *f, unsigned *nopen_files, unsigned *nopen_objs); /* Superblock related routines */ H5_DLL herr_t H5F_init_superblock(const H5F_t *f, hid_t dxpl_id); diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index ba978a8..abe4752 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -418,8 +418,8 @@ H5_DLL hid_t H5F_get_driver_id(const H5F_t *f); H5_DLL unsigned H5F_get_intent(const H5F_t *f); H5_DLL herr_t H5F_get_fileno(const H5F_t *f, unsigned long *filenum); H5_DLL hid_t H5F_get_id(H5F_t *file); -H5_DLL int H5F_get_obj_count(const H5F_t *f, unsigned types); -H5_DLL int H5F_get_obj_ids(const H5F_t *f, unsigned types, int max_objs, hid_t *obj_id_list); +H5_DLL unsigned H5F_get_obj_count(const H5F_t *f, unsigned types); +H5_DLL unsigned H5F_get_obj_ids(const H5F_t *f, unsigned types, int max_objs, hid_t *obj_id_list); H5_DLL haddr_t H5F_get_base_addr(const H5F_t *f); H5_DLL haddr_t H5F_get_eoa(const H5F_t *f); #ifdef H5_HAVE_PARALLEL @@ -1011,7 +1011,7 @@ done: static herr_t H5G_init_interface(void) { - herr_t ret_value=SUCCEED; /* Return value */ + herr_t ret_value=SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5G_init_interface); @@ -1995,7 +1995,8 @@ H5G_open(H5G_entry_t *ent, hid_t dxpl_id) HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, NULL, "can't insert group into list of open objects") } - grp->shared->fo_count =1; + /* Set open object count */ + grp->shared->fo_count = 1; } else { if(NULL == (grp = H5FL_CALLOC(H5G_t))) @@ -2005,7 +2006,10 @@ H5G_open(H5G_entry_t *ent, hid_t dxpl_id) if(H5G_ent_copy(&(grp->ent), ent, H5G_COPY_SHALLOW)<0) HGOTO_ERROR (H5E_SYM, H5E_CANTCOPY, NULL, "can't copy group entry") - grp->shared=shared_fo; + /* Point to shared group info */ + grp->shared = shared_fo; + + /* Increment shared reference count */ shared_fo->fo_count++; } @@ -2158,11 +2162,14 @@ H5G_close(H5G_t *grp) HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to close"); H5FL_FREE (H5G_shared_t, grp->shared); } else { - /* Check if this group was the last object holding open a mounted file - * hierarchy and close down the file hierarchy if so */ - if(grp->shared->fo_count == 1) - if(H5F_check_mounts(grp->ent.file) < 0) - HGOTO_ERROR(H5E_SYM, H5E_MOUNT, FAIL, "problem checking mount hierarchy"); + /* If this group is a mount point and the mount point is the last open + * reference to the group, then attempt to close down the file hierarchy + */ + if(grp->shared->mounted && grp->shared->fo_count == 1) { + /* Attempt to close down the file hierarchy */ + if(H5F_try_close(grp->ent.file) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close") + } /* end if */ if(H5G_free_ent_name(&(grp->ent))<0) { @@ -2175,7 +2182,7 @@ H5G_close(H5G_t *grp) done: FUNC_LEAVE_NOAPI(ret_value); -} +} /* end H5G_close() */ /*------------------------------------------------------------------------- @@ -2435,6 +2442,9 @@ H5G_loc (hid_t loc_id) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "unable to get symbol table entry for root group"); /* Patch up root group's symbol table entry to reflect this file */ + /* (Since the root group info is only stored once for files which + * share an underlying low-level file) + */ /* (but only for non-mounted files) */ if(!f->mtab.parent) ret_value->file = f; @@ -4001,8 +4011,68 @@ H5G_get_shared_count(H5G_t *grp) FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_get_shared_count); /* Check args */ - assert(grp && grp->shared); + HDassert(grp && grp->shared); FUNC_LEAVE_NOAPI(grp->shared->fo_count); } /* end H5G_get_shared_count() */ + +/*------------------------------------------------------------------------- + * Function: H5G_mount + * + * Purpose: Sets the 'mounted' flag for a group + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, July 19, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_mount(H5G_t *grp) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_mount); + + /* Check args */ + HDassert(grp && grp->shared); + HDassert(grp->shared->mounted == FALSE); + + /* Set the 'mounted' flag */ + grp->shared->mounted = TRUE; + + FUNC_LEAVE_NOAPI(SUCCEED); +} /* end H5G_mount() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_unmount + * + * Purpose: Resets the 'mounted' flag for a group + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, July 19, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_unmount(H5G_t *grp) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_unmount); + + /* Check args */ + HDassert(grp && grp->shared); + HDassert(grp->shared->mounted == TRUE); + + /* Reset the 'mounted' flag */ + grp->shared->mounted = FALSE; + + FUNC_LEAVE_NOAPI(SUCCEED); +} /* end H5G_unmount() */ + diff --git a/src/H5Gpkg.h b/src/H5Gpkg.h index bc14364..11bd437 100644 --- a/src/H5Gpkg.h +++ b/src/H5Gpkg.h @@ -47,10 +47,11 @@ typedef struct H5G_node_t { } H5G_node_t; /* - * Reference count shared between all instances of an open group + * Shared information for all open group objects */ struct H5G_shared_t { int fo_count; /* open file object count */ + hbool_t mounted; /* Group is mount point */ }; /* diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h index 9eb8d85..912e7d5 100644 --- a/src/H5Gprivate.h +++ b/src/H5Gprivate.h @@ -157,6 +157,8 @@ H5_DLL herr_t H5G_replace_name(int type, H5G_entry_t *loc, H5RS_str_t *dst_name, H5G_entry_t *dst_loc, H5G_names_op_t op); H5_DLL herr_t H5G_free_grp_name(H5G_t *grp); H5_DLL herr_t H5G_get_shared_count(H5G_t *grp); +H5_DLL herr_t H5G_mount(H5G_t *grp); +H5_DLL herr_t H5G_unmount(H5G_t *grp); /* * These functions operate on symbol table nodes. @@ -114,7 +114,6 @@ H5FL_DEFINE_STATIC(H5I_id_info_t); /*--------------------- Local function prototypes ---------------------------*/ static H5I_id_info_t *H5I_find_id(hid_t id); static hid_t H5I_get_file_id(hid_t obj_id); -static int H5I_get_ref(hid_t id); #ifdef H5I_DEBUG_OUTPUT static herr_t H5I_debug(H5I_type_t grp); #endif /* H5I_DEBUG_OUTPUT */ @@ -311,9 +310,6 @@ int H5I_nmembers(H5I_type_t grp) { H5I_id_group_t *grp_ptr = NULL; - H5I_id_info_t *cur=NULL; - int n=0; - unsigned i; int ret_value; FUNC_ENTER_NOAPI(H5I_nmembers, FAIL); @@ -323,12 +319,8 @@ H5I_nmembers(H5I_type_t grp) if (NULL==(grp_ptr=H5I_id_group_list_g[grp]) || grp_ptr->count<=0) HGOTO_DONE(0); - for (i=0; i<grp_ptr->hash_size; i++) - for (cur=grp_ptr->id_list[i]; cur; cur=cur->next) - n++; - /* Set return value */ - ret_value=n; + H5_ASSIGN_OVERFLOW(ret_value, grp_ptr->ids, unsigned, int); done: FUNC_LEAVE_NOAPI(ret_value); @@ -1127,7 +1119,7 @@ done: * *------------------------------------------------------------------------- */ -static int +int H5I_get_ref(hid_t id) { H5I_type_t grp; /*group the object is in*/ @@ -1203,20 +1195,23 @@ H5I_search(H5I_type_t grp, H5I_search_func_t func, void *key) if (grp_ptr == NULL || grp_ptr->count <= 0) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "invalid group"); - /* Start at the beginning of the array */ - for (i=0; i<grp_ptr->hash_size; i++) { - id_ptr = grp_ptr->id_list[i]; - while (id_ptr) { - next_id= id_ptr->next; /* Protect against ID being deleted in callback */ - if ((*func)(id_ptr->obj_ptr, id_ptr->id, key)) - HGOTO_DONE(id_ptr->obj_ptr); /*found the item*/ - id_ptr = next_id; - } - } + /* Only iterate through hash table if there are IDs in group */ + if(grp_ptr->ids > 0) { + /* Start at the beginning of the array */ + for (i=0; i<grp_ptr->hash_size; i++) { + id_ptr = grp_ptr->id_list[i]; + while (id_ptr) { + next_id= id_ptr->next; /* Protect against ID being deleted in callback */ + if ((*func)(id_ptr->obj_ptr, id_ptr->id, key)) + HGOTO_DONE(id_ptr->obj_ptr); /*found the item*/ + id_ptr = next_id; + } /* end while */ + } /* end for */ + } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value); -} +} /* end H5I_search() */ /*------------------------------------------------------------------------- diff --git a/src/H5Iprivate.h b/src/H5Iprivate.h index a244d31..fb4b282 100644 --- a/src/H5Iprivate.h +++ b/src/H5Iprivate.h @@ -66,6 +66,7 @@ H5_DLL void *H5I_object_verify(hid_t id, H5I_type_t id_type); H5_DLL H5I_type_t H5I_get_type(hid_t id); H5_DLL void *H5I_remove(hid_t id); H5_DLL void *H5I_search(H5I_type_t grp, H5I_search_func_t func, void *key); +H5_DLL int H5I_get_ref(hid_t id); H5_DLL int H5I_inc_ref(hid_t id); H5_DLL int H5I_dec_ref(hid_t id); #endif diff --git a/src/H5Ipublic.h b/src/H5Ipublic.h index ce29be3..33ad2ad 100644 --- a/src/H5Ipublic.h +++ b/src/H5Ipublic.h @@ -35,7 +35,6 @@ typedef enum { H5I_BADID = (-1), /*invalid Group */ H5I_FILE = 1, /*group ID for File objects */ - H5I_FILE_CLOSING, /*files pending close due to open objhdrs */ H5I_GROUP, /*group ID for Group objects */ H5I_DATATYPE, /*group ID for Datatype objects */ H5I_DATASPACE, /*group ID for Dataspace objects */ @@ -405,7 +405,7 @@ H5O_close(H5G_entry_t *obj_ent) #ifdef H5O_DEBUG if (H5DEBUG(O)) { - if (obj_ent->file->closing && 1==obj_ent->file->shared->nrefs) { + if (obj_ent->file->file_id < 0 && 1==obj_ent->file->shared->nrefs) { HDfprintf(H5DEBUG(O), "< %a auto %lu remaining\n", obj_ent->header, (unsigned long)(obj_ent->file->nopen_objs)); @@ -416,28 +416,13 @@ H5O_close(H5G_entry_t *obj_ent) #endif /* - * If the file open-lock count has reached the number of open mount points - * (each of which has a group open in the file) and the file has a close - * pending then close the file and remove it from the H5I_FILE_CLOSING ID - * group. + * If the file open object count has reached the number of open mount points + * (each of which has a group open in the file) attempt to close the file. */ - /* Check for just mount points holding file open */ - if(obj_ent->file->mtab.nmounts == obj_ent->file->nopen_objs && obj_ent->file->closing) { - unsigned u; /* Local index variable */ - hbool_t really_close; /* Whether to delay the file close by going to a "closing" state */ - - /* Check for open groups on mount points */ - really_close = TRUE; - for(u = 0; u < obj_ent->file->mtab.nmounts; u++) { - if(H5G_get_shared_count(obj_ent->file->mtab.child[u].group) > 1) { - really_close = FALSE; - break; - } /* end if */ - } /* end for */ - - /* If we really want to close this file now */ - if(really_close) - H5I_dec_ref(obj_ent->file->closing); + if(obj_ent->file->nopen_objs == obj_ent->file->mtab.nmounts) { + /* Attempt to close down the file hierarchy */ + if(H5F_try_close(obj_ent->file) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close") } /* end if */ /* Free the ID to name buffers */ @@ -445,7 +430,7 @@ H5O_close(H5G_entry_t *obj_ent) done: FUNC_LEAVE_NOAPI(ret_value); -} +} /* end H5O_close() */ /*------------------------------------------------------------------------- diff --git a/test/Makefile.in b/test/Makefile.in index 83b2f94..26f144c 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -28,7 +28,7 @@ TEST_PROGS=testhdf5 lheap ohdr stab gheap cache hyperslab istore bittests \ dtypes dsets cmpd_dset extend external links unlink big mtime fillval \ mount flush1 flush2 enum gass_write gass_read gass_append set_extent \ srb_write srb_append srb_read ttsafe stream_test getname file_handle \ - ntypes dangle filename reserved + ntypes dangle reserved TIMINGS=testmeta @@ -61,7 +61,7 @@ MOSTLYCLEAN=cmpd_dset.h5 compact_dataset.h5 dataset.h5 extend.h5 istore.h5 \ getname.h5 getname1.h5 getname2.h5 getname3.h5 sec2_file.h5 \ family_file000[0-3][0-9].h5 multi_file-[rs].h5 core_file \ new_move_[ab].h5 ntypes.h5 dangle.h5 test_filters.h5 \ - get_file_name.h5 tstint[1-2].h5 unlink_chunked.h5 + tstint[1-2].h5 unlink_chunked.h5 CLEAN=$(TIMINGS) @@ -79,8 +79,7 @@ TEST_SRC=big.c bittests.c cache.c cmpd_dset.c dsets.c dtypes.c extend.c \ unlink.c enum.c ttsafe.c ttsafe_dcreate.c ttsafe_error.c \ ttsafe_cancel.c ttsafe_acreate.c gass_write.c gass_read.c \ gass_append.c srb_read.c srb_write.c srb_append.c stream_test.c \ - set_extent.c getname.c file_handle.c ntypes.c dangle.c filename.c \ - reserved.c + set_extent.c getname.c file_handle.c ntypes.c dangle.c reserved.c TEST_OBJ=$(TEST_SRC:.c=.lo) @@ -225,9 +224,6 @@ ntypes: ntypes.lo dangle: dangle.lo @$(LT_LINK_EXE) $(CFLAGS) -o $@ dangle.lo $(LIB) $(LIBHDF5) $(LDFLAGS) $(LIBS) -filename: filename.lo - @$(LT_LINK_EXE) $(CFLAGS) -o $@ filename.lo $(LIB) $(LIBHDF5) $(LDFLAGS) $(LIBS) - reserved: reserved.lo @$(LT_LINK_EXE) $(CFLAGS) -o $@ reserved.lo $(LIB) $(LIBHDF5) $(LDFLAGS) $(LIBS) diff --git a/test/filename.c b/test/filename.c deleted file mode 100644 index 32dfd63..0000000 --- a/test/filename.c +++ /dev/null @@ -1,154 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright by the Board of Trustees of the University of Illinois. * - * All rights reserved. * - * * - * This file is part of HDF5. The full HDF5 copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the files COPYING and Copyright.html. COPYING can be found at the root * - * of the source code distribution tree; Copyright.html can be found at the * - * root level of an installed copy of the electronic HDF5 document set and * - * is linked from the top-level documents page. It can also be found at * - * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * - * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* - * Programmer: Raymond Lu <slu@ncsa.uiuc.edu> - * June 29, 2004 - * - * Purpose: Tests the "H5Fget_name" functionality - */ - -#include "testhdf5.h" - -#define FILENAME "get_file_name" -#define GROUPNAME "group" -#define DSETNAME "dataset" -#define ATTRNAME "attribute" -#define DTYPENAME "compound" -#define NAME_BUF_SIZE 64 - -#define RANK 2 -#define NX 4 -#define NY 5 - -/* Compound datatype */ -typedef struct s1_t { - unsigned int a; - float b; -} s1_t; - -/* Used to make certain a return name _is_ the file name */ -#define VERIFY_NAME(x, val, where) do { \ - if (GetTestVerbosity()>=VERBO_HI) { \ - print_func(" Call to routine: %15s at line %4d in %s had value " \ - "%ld \n", (where), (int)__LINE__, __FILE__, (long)(x)); \ - } \ - if (strcmp(x, val)) { \ - TestErrPrintf("*** UNEXPECTED VALUE from %s should be %s, but is %s at line %4d " \ - "in %s\n", where, val, x, (int)__LINE__, __FILE__); \ - H5Eprint (stdout); \ - } \ -} while(0) - -int main( void ) -{ - char filename[NAME_BUF_SIZE]; - hid_t fapl; - hid_t file_id; - hid_t group_id; - hid_t dataset_id; - hid_t space_id; - hid_t type_id; - hid_t attr_id; - hsize_t dims[RANK] = {NX, NY}; - char name[NAME_BUF_SIZE]; - ssize_t name_len; - herr_t ret; - - TESTING("H5Fget_name"); - - /* Reset the library and get the file access property list */ - h5_reset(); - fapl = h5_fileaccess(); - - /* Initialize the file names */ - h5_fixname(FILENAME, fapl, filename, sizeof filename); - - /* Create a new file_id using default properties. */ - file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl ); - CHECK(file_id, FAIL, "H5Fcreate"); - - /* Get and verify file name */ - name_len = H5Fget_name(file_id, name, NAME_BUF_SIZE); - CHECK(name_len, FAIL, "H5Fget_name"); - VERIFY_NAME(name, filename, "H5Fget_name"); - - /* Create a group in the root group */ - group_id = H5Gcreate(file_id, GROUPNAME, 0); - CHECK(group_id, FAIL, "H5Gcreate"); - - /* Get and verify file name */ - name_len = H5Fget_name(group_id, name, NAME_BUF_SIZE); - CHECK(name_len, FAIL, "H5Fget_name"); - VERIFY_NAME(name, filename, "H5Fget_name"); - - /* Create the data space */ - space_id = H5Screate_simple(RANK, dims, NULL); - CHECK(space_id, FAIL, "H5Screate_simple"); - - /* Try get file name from data space. Supposed to fail because - * it's illegal operation. */ - H5E_BEGIN_TRY { - name_len = H5Fget_name(space_id, name, NAME_BUF_SIZE); - } H5E_END_TRY; - VERIFY(name_len, FAIL, "H5Fget_name"); - - /* Create a new dataset */ - dataset_id = H5Dcreate(file_id, DSETNAME, H5T_NATIVE_INT, space_id, H5P_DEFAULT); - CHECK(dataset_id, FAIL, "H5Dcreate"); - - /* Get and verify file name */ - name_len = H5Fget_name(dataset_id, name, NAME_BUF_SIZE); - CHECK(name_len, FAIL, "H5Fget_name"); - VERIFY_NAME(name, filename, "H5Fget_name"); - - /* Create an attribute for the dataset */ - attr_id = H5Acreate(dataset_id,ATTRNAME,H5T_NATIVE_INT,space_id,H5P_DEFAULT); - CHECK(attr_id, FAIL, "H5Acreate"); - - /* Get and verify file name */ - name_len = H5Fget_name(attr_id, name, NAME_BUF_SIZE); - CHECK(name_len, FAIL, "H5Fget_name"); - VERIFY_NAME(name, filename, "H5Fget_name"); - - /* Create a compound datatype */ - type_id = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); - CHECK(type_id, FAIL, "H5Tcreate"); - - /* Insert fields */ - ret = H5Tinsert (type_id, "a", HOFFSET(s1_t,a), H5T_NATIVE_INT); - CHECK(ret, FAIL, "H5Tinsert"); - - ret = H5Tinsert (type_id, "b", HOFFSET(s1_t,b), H5T_NATIVE_FLOAT); - CHECK(ret, FAIL, "H5Tinsert"); - - /* Save it on file */ - ret = H5Tcommit(file_id, DTYPENAME, type_id); - CHECK(ret, FAIL, "H5Tcommit"); - - /* Get and verify file name */ - name_len = H5Fget_name(type_id, name, NAME_BUF_SIZE); - CHECK(name_len, FAIL, "H5Fget_name"); - VERIFY_NAME(name, filename, "H5Fget_name"); - - H5Tclose(type_id); - H5Aclose(attr_id); - H5Dclose(dataset_id); - H5Sclose(space_id); - H5Gclose(group_id); - H5Fclose(file_id); - - PASSED(); - return 0; -} diff --git a/test/mount.c b/test/mount.c index 8df2b21..9da01f2 100644 --- a/test/mount.c +++ b/test/mount.c @@ -124,15 +124,21 @@ test_basic(hid_t fapl) h5_fixname(FILENAME[0], fapl, filename1, sizeof filename1); h5_fixname(FILENAME[1], fapl, filename2, sizeof filename2); - if ((file1=H5Fopen(filename1, H5F_ACC_RDONLY, fapl))<0 || - (file2=H5Fopen(filename2, H5F_ACC_RDONLY, fapl))<0) - goto error; - if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error; - if ((grp=H5Gopen(file1, "/mnt1/file2"))<0) goto error; - if (H5Gclose(grp)<0) goto error; - if (H5Funmount(file1, "/mnt1")<0) goto error; - if (H5Fclose(file1)<0) goto error; - if (H5Fclose(file2)<0) goto error; + if ((file1 = H5Fopen(filename1, H5F_ACC_RDONLY, fapl)) < 0 || + (file2 = H5Fopen(filename2, H5F_ACC_RDONLY, fapl)) < 0) + TEST_ERROR + if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT) < 0) + TEST_ERROR + if ((grp = H5Gopen(file1, "/mnt1/file2")) < 0) + TEST_ERROR + if (H5Gclose(grp) < 0) + TEST_ERROR + if (H5Funmount(file1, "/mnt1") < 0) + TEST_ERROR + if (H5Fclose(file1) < 0) + TEST_ERROR + if (H5Fclose(file2) < 0) + TEST_ERROR PASSED(); return 0; @@ -974,7 +980,6 @@ test_close(hid_t fapl) { hid_t file1=-1, file2=-1; char filename1[1024], filename2[1024]; - herr_t status; TESTING("file handle close"); h5_fixname(FILENAME[0], fapl, filename1, sizeof filename1); @@ -987,21 +992,21 @@ test_close(hid_t fapl) if (H5Fmount(file1, "/mnt1", file2, H5P_DEFAULT)<0) goto error; /* - * Close file1 unmounting it from the virtual file. Objects in file2 are - * still accessible through the file2 handle, but nothing in file1 is - * accessible. + * Close file1 unmounting it from the virtual file. Objects in file1 are + * still accessible through the file2 handle. */ if (H5Fclose(file1)<0) goto error; - H5E_BEGIN_TRY { - status = H5Gget_objinfo(file2, "/mnt1", TRUE, NULL); - } H5E_END_TRY; - if (status>=0) { + if(H5Gget_objinfo(file2, "/mnt1", TRUE, NULL) < 0) { H5_FAILED(); - puts(" File1 contents are still accessible!"); + puts(" File1 contents are not accessible!"); goto error; } if (H5Fclose(file2)<0) goto error; + /* Check that all file IDs have been closed */ + if(H5I_nmembers(H5I_FILE) != 0) + TEST_ERROR + /* Build the virtual file again */ if ((file1=H5Fopen(filename1, H5F_ACC_RDWR, fapl))<0 || (file2=H5Fopen(filename2, H5F_ACC_RDWR, fapl))<0) @@ -1015,6 +1020,10 @@ test_close(hid_t fapl) if (H5Gget_objinfo(file1, "/mnt1/file2", TRUE, NULL)<0) goto error; if (H5Fclose(file1)<0) goto error; + /* Check that all file IDs have been closed */ + if(H5I_nmembers(H5I_FILE) != 0) + TEST_ERROR + /* Shut down */ PASSED(); return 0; @@ -1659,10 +1668,6 @@ test_missing_unmount(hid_t fapl) if(H5I_nmembers(H5I_FILE) != 0) TEST_ERROR - /* Check that all "file closing" IDs have been closed */ - if(H5I_nmembers(H5I_FILE_CLOSING) != 0) - TEST_ERROR - PASSED(); return 0; @@ -1797,10 +1802,6 @@ test_hold_open_file(hid_t fapl) if(H5I_nmembers(H5I_FILE) != 0) TEST_ERROR - /* Check that all "file closing" IDs have been closed */ - if(H5I_nmembers(H5I_FILE_CLOSING) != 0) - TEST_ERROR - PASSED(); return 0; @@ -1837,7 +1838,7 @@ static int test_hold_open_group(hid_t fapl) { hid_t fid1 = -1, fid2 = -1; /* File IDs */ - hid_t gidA = -1, gidM = -1, gidAM = -1, gidAM2 = -1; /* Group IDs */ + hid_t gid = -1, gidA = -1, gidM = -1, gidAM = -1, gidAM2 = -1; /* Group IDs */ char filename1[1024], filename2[1024]; /* Name of files to mount */ @@ -1918,21 +1919,326 @@ test_hold_open_group(hid_t fapl) if((gidAM2 = H5Gopen(fid1, "/A/M")) < 0) TEST_ERROR + /* Close file #1 */ + if(H5Fclose(fid1) < 0) + TEST_ERROR + + /* Get ID of file #2 */ + if((fid2 = H5Iget_file_id(gidAM2)) < 0) + TEST_ERROR + + /* Close group in mounted file */ + if(H5Gclose(gidAM2) < 0) + TEST_ERROR + + /* Attempt to open group in mounted file */ + /* (Should work because file is still mounted) */ + if((gidAM2 = H5Gopen(fid2, "/A/M")) < 0) + TEST_ERROR + + /* Close file #2 */ + if(H5Fclose(fid2) < 0) + TEST_ERROR + + /* Attempt to open group in parent file */ + /* (Should work because files should be mounted together) */ + if((gid = H5Gopen(gidAM2, "/")) < 0) + TEST_ERROR + /* Close group in mounted file */ if(H5Gclose(gidAM2) < 0) TEST_ERROR + /* Close group in parent file */ + if(H5Gclose(gid) < 0) + TEST_ERROR + + /* Check that all file IDs have been closed */ + if(H5I_nmembers(H5I_FILE) != 0) + TEST_ERROR + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY { + H5Gclose(gidM); + H5Gclose(gidAM); + H5Gclose(gidAM2); + H5Gclose(gidA); + H5Gclose(gid); + H5Fclose(fid2); + H5Fclose(fid1); + } H5E_END_TRY; + return 1; +} /* end test_hold_open_group() */ + + +/*------------------------------------------------------------------------- + * Function: test_fcdegree_same + * + * Purpose: Test that the library will only allow files with same file + * close degree to be mounted together. + * + * Return: Success: 0 + * + * Failure: number of errors + * + * Programmer: Quincey Koziol + * Tuesday, July 19, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +test_fcdegree_same(hid_t fapl) +{ + hid_t fid1 = -1, fid2 = -1; /* File IDs */ + hid_t gidA = -1, gidM = -1, gidAM = -1; /* Group IDs */ + hid_t fapl_id = -1; /* FAPL IDs */ + herr_t ret; /* Generic return value */ + char filename1[1024], + filename2[1024]; /* Name of files to mount */ + + TESTING("file close degrees must be same"); + + h5_fixname(FILENAME[0], fapl, filename1, sizeof filename1); + h5_fixname(FILENAME[1], fapl, filename2, sizeof filename2); + + /* Create file #1 */ + if((fid1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidA = H5Gcreate(fid1, "A", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidA) < 0) + TEST_ERROR + + if(H5Fclose(fid1) < 0) + TEST_ERROR + + + /* Create file #2 */ + if((fid2 = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidM = H5Gcreate(fid2, "M", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidM) < 0) + TEST_ERROR + + if(H5Fclose(fid2) < 0) + TEST_ERROR + + + /* Re-open files and mount file #2 in file #1 */ + if((fid1 = H5Fopen(filename1, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidA = H5Gopen(fid1, "A")) < 0) + TEST_ERROR + + /* Create FAPL & set file close degree for file #2 to be different */ + if((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + TEST_ERROR + + /* Set file close mode to H5F_CLOSE_STRONG */ + if(H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG) < 0) + TEST_ERROR + + if((fid2 = H5Fopen(filename2, H5F_ACC_RDONLY, fapl_id)) < 0) + TEST_ERROR + + /* Try mounting file with different file close degree (should fail) */ + H5E_BEGIN_TRY { + ret = H5Fmount(gidA, ".", fid2, H5P_DEFAULT); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR + + /* Set file close mode to H5F_CLOSE_WEAK */ + if(H5Pset_fclose_degree(fapl_id, H5F_CLOSE_WEAK) < 0) + TEST_ERROR + + /* Close file #2 & re-open with same file close degree as file #1 */ + if(H5Fclose(fid2) < 0) + TEST_ERROR + if((fid2 = H5Fopen(filename2, H5F_ACC_RDONLY, fapl_id)) < 0) + TEST_ERROR + + /* Try mounting files again (should work now) */ + if(H5Fmount(gidA, ".", fid2, H5P_DEFAULT) < 0) + TEST_ERROR + + /* Verify opening group in mounted file */ + if((gidAM = H5Gopen(fid1, "A/M")) < 0) + TEST_ERROR + + /* Close group in mounted file */ + if(H5Gclose(gidAM) < 0) + TEST_ERROR + + /* Close group in parent file */ + if(H5Gclose(gidA) < 0) + TEST_ERROR + + /* Close file #2 */ + if(H5Fclose(fid2) < 0) + TEST_ERROR + /* Close file #1 */ - /* (should unmount file #2 also) */ if(H5Fclose(fid1) < 0) TEST_ERROR + /* Close FAPL ID */ + if(H5Pclose(fapl_id) < 0) + TEST_ERROR + /* Check that all file IDs have been closed */ if(H5I_nmembers(H5I_FILE) != 0) TEST_ERROR - /* Check that all "file closing" IDs have been closed */ - if(H5I_nmembers(H5I_FILE_CLOSING) != 0) + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY { + H5Pclose(fapl_id); + H5Gclose(gidM); + H5Gclose(gidAM); + H5Gclose(gidA); + H5Fclose(fid2); + H5Fclose(fid1); + } H5E_END_TRY; + return 1; +} /* end test_fcdegree_same() */ + + +/*------------------------------------------------------------------------- + * Function: test_fcdegree_semi + * + * Purpose: Test that the library perform correct actions when using + * "semi" file close degree on mounted files + * + * Return: Success: 0 + * + * Failure: number of errors + * + * Programmer: Quincey Koziol + * Tuesday, July 19, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +test_fcdegree_semi(hid_t fapl) +{ + hid_t fid1 = -1, fid2 = -1; /* File IDs */ + hid_t gidA = -1, gidM = -1, gidAM = -1; /* Group IDs */ + hid_t fapl_id = -1; /* FAPL IDs */ + herr_t ret; /* Generic return value */ + char filename1[1024], + filename2[1024]; /* Name of files to mount */ + + TESTING("'semi' file close degree"); + + h5_fixname(FILENAME[0], fapl, filename1, sizeof filename1); + h5_fixname(FILENAME[1], fapl, filename2, sizeof filename2); + + /* Create file #1 */ + if((fid1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidA = H5Gcreate(fid1, "A", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidA) < 0) + TEST_ERROR + + if(H5Fclose(fid1) < 0) + TEST_ERROR + + + /* Create file #2 */ + if((fid2 = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidM = H5Gcreate(fid2, "M", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidM) < 0) + TEST_ERROR + + if(H5Fclose(fid2) < 0) + TEST_ERROR + + + /* Create FAPL & set file close degree to be "semi" */ + if((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + TEST_ERROR + + /* Set file close mode to H5F_CLOSE_SEMI */ + if(H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI) < 0) + TEST_ERROR + + /* Re-open files and mount file #2 in file #1 */ + if((fid1 = H5Fopen(filename1, H5F_ACC_RDONLY, fapl_id)) < 0) + TEST_ERROR + + if((gidA = H5Gopen(fid1, "A")) < 0) + TEST_ERROR + + if((fid2 = H5Fopen(filename2, H5F_ACC_RDONLY, fapl_id)) < 0) + TEST_ERROR + + /* Mount files together */ + if(H5Fmount(gidA, ".", fid2, H5P_DEFAULT) < 0) + TEST_ERROR + + /* Verify opening group in mounted file */ + if((gidAM = H5Gopen(fid1, "A/M")) < 0) + TEST_ERROR + + /* Close file #1 (should succeed, since file #2 is open still) */ + if(H5Fclose(fid1) < 0) + TEST_ERROR + + /* Try closing file #2 (should fail, since there are still objects open) */ + H5E_BEGIN_TRY { + ret = H5Fclose(fid2); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR + + /* Close group in parent file */ + if(H5Gclose(gidA) < 0) + TEST_ERROR + + /* Try closing file #2 (should still fail, since there are still objects open in child file) */ + H5E_BEGIN_TRY { + ret = H5Fclose(fid2); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR + + /* Close group in mounted file */ + if(H5Gclose(gidAM) < 0) + TEST_ERROR + + /* Close file #2 (should succeed now) */ + if(H5Fclose(fid2) < 0) + TEST_ERROR + + /* Close FAPL ID */ + if(H5Pclose(fapl_id) < 0) + TEST_ERROR + + /* Check that all file IDs have been closed */ + if(H5I_nmembers(H5I_FILE) != 0) TEST_ERROR PASSED(); @@ -1940,15 +2246,356 @@ test_hold_open_group(hid_t fapl) error: H5E_BEGIN_TRY { + H5Pclose(fapl_id); H5Gclose(gidM); H5Gclose(gidAM); - H5Gclose(gidAM2); H5Gclose(gidA); H5Fclose(fid2); H5Fclose(fid1); } H5E_END_TRY; return 1; -} /* end test_hold_open_group() */ +} /* end test_fcdegree_semi() */ + + +/*------------------------------------------------------------------------- + * Function: test_fcdegree_strong + * + * Purpose: Test that the library perform correct actions when using + * "strong" file close degree on mounted files + * + * Return: Success: 0 + * + * Failure: number of errors + * + * Programmer: Quincey Koziol + * Tuesday, July 19, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +test_fcdegree_strong(hid_t fapl) +{ + hid_t fid1 = -1, fid2 = -1; /* File IDs */ + hid_t gidA = -1, gidM = -1, gidAM = -1; /* Group IDs */ + hid_t fapl_id = -1; /* FAPL IDs */ + herr_t ret; /* Generic return value */ + char filename1[1024], + filename2[1024]; /* Name of files to mount */ + + TESTING("'strong' file close degree"); + + h5_fixname(FILENAME[0], fapl, filename1, sizeof filename1); + h5_fixname(FILENAME[1], fapl, filename2, sizeof filename2); + + /* Create file #1 */ + if((fid1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidA = H5Gcreate(fid1, "A", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidA) < 0) + TEST_ERROR + + if(H5Fclose(fid1) < 0) + TEST_ERROR + + + /* Create file #2 */ + if((fid2 = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidM = H5Gcreate(fid2, "M", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidM) < 0) + TEST_ERROR + + if(H5Fclose(fid2) < 0) + TEST_ERROR + + + /* Create FAPL & set file close degree to be "strong" */ + if((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + TEST_ERROR + + /* Set file close mode to H5F_CLOSE_STRONG */ + if(H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG) < 0) + TEST_ERROR + + /* Re-open files and mount file #2 in file #1 */ + if((fid1 = H5Fopen(filename1, H5F_ACC_RDONLY, fapl_id)) < 0) + TEST_ERROR + + if((gidA = H5Gopen(fid1, "A")) < 0) + TEST_ERROR + + if((fid2 = H5Fopen(filename2, H5F_ACC_RDONLY, fapl_id)) < 0) + TEST_ERROR + + /* Mount files together */ + if(H5Fmount(gidA, ".", fid2, H5P_DEFAULT) < 0) + TEST_ERROR + + /* Open group in mounted file */ + if((gidAM = H5Gopen(fid1, "A/M")) < 0) + TEST_ERROR + + /* Close file #1 */ + if(H5Fclose(fid1) < 0) + TEST_ERROR + + /* Check that objects are still open */ + if (H5Gget_objinfo(gidA, ".", TRUE, NULL) < 0) + TEST_ERROR + if (H5Gget_objinfo(gidAM, ".", TRUE, NULL) < 0) + TEST_ERROR + + /* Close file #2 (should close open objects also) */ + if(H5Fclose(fid2) < 0) + TEST_ERROR + + /* Check that objects are closed */ + H5E_BEGIN_TRY { + ret = H5Gget_objinfo(gidA, ".", TRUE, NULL); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR + H5E_BEGIN_TRY { + ret = H5Gget_objinfo(gidAM, ".", TRUE, NULL); + } H5E_END_TRY; + if(ret >= 0) + TEST_ERROR + + /* Close FAPL ID */ + if(H5Pclose(fapl_id) < 0) + TEST_ERROR + + /* Check that all file IDs have been closed */ + if(H5I_nmembers(H5I_FILE) != 0) + TEST_ERROR + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY { + H5Pclose(fapl_id); + H5Gclose(gidM); + H5Gclose(gidAM); + H5Gclose(gidA); + H5Fclose(fid2); + H5Fclose(fid1); + } H5E_END_TRY; + return 1; +} /* end test_fcdegree_strong() */ + + +/*------------------------------------------------------------------------- + * Function: test_acc_perm + * + * Purpose: Test that the library correctly segregates operations in + * parts of mounted file hierarchy with files that have different + * R/W access permissions. + * + * + * Return: Success: 0 + * + * Failure: number of errors + * + * Programmer: Quincey Koziol + * Tuesday, July 19, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +test_acc_perm(hid_t fapl) +{ + hid_t fid1 = -1, fid2 = -1, fid3 = -1; /* File IDs */ + hid_t gidA = -1, gidB = -1, gidC = -1, gidM = -1, gidAM = -1, gidAMZ = -1; /* Group IDs */ + hid_t bad_id = -1; /* Bad ID from object create */ + char name[NAME_BUF_SIZE]; /* Buffer for filename retrieved */ + ssize_t name_len; /* Filename length */ + char filename1[1024], + filename2[1024], + filename3[1024]; /* Name of files to mount */ + + TESTING("access permissions"); + + h5_fixname(FILENAME[0], fapl, filename1, sizeof filename1); + h5_fixname(FILENAME[1], fapl, filename2, sizeof filename2); + h5_fixname(FILENAME[2], fapl, filename3, sizeof filename3); + + /* Create file #1 */ + if((fid1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidA = H5Gcreate(fid1, "A", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidA) < 0) + TEST_ERROR + + if(H5Fclose(fid1) < 0) + TEST_ERROR + + + /* Create file #2 */ + if((fid2 = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidM = H5Gcreate(fid2, "M", (size_t)0)) < 0) + TEST_ERROR + + if(H5Gclose(gidM) < 0) + TEST_ERROR + + if(H5Fclose(fid2) < 0) + TEST_ERROR + + + /* Re-open files and mount file #2 in file #1 */ + if((fid1 = H5Fopen(filename1, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) + TEST_ERROR + + if((gidA = H5Gopen(fid1, "A")) < 0) + TEST_ERROR + + /* Get and verify file name */ + if((name_len = H5Fget_name(gidA, name, NAME_BUF_SIZE)) < 0) + TEST_ERROR + if(HDstrcmp(name, filename1) != 0) + TEST_ERROR + + if((fid2 = H5Fopen(filename2, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) + TEST_ERROR + + /* Get and verify file name */ + if((name_len = H5Fget_name(fid2, name, NAME_BUF_SIZE)) < 0) + TEST_ERROR + if(HDstrcmp(name, filename2) != 0) + TEST_ERROR + + /* Mount files together */ + if(H5Fmount(gidA, ".", fid2, H5P_DEFAULT) < 0) + TEST_ERROR + + /* Get and verify file name */ + if((name_len = H5Fget_name(fid2, name, NAME_BUF_SIZE)) < 0) + TEST_ERROR + if(HDstrcmp(name, filename2) != 0) + TEST_ERROR + + /* Open group in mounted file */ + if((gidAM = H5Gopen(fid1, "A/M")) < 0) + TEST_ERROR + + /* Get and verify file name */ + if((name_len = H5Fget_name(gidAM, name, NAME_BUF_SIZE)) < 0) + TEST_ERROR + if(HDstrcmp(name, filename2) != 0) + TEST_ERROR + + /* Attempt to create objects in read only file (should fail) */ + H5E_BEGIN_TRY { + bad_id = H5Gcreate(gidAM, "Z", (size_t)0); + } H5E_END_TRY; + if(bad_id >= 0) + TEST_ERROR + H5E_BEGIN_TRY { + bad_id = H5Gcreate(fid1, "/A/L", (size_t)0); + } H5E_END_TRY; + if(bad_id >= 0) + TEST_ERROR + + /* Attempt to create objects in read/write file (should succeed) */ + if((gidB = H5Gcreate(fid2, "/B", (size_t)0)) < 0) + TEST_ERROR + if(H5Gclose(gidB) < 0) + TEST_ERROR + + /* (Note that this object should get created in the "hidden" group for "A" in parent file) */ + if((gidC = H5Gcreate(gidA, "C", (size_t)0)) < 0) + TEST_ERROR + if(H5Gclose(gidC) < 0) + TEST_ERROR + + /* Create file #3 (it will have R/W permissions) */ + if((fid3 = H5Fcreate(filename3, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + /* Mount file #3 on file #2 */ + if(H5Fmount(gidAM, ".", fid3, H5P_DEFAULT) < 0) + TEST_ERROR + + /* Attempt to create objects in read/write file (should succeed) */ + if((gidAMZ = H5Gcreate(fid1, "/A/M/Z", (size_t)0)) < 0) + TEST_ERROR + + /* Get and verify file name */ + if((name_len = H5Fget_name(gidAMZ, name, NAME_BUF_SIZE)) < 0) + TEST_ERROR + if(HDstrcmp(name, filename3) != 0) + TEST_ERROR + + /* Close object in file #3 */ + if(H5Gclose(gidAMZ) < 0) + TEST_ERROR + + + /* Attempt to create objects in read only file again (should fail) */ + H5E_BEGIN_TRY { + bad_id = H5Gcreate(fid1, "/A/L", (size_t)0); + } H5E_END_TRY; + if(bad_id >= 0) + TEST_ERROR + + /* Close group in mounted file */ + if(H5Gclose(gidAM) < 0) + TEST_ERROR + + /* Close group in parent file */ + if(H5Gclose(gidA) < 0) + TEST_ERROR + + /* Close file #3 */ + if(H5Fclose(fid3) < 0) + TEST_ERROR + + /* Close file #2 */ + if(H5Fclose(fid2) < 0) + TEST_ERROR + + /* Close file #1 */ + if(H5Fclose(fid1) < 0) + TEST_ERROR + + + /* Check that all file IDs have been closed */ + if(H5I_nmembers(H5I_FILE) != 0) + TEST_ERROR + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY { + H5Gclose(gidM); + H5Gclose(gidAMZ); + H5Gclose(gidAM); + H5Gclose(gidC); + H5Gclose(gidB); + H5Gclose(gidA); + H5Fclose(fid3); + H5Fclose(fid2); + H5Fclose(fid1); + } H5E_END_TRY; + return 1; +} /* end test_acc_perm() */ /*------------------------------------------------------------------------- @@ -1995,6 +2642,10 @@ main(void) nerrors += test_missing_unmount(fapl); nerrors += test_hold_open_file(fapl); nerrors += test_hold_open_group(fapl); + nerrors += test_fcdegree_same(fapl); + nerrors += test_fcdegree_semi(fapl); + nerrors += test_fcdegree_strong(fapl); + nerrors += test_acc_perm(fapl); if (nerrors) goto error; puts("All mount tests passed."); diff --git a/test/testhdf5.h b/test/testhdf5.h index ffea037..a29093b 100644 --- a/test/testhdf5.h +++ b/test/testhdf5.h @@ -67,7 +67,7 @@ } \ } -/* Used to make certain a return value _is_ a value */ +/* Used to make certain a scalar return value _is_ a value */ #define VERIFY(x, val, where) do { \ if (GetTestVerbosity()>=VERBO_HI) { \ print_func(" Call to routine: %15s at line %4d in %s had value " \ @@ -80,6 +80,19 @@ } \ } while(0) +/* Used to make certain a string return value _is_ a value */ +#define VERIFY_STR(x, val, where) do { \ + if (GetTestVerbosity()>=VERBO_HI) { \ + print_func(" Call to routine: %15s at line %4d in %s had value " \ + "%s \n", (where), (int)__LINE__, __FILE__, x); \ + } \ + if (HDstrcmp(x, val)) { \ + TestErrPrintf("*** UNEXPECTED VALUE from %s should be %s, but is %s at line %4d " \ + "in %s\n", where, val, x, (int)__LINE__, __FILE__); \ + H5Eprint (stdout); \ + } \ +} while(0) + /* Used to document process through a test and to check for errors */ #define RESULT(ret,func) do { \ if (GetTestVerbosity()>VERBO_MED) { \ diff --git a/test/tfile.c b/test/tfile.c index dbe974b..057ebb5 100644 --- a/test/tfile.c +++ b/test/tfile.c @@ -69,6 +69,15 @@ #define DSET1 "Dataset1" #define DSET2 "/Group1/Dataset2" +#define TESTA_GROUPNAME "group" +#define TESTA_DSETNAME "dataset" +#define TESTA_ATTRNAME "attribute" +#define TESTA_DTYPENAME "compound" +#define TESTA_NAME_BUF_SIZE 64 +#define TESTA_RANK 2 +#define TESTA_NX 4 +#define TESTA_NY 5 + static void create_objects(hid_t, hid_t, hid_t *, hid_t *, hid_t *, hid_t *); static void @@ -1455,64 +1464,181 @@ test_file_open_overlap(void) /* Create file */ fid1 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); - assert(fid1 > 0); + CHECK(fid1, FAIL, "H5Fcreate"); /* Open file also */ fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, H5P_DEFAULT); - assert(fid2 > 0); + CHECK(fid2, FAIL, "H5Fopen"); /* Create a group in file */ gid = H5Gcreate(fid1, GROUP1, (size_t)0); - assert(gid > 0); + CHECK(gid, FAIL, "H5Gcreate"); /* Create dataspace for dataset */ sid = H5Screate(H5S_SCALAR); - assert(sid > 0); + CHECK(sid, FAIL, "H5Screate"); /* Create dataset in group w/first file ID */ did1 = H5Dcreate(gid, DSET1, H5T_NATIVE_INT, sid, H5P_DEFAULT); - assert(did1 > 0); + CHECK(did1, FAIL, "H5Dcreate"); /* Check number of objects opened in first file */ nobjs = H5Fget_obj_count(fid1, H5F_OBJ_LOCAL|H5F_OBJ_ALL); - assert(nobjs == 3); /* 3 == file, dataset & group */ + VERIFY(nobjs, 3, "H5Fget_obj_count"); /* 3 == file, dataset & group */ /* Close dataset */ ret = H5Dclose(did1); - assert(ret >= 0); + CHECK(ret, FAIL, "H5Dclose"); /* Close group */ ret = H5Gclose(gid); - assert(ret >= 0); + CHECK(ret, FAIL, "H5Gclose"); /* Close first file ID */ ret = H5Fclose(fid1); - assert(ret >= 0); + CHECK(ret, FAIL, "H5Fclose"); /* Create dataset with second file ID */ did2 = H5Dcreate(fid2, DSET2, H5T_NATIVE_INT, sid, H5P_DEFAULT); - assert(did2 > 0); + CHECK(did2, FAIL, "H5Dcreate"); /* Check number of objects opened in first file */ nobjs = H5Fget_obj_count(fid2, H5F_OBJ_ALL); - assert(nobjs == 2); /* 2 == file & dataset */ + VERIFY(nobjs, 2, "H5Fget_obj_count"); /* 3 == file & dataset */ /* Close dataspace */ ret = H5Sclose(sid); - assert(ret >= 0); + CHECK(ret, FAIL, "H5Sclose"); /* Close second dataset */ ret = H5Dclose(did2); - assert(ret >= 0); + CHECK(ret, FAIL, "H5Dclose"); /* Close second file */ ret = H5Fclose(fid2); - assert(ret >= 0); + CHECK(ret, FAIL, "H5Fclose"); } /* end test_file_open_overlap() */ /**************************************************************** ** +** test_file_getname(): low-level file test routine. +** This test checks whether H5Fget_name works correctly. +** +*****************************************************************/ +static void +test_file_getname(void) +{ + /* Compound datatype */ + typedef struct s1_t { + unsigned int a; + float b; + } s1_t; + + hid_t file_id; + hid_t group_id; + hid_t dataset_id; + hid_t space_id; + hid_t type_id; + hid_t attr_id; + hsize_t dims[TESTA_RANK] = {TESTA_NX, TESTA_NY}; + char name[TESTA_NAME_BUF_SIZE]; + ssize_t name_len; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing H5Fget_name() functionality\n")); + + /* Create a new file_id using default properties. */ + file_id = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT ); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Get and verify file name */ + name_len = H5Fget_name(file_id, name, TESTA_NAME_BUF_SIZE); + CHECK(name_len, FAIL, "H5Fget_name"); + VERIFY_STR(name, FILE1, "H5Fget_name"); + + /* Create a group in the root group */ + group_id = H5Gcreate(file_id, TESTA_GROUPNAME, 0); + CHECK(group_id, FAIL, "H5Gcreate"); + + /* Get and verify file name */ + name_len = H5Fget_name(group_id, name, TESTA_NAME_BUF_SIZE); + CHECK(name_len, FAIL, "H5Fget_name"); + VERIFY_STR(name, FILE1, "H5Fget_name"); + + /* Create the data space */ + space_id = H5Screate_simple(TESTA_RANK, dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + + /* Try get file name from data space. Supposed to fail because + * it's illegal operation. */ + H5E_BEGIN_TRY { + name_len = H5Fget_name(space_id, name, TESTA_NAME_BUF_SIZE); + } H5E_END_TRY; + VERIFY(name_len, FAIL, "H5Fget_name"); + + /* Create a new dataset */ + dataset_id = H5Dcreate(file_id, TESTA_DSETNAME, H5T_NATIVE_INT, space_id, H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dcreate"); + + /* Get and verify file name */ + name_len = H5Fget_name(dataset_id, name, TESTA_NAME_BUF_SIZE); + CHECK(name_len, FAIL, "H5Fget_name"); + VERIFY_STR(name, FILE1, "H5Fget_name"); + + /* Create an attribute for the dataset */ + attr_id = H5Acreate(dataset_id,TESTA_ATTRNAME,H5T_NATIVE_INT,space_id,H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate"); + + /* Get and verify file name */ + name_len = H5Fget_name(attr_id, name, TESTA_NAME_BUF_SIZE); + CHECK(name_len, FAIL, "H5Fget_name"); + VERIFY_STR(name, FILE1, "H5Fget_name"); + + /* Create a compound datatype */ + type_id = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(type_id, FAIL, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert (type_id, "a", HOFFSET(s1_t,a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert (type_id, "b", HOFFSET(s1_t,b), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save it on file */ + ret = H5Tcommit(file_id, TESTA_DTYPENAME, type_id); + CHECK(ret, FAIL, "H5Tcommit"); + + /* Get and verify file name */ + name_len = H5Fget_name(type_id, name, TESTA_NAME_BUF_SIZE); + CHECK(name_len, FAIL, "H5Fget_name"); + VERIFY_STR(name, FILE1, "H5Fget_name"); + + /* Close things down */ + ret = H5Tclose(type_id); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Gclose(group_id); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_file_getname() */ + +/**************************************************************** +** ** test_file(): Main low-level file I/O test routine. ** ****************************************************************/ @@ -1533,6 +1659,7 @@ test_file(void) test_file_ishdf5(); /* Test detecting HDF5 files correctly */ test_file_open_dot(); /* Test opening objects with "." for a name */ test_file_open_overlap(); /* Test opening files in an overlapping manner */ + test_file_getname(); /* Test basic H5Fget_name() functionality */ } /* test_file() */ |