From bb31e94a924a1b3f6f1da6c10ffe95029c87d5c5 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Thu, 21 Jul 2005 09:48:26 -0500 Subject: [svn-r11093] 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 --- MANIFEST | 1 - src/H5.c | 108 ++++----- src/H5D.c | 17 +- src/H5F.c | 723 ++++++++++++++++++++++++++++++++----------------------- src/H5Fmount.c | 186 ++++++-------- src/H5Fpkg.h | 9 +- src/H5Fprivate.h | 4 +- src/H5G.c | 88 ++++++- src/H5Gpkg.h | 3 +- src/H5Gprivate.h | 2 + src/H5I.c | 51 ++-- src/H5Iprivate.h | 1 + src/H5Ipublic.h | 1 - src/H5O.c | 34 +-- test/Makefile.am | 2 +- test/Makefile.in | 34 +-- test/filename.c | 154 ------------ test/mount.c | 719 +++++++++++++++++++++++++++++++++++++++++++++++++++--- test/testhdf5.h | 13 + test/tfile.c | 155 ++++++++++-- 20 files changed, 1527 insertions(+), 778 deletions(-) delete mode 100644 test/filename.c diff --git a/MANIFEST b/MANIFEST index 1e48d0e..71ea466 100644 --- a/MANIFEST +++ b/MANIFEST @@ -622,7 +622,6 @@ a------------------------------------------------------------------------------ ./test/family_v1.6_00001.h5 ./test/family_v1.6_00002.h5 ./test/family_v1.6_00003.h5 -./test/filename.c ./test/fill_old.h5 ./test/fillval.c ./test/flush1.c diff --git a/src/H5.c b/src/H5.c index 5956c9e..cb86136 100644 --- a/src/H5.c +++ b/src/H5.c @@ -2098,9 +2098,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; @@ -2300,60 +2297,57 @@ 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_UNINIT: - fprintf (out, "H5I_UNINIT"); - break; - 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_ERROR_CLASS: - fprintf (out, "H5I_ERROR_CLASS"); - break; - case H5I_ERROR_MSG: - fprintf (out, "H5I_ERROR_MSG"); - break; - case H5I_ERROR_STACK: - fprintf (out, "H5I_ERROR_STACK"); - break; - case H5I_NTYPES: - fprintf (out, "H5I_NTYPES"); - break; - default: - fprintf (out, "%ld", (long)id_type); - break; + case H5I_UNINIT: + fprintf (out, "H5I_UNINIT"); + 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_ERROR_CLASS: + fprintf (out, "H5I_ERROR_CLASS"); + break; + case H5I_ERROR_MSG: + fprintf (out, "H5I_ERROR_MSG"); + break; + case H5I_ERROR_STACK: + fprintf (out, "H5I_ERROR_STACK"); + break; + case H5I_NTYPES: + fprintf (out, "H5I_NTYPES"); + break; + default: + fprintf (out, "%ld", (long)id_type); + break; } } break; diff --git a/src/H5D.c b/src/H5D.c index 41376a9..5f9658d 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -4101,8 +4101,6 @@ done: * * Date: August 14, 2002 * - * Comments: Just flushing the compact data information currently. - * * Modifications: * *------------------------------------------------------------------------- @@ -4110,11 +4108,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) @@ -4122,18 +4120,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 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) } @@ -1296,39 +1299,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 @@ -1557,20 +1527,19 @@ H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id) * The cache might be created with a different number of elements and * the access property list should be updated to reflect that. */ - if ( SUCCEED != H5AC_create(f, &(f->shared->mdc_initCacheCfg)) ) { - - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, \ - "unable to create meta data cache") - - } + if ( SUCCEED != H5AC_create(f, &(f->shared->mdc_initCacheCfg)) ) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create meta data cache") /* 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; @@ -1627,77 +1596,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() */ /*------------------------------------------------------------------------- @@ -1836,8 +1811,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 @@ -1847,24 +1821,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; @@ -2608,26 +2575,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: @@ -2642,134 +2641,81 @@ 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 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) { #ifdef H5_HAVE_FPHDF5 /* @@ -2803,12 +2749,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() */ /*------------------------------------------------------------------------- @@ -2835,14 +2781,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 @@ -2898,6 +2872,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") @@ -2906,7 +2883,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) } @@ -3292,15 +3269,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) @@ -4154,21 +4125,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 */ @@ -4179,3 +4162,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 c67f40d..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,100 +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: * * 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) - - /* 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 363c1e6..596103e 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -93,7 +93,7 @@ typedef struct H5F_file_t { haddr_t freespace_addr; /* Relative address of free-space info */ haddr_t driver_addr; /* File driver information block address*/ hbool_t fam_to_sec2; /* Is h5repart changing driver from family to sec2 */ - + unsigned super_chksum; /* Superblock checksum */ unsigned drvr_chksum; /* Driver info block checksum */ H5AC_t *cache; /* The object cache */ @@ -144,13 +144,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 */ }; @@ -165,14 +164,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 hsize_t H5F_init_superblock(const H5F_t *f, hid_t dxpl_id); diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index 8466bf2..52b92dc 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -438,8 +438,8 @@ H5_DLL hid_t H5F_get_access_plist(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 diff --git a/src/H5G.c b/src/H5G.c index ec17d28..c2305c5 100644 --- a/src/H5G.c +++ b/src/H5G.c @@ -2091,7 +2091,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))) @@ -2101,7 +2102,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++; } @@ -2254,11 +2258,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) { @@ -2271,7 +2278,7 @@ H5G_close(H5G_t *grp) done: FUNC_LEAVE_NOAPI(ret_value); -} +} /* end H5G_close() */ /*------------------------------------------------------------------------- @@ -2547,6 +2554,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; @@ -4121,8 +4131,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 e190ba0..36a18f9 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 34d6797..08ec9af 100644 --- a/src/H5Gprivate.h +++ b/src/H5Gprivate.h @@ -167,6 +167,8 @@ H5_DLL herr_t H5G_replace_name(H5G_obj_t 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. diff --git a/src/H5I.c b/src/H5I.c index 98b3c86..6ae8ca8 100644 --- a/src/H5I.c +++ b/src/H5I.c @@ -125,7 +125,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 type); #endif /* H5I_DEBUG_OUTPUT */ @@ -483,9 +482,6 @@ int H5I_nmembers(H5I_type_t type) { H5I_id_type_t *type_ptr = NULL; - H5I_id_info_t *cur=NULL; - int n=0; - unsigned i; int ret_value; FUNC_ENTER_NOAPI(H5I_nmembers, FAIL); @@ -495,12 +491,8 @@ H5I_nmembers(H5I_type_t type) if (NULL==(type_ptr=H5I_id_type_list_g[type]) || type_ptr->count<=0) HGOTO_DONE(0); - for (i=0; ihash_size; i++) - for (cur=type_ptr->id_list[i]; cur; cur=cur->next) - n++; - /* Set return value */ - ret_value=n; + H5_ASSIGN_OVERFLOW(ret_value, type_ptr->ids, unsigned, int); done: FUNC_LEAVE_NOAPI(ret_value); @@ -971,18 +963,14 @@ void *H5Iobject_verify(hid_t id, H5I_type_t id_type) FUNC_ENTER_API(H5Iobject_verify, NULL); if( H5I_IS_LIB_TYPE( id_type ) ) - { - HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "cannot call public function on library type"); - } + HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "cannot call public function on library type") if(id_type < 1 || id_type >= H5I_next_type) - { - HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "identifier has invalid type"); - } + HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "identifier has invalid type") ret_value = H5I_object_verify(id, id_type); - done: +done: FUNC_LEAVE_API(ret_value); } @@ -1127,9 +1115,7 @@ void *H5Iremove_verify(hid_t id, H5I_type_t id_type) FUNC_ENTER_API(H5Iremove_verify, NULL); if( H5I_IS_LIB_TYPE( id_type ) ) - { - HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "cannot call public function on library type"); - } + HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "cannot call public function on library type") /* Remove the id */ ret_value = H5I_remove_verify(id, id_type); @@ -1516,7 +1502,7 @@ done: * *------------------------------------------------------------------------- */ -static int +int H5I_get_ref(hid_t id) { H5I_type_t type; /*type the object is in*/ @@ -1906,20 +1892,23 @@ H5I_search(H5I_type_t type, H5I_search_func_t func, void *key) if (type_ptr == NULL || type_ptr->count <= 0) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "invalid type"); - /* Start at the beginning of the array */ - for (i=0; ihash_size; i++) { - id_ptr = type_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(type_ptr->ids > 0) { + /* Start at the beginning of the array */ + for (i=0; ihash_size; i++) { + id_ptr = type_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 667af3d1..c91240a 100644 --- a/src/H5Iprivate.h +++ b/src/H5Iprivate.h @@ -60,6 +60,7 @@ H5_DLL H5I_type_t H5I_get_type(hid_t id); H5_DLL void *H5I_remove(hid_t id); H5_DLL void *H5I_remove_verify(hid_t id, H5I_type_t id_type); H5_DLL void *H5I_search(H5I_type_t type, 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); H5_DLL int H5I_inc_type_ref(H5I_type_t type); diff --git a/src/H5Ipublic.h b/src/H5Ipublic.h index 78915a6..bda034c 100644 --- a/src/H5Ipublic.h +++ b/src/H5Ipublic.h @@ -36,7 +36,6 @@ typedef enum H5I_type_t { H5I_UNINIT = (-2), /*uninitialized type */ H5I_BADID = (-1), /*invalid Type */ H5I_FILE = 1, /*type ID for File objects */ - H5I_FILE_CLOSING, /*files pending close due to open objhdrs */ H5I_GROUP, /*type ID for Group objects */ H5I_DATATYPE, /*type ID for Datatype objects */ H5I_DATASPACE, /*type ID for Dataspace objects */ diff --git a/src/H5O.c b/src/H5O.c index 7abc16e..a15d9ac 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -412,7 +412,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)); @@ -423,28 +423,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 */ @@ -452,7 +437,7 @@ H5O_close(H5G_entry_t *obj_ent) done: FUNC_LEAVE_NOAPI(ret_value); -} +} /* end H5O_close() */ /*------------------------------------------------------------------------- @@ -1920,7 +1905,7 @@ H5O_modify_real(H5G_entry_t *ent, const H5O_class_t *type, int overwrite, HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "message not found"); } /* end if */ - /* Check for creating new message */ + /* Check for creating new message */ if (overwrite < 0) { /* Create a new message */ if((idx=H5O_new_mesg(ent->file,oh,&flags,type,mesg,&sh_mesg,&type,&mesg,dxpl_id,&oh_flags))==UFAIL) @@ -2265,7 +2250,6 @@ H5O_write_mesg(H5O_t *oh, unsigned idx, const H5O_class_t *type, unsigned * oh_flags_ptr) { H5O_mesg_t *idx_msg; /* Pointer to message to modify */ - herr_t ret_value=SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_write_mesg); diff --git a/test/Makefile.am b/test/Makefile.am index eb53695..6247d1a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -34,7 +34,7 @@ TEST_PROG=testhdf5 lheap ohdr stab gheap cache b+tree btree2 blocktrack sheap \ dtypes dsets cmpd_dset extend external links unlink big mtime \ fillval mount flush1 flush2 enum \ set_extent ttsafe stream_test \ - getname vfd ntypes dangle dtransform filename reserved + getname vfd ntypes dangle dtransform reserved # List programs to be built when testing here. error_test and err_compat are # built at the same time as the other tests, but executed by testerror.sh. diff --git a/test/Makefile.in b/test/Makefile.in index 54ec422..ce95a9b 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -29,7 +29,7 @@ # # HDF5 Library Test Makefile(.in) # -SOURCES = $(libh5test_la_SOURCES) b+tree.c big.c bittests.c blocktrack.c btree2.c cache.c cmpd_dset.c dangle.c dsets.c dt_arith.c dtransform.c dtypes.c enum.c err_compat.c error_test.c extend.c external.c filename.c fillval.c flush1.c flush2.c getname.c gheap.c hyperslab.c istore.c lheap.c links.c mount.c mtime.c ntypes.c ohdr.c pool.c reserved.c set_extent.c sheap.c stab.c stream_test.c $(testhdf5_SOURCES) testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c +SOURCES = $(libh5test_la_SOURCES) b+tree.c big.c bittests.c blocktrack.c btree2.c cache.c cmpd_dset.c dangle.c dsets.c dt_arith.c dtransform.c dtypes.c enum.c err_compat.c error_test.c extend.c external.c fillval.c flush1.c flush2.c getname.c gheap.c hyperslab.c istore.c lheap.c links.c mount.c mtime.c ntypes.c ohdr.c pool.c reserved.c set_extent.c sheap.c stab.c stream_test.c $(testhdf5_SOURCES) testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c srcdir = @srcdir@ top_srcdir = @top_srcdir@ @@ -81,7 +81,7 @@ am__EXEEXT_1 = testhdf5$(EXEEXT) lheap$(EXEEXT) ohdr$(EXEEXT) \ flush2$(EXEEXT) enum$(EXEEXT) set_extent$(EXEEXT) \ ttsafe$(EXEEXT) stream_test$(EXEEXT) getname$(EXEEXT) \ vfd$(EXEEXT) ntypes$(EXEEXT) dangle$(EXEEXT) \ - dtransform$(EXEEXT) filename$(EXEEXT) reserved$(EXEEXT) + dtransform$(EXEEXT) reserved$(EXEEXT) b_tree_SOURCES = b+tree.c b_tree_OBJECTS = b+tree.$(OBJEXT) b_tree_LDADD = $(LDADD) @@ -150,10 +150,6 @@ external_SOURCES = external.c external_OBJECTS = external.$(OBJEXT) external_LDADD = $(LDADD) external_DEPENDENCIES = libh5test.la $(am__DEPENDENCIES_1) -filename_SOURCES = filename.c -filename_OBJECTS = filename.$(OBJEXT) -filename_LDADD = $(LDADD) -filename_DEPENDENCIES = libh5test.la $(am__DEPENDENCIES_1) fillval_SOURCES = fillval.c fillval_OBJECTS = fillval.$(OBJEXT) fillval_LDADD = $(LDADD) @@ -273,19 +269,19 @@ LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ SOURCES = $(libh5test_la_SOURCES) b+tree.c big.c bittests.c \ blocktrack.c btree2.c cache.c cmpd_dset.c dangle.c dsets.c \ dt_arith.c dtransform.c dtypes.c enum.c err_compat.c \ - error_test.c extend.c external.c filename.c fillval.c flush1.c \ - flush2.c getname.c gheap.c hyperslab.c istore.c lheap.c \ - links.c mount.c mtime.c ntypes.c ohdr.c pool.c reserved.c \ - set_extent.c sheap.c stab.c stream_test.c $(testhdf5_SOURCES) \ - testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c + error_test.c extend.c external.c fillval.c flush1.c flush2.c \ + getname.c gheap.c hyperslab.c istore.c lheap.c links.c mount.c \ + mtime.c ntypes.c ohdr.c pool.c reserved.c set_extent.c sheap.c \ + stab.c stream_test.c $(testhdf5_SOURCES) testmeta.c \ + $(ttsafe_SOURCES) unlink.c vfd.c DIST_SOURCES = $(libh5test_la_SOURCES) b+tree.c big.c bittests.c \ blocktrack.c btree2.c cache.c cmpd_dset.c dangle.c dsets.c \ dt_arith.c dtransform.c dtypes.c enum.c err_compat.c \ - error_test.c extend.c external.c filename.c fillval.c flush1.c \ - flush2.c getname.c gheap.c hyperslab.c istore.c lheap.c \ - links.c mount.c mtime.c ntypes.c ohdr.c pool.c reserved.c \ - set_extent.c sheap.c stab.c stream_test.c $(testhdf5_SOURCES) \ - testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c + error_test.c extend.c external.c fillval.c flush1.c flush2.c \ + getname.c gheap.c hyperslab.c istore.c lheap.c links.c mount.c \ + mtime.c ntypes.c ohdr.c pool.c reserved.c set_extent.c sheap.c \ + stab.c stream_test.c $(testhdf5_SOURCES) testmeta.c \ + $(ttsafe_SOURCES) unlink.c vfd.c ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -532,7 +528,7 @@ TEST_PROG = testhdf5 lheap ohdr stab gheap cache b+tree btree2 blocktrack sheap dtypes dsets cmpd_dset extend external links unlink big mtime \ fillval mount flush1 flush2 enum \ set_extent ttsafe stream_test \ - getname vfd ntypes dangle dtransform filename reserved + getname vfd ntypes dangle dtransform reserved # The libh5test.a library provides common support code for the tests. @@ -677,9 +673,6 @@ extend$(EXEEXT): $(extend_OBJECTS) $(extend_DEPENDENCIES) external$(EXEEXT): $(external_OBJECTS) $(external_DEPENDENCIES) @rm -f external$(EXEEXT) $(LINK) $(external_LDFLAGS) $(external_OBJECTS) $(external_LDADD) $(LIBS) -filename$(EXEEXT): $(filename_OBJECTS) $(filename_DEPENDENCIES) - @rm -f filename$(EXEEXT) - $(LINK) $(filename_LDFLAGS) $(filename_OBJECTS) $(filename_LDADD) $(LIBS) fillval$(EXEEXT): $(fillval_OBJECTS) $(fillval_DEPENDENCIES) @rm -f fillval$(EXEEXT) $(LINK) $(fillval_LDFLAGS) $(fillval_OBJECTS) $(fillval_LDADD) $(LIBS) @@ -776,7 +769,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extend.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/external.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filename.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fillval.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flush1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flush2.Po@am__quote@ diff --git a/test/filename.c b/test/filename.c deleted file mode 100644 index b11e6c7..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 - * 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_stack(H5E_DEFAULT, 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 dd798a6..4813fa0 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; @@ -972,7 +978,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); @@ -985,21 +990,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) @@ -1013,6 +1018,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; @@ -1657,10 +1666,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; @@ -1795,10 +1800,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; @@ -1835,7 +1836,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 */ @@ -1916,21 +1917,42 @@ 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 - /* Close file #1 */ - /* (should unmount file #2 also) */ - if(H5Fclose(fid1) < 0) + /* Attempt to open group in mounted file */ + /* (Should work because file is still mounted) */ + if((gidAM2 = H5Gopen(fid2, "/A/M")) < 0) TEST_ERROR - /* Check that all file IDs have been closed */ - if(H5I_nmembers(H5I_FILE) != 0) + /* 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 - /* Check that all "file closing" IDs have been closed */ - if(H5I_nmembers(H5I_FILE_CLOSING) != 0) + /* 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(); @@ -1942,6 +1964,7 @@ error: H5Gclose(gidAM); H5Gclose(gidAM2); H5Gclose(gidA); + H5Gclose(gid); H5Fclose(fid2); H5Fclose(fid1); } H5E_END_TRY; @@ -1950,6 +1973,630 @@ error: /*------------------------------------------------------------------------- + * 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 */ + 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 + + 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(); + 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_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() */ + + +/*------------------------------------------------------------------------- * Function: main * * Purpose: Test file mounting @@ -1993,6 +2640,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 7043950..2274b78 100644 --- a/test/testhdf5.h +++ b/test/testhdf5.h @@ -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_stack(H5E_DEFAULT, 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 0e1e7ec..05a0765 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 @@ -1447,64 +1456,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. ** ****************************************************************/ @@ -1525,6 +1651,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() */ -- cgit v0.12