diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2005-07-21 14:49:11 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2005-07-21 14:49:11 (GMT) |
commit | 1e2ddfc8b1847c4b1f67c764d4920c5d1e0c538d (patch) | |
tree | 60e8d8ee4b4fa77ef7a01ebf106d53b9d7675a32 /src/H5F.c | |
parent | c9b45e24d5f1935d5356cf90f0521d1e82efc4e3 (diff) | |
download | hdf5-1e2ddfc8b1847c4b1f67c764d4920c5d1e0c538d.zip hdf5-1e2ddfc8b1847c4b1f67c764d4920c5d1e0c538d.tar.gz hdf5-1e2ddfc8b1847c4b1f67c764d4920c5d1e0c538d.tar.bz2 |
[svn-r11094] Purpose:
Bug fix
Description:
Rewrite code for mounting files to clean up layers of kludges and implement
a much cleaner and more maintainable design.
Platforms tested:
FreeBSD 4.11 (sleipnir)
Linux 2.4
Diffstat (limited to 'src/H5F.c')
-rw-r--r-- | src/H5F.c | 714 |
1 files changed, 423 insertions, 291 deletions
@@ -61,6 +61,12 @@ typedef struct H5F_olist_t { int max_index; /* Maximum # of IDs to put into array */ } H5F_olist_t; +/* Struct for tracking "shared" file structs */ +typedef struct H5F_sfile_node_t { + H5F_file_t *shared; /* Pointer to "shared" struct */ + struct H5F_sfile_node_t *next; /* Pointer to next node */ +} H5F_sfile_node_t; + /* PRIVATE PROTOTYPES */ static H5F_t *H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t dxpl_id); @@ -70,19 +76,31 @@ static herr_t H5F_flush_all(hbool_t invalidate); static int H5F_flush_all_cb(void *f, hid_t fid, void *_invalidate); #endif /* NOT_YET */ +static herr_t H5F_close(H5F_t *f); static H5F_t *H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id); static herr_t H5F_dest(H5F_t *f, hid_t dxpl_id); static herr_t H5F_flush(H5F_t *f, hid_t dxpl_id, H5F_scope_t scope, unsigned flags); -static int H5F_get_objects(const H5F_t *f, unsigned types, int max_objs, hid_t *obj_id_list); +static unsigned H5F_get_objects(const H5F_t *f, unsigned types, int max_objs, hid_t *obj_id_list); static int H5F_get_objects_cb(void *obj_ptr, hid_t obj_id, void *key); static herr_t H5F_get_vfd_handle(const H5F_t *file, hid_t fapl, void** file_handle); +/* Routines to operate on the shared file list */ +static herr_t H5F_shared_add(H5F_file_t *shared); +static H5F_file_t * H5F_shared_search(H5FD_t *lf); +static herr_t H5F_shared_remove(H5F_file_t *shared); + /* Declare a free list to manage the H5F_t struct */ H5FL_DEFINE_STATIC(H5F_t); /* Declare a free list to manage the H5F_file_t struct */ H5FL_DEFINE_STATIC(H5F_file_t); +/* Declare a free list to manage the H5F_sfile_node_t struct */ +H5FL_DEFINE_STATIC(H5F_sfile_node_t); + +/* Declare a local variable to track the shared file information */ +H5F_sfile_node_t *H5F_sfile_head_g = NULL; + /*------------------------------------------------------------------------- * Function: H5F_init @@ -222,8 +240,7 @@ H5F_init_interface(void) * which are pending completion because there are object headers still * open within the file. */ - if (H5I_init_group(H5I_FILE, (size_t)H5I_FILEID_HASHSIZE, 0, (H5I_free_t)H5F_close)<0 || - H5I_init_group(H5I_FILE_CLOSING, (size_t)H5I_FILEID_HASHSIZE, 0, (H5I_free_t)H5F_close)<0) + if (H5I_init_group(H5I_FILE, (size_t)H5I_FILEID_HASHSIZE, 0, (H5I_free_t)H5F_close)<0) HGOTO_ERROR (H5E_FILE, H5E_CANTINIT, FAIL, "unable to initialize interface") /* ========== File Creation Property Class Initialization ============*/ @@ -424,13 +441,11 @@ H5F_term_interface(void) if (H5_interface_initialize_g) { if ((n=H5I_nmembers(H5I_FILE))!=0) { H5I_clear_group(H5I_FILE, FALSE); - } else if ((n=H5I_nmembers(H5I_FILE_CLOSING))!=0) { - /* Attempt to unmount any child files from files that are closing */ - (void)H5I_search(H5I_FILE_CLOSING, H5F_term_unmount_cb, NULL); - } - else { + } else { + /* Make certain we've cleaned up all the shared file objects */ + HDassert(H5F_sfile_head_g == NULL); + H5I_destroy_group(H5I_FILE); - H5I_destroy_group(H5I_FILE_CLOSING); H5_interface_initialize_g = 0; n = 1; /*H5I*/ } @@ -899,17 +914,15 @@ done: * *------------------------------------------------------------------------- */ -int +unsigned H5F_get_obj_count(const H5F_t *f, unsigned types) { - int ret_value; /* Return value */ + unsigned ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5F_get_obj_count) + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_obj_count) - if((ret_value=H5F_get_objects(f, types, -1, NULL)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get counts of opened file IDs and object IDs in the file") + ret_value=H5F_get_objects(f, types, -1, NULL); -done: FUNC_LEAVE_NOAPI(ret_value) } @@ -951,7 +964,7 @@ done: /*------------------------------------------------------------------------- - * Function: H5F_get_object_ids + * Function: H5F_get_obj_ids * * Purpose: Private function to return a list of opened object IDs. * @@ -964,17 +977,15 @@ done: * *------------------------------------------------------------------------- */ -int +unsigned H5F_get_obj_ids(const H5F_t *f, unsigned types, int max_objs, hid_t *oid_list) { - int ret_value; /* Return value */ + unsigned ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5F_get_obj_ids) + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_obj_ids) - if((ret_value=H5F_get_objects(f, types, max_objs, oid_list)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get object IDs opened in the file") + ret_value = H5F_get_objects(f, types, max_objs, oid_list); -done: FUNC_LEAVE_NOAPI(ret_value) } @@ -994,12 +1005,12 @@ done: * *--------------------------------------------------------------------------- */ -static int +static unsigned H5F_get_objects(const H5F_t *f, unsigned types, int max_index, hid_t *obj_id_list) { unsigned obj_id_count=0; /* Number of open IDs */ H5F_olist_t olist; /* Structure to hold search results */ - int ret_value; /* Return value */ + unsigned ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_objects) @@ -1021,45 +1032,42 @@ H5F_get_objects(const H5F_t *f, unsigned types, int max_index, hid_t *obj_id_lis /* Search through file IDs to count the number, and put their * IDs on the object list */ - if( (types & H5F_OBJ_FILE) && H5I_nmembers(H5I_FILE) > 0 ) { + if(types & H5F_OBJ_FILE) { olist.obj_type = H5I_FILE; (void)H5I_search(H5I_FILE, H5F_get_objects_cb, &olist); - } + } /* end if */ /* Search through dataset IDs to count number of datasets, and put their * IDs on the object list */ - if( (max_index<0 || (int)olist.list_index< max_index) && (types & H5F_OBJ_DATASET) && H5I_nmembers(H5I_DATASET) > 0 ) { + if( (max_index < 0 || (int)olist.list_index < max_index) && (types & H5F_OBJ_DATASET) ) { olist.obj_type = H5I_DATASET; (void)H5I_search(H5I_DATASET, H5F_get_objects_cb, &olist); } /* Search through group IDs to count number of groups, and put their * IDs on the object list */ - if( (max_index<0 || (int)olist.list_index< max_index) && (types & H5F_OBJ_GROUP) && H5I_nmembers(H5I_GROUP) > 0 ) { + if( (max_index < 0 || (int)olist.list_index < max_index) && (types & H5F_OBJ_GROUP) ) { olist.obj_type = H5I_GROUP; (void)H5I_search(H5I_GROUP, H5F_get_objects_cb, &olist); } /* Search through datatype IDs to count number of named datatypes, and put their * IDs on the object list */ - if( (max_index<0 || (int)olist.list_index< max_index) && (types & H5F_OBJ_DATATYPE) && H5I_nmembers(H5I_DATATYPE) > 0 ) { + if( (max_index < 0 || (int)olist.list_index < max_index) && (types & H5F_OBJ_DATATYPE) ) { olist.obj_type = H5I_DATATYPE; (void)H5I_search(H5I_DATATYPE, H5F_get_objects_cb, &olist); } /* Search through attribute IDs to count number of attributes, and put their * IDs on the object list */ - if( (max_index<0 || (int)olist.list_index< max_index) && (types & H5F_OBJ_ATTR) && H5I_nmembers(H5I_ATTR) > 0 ) { + if( (max_index < 0 || (int)olist.list_index < max_index) && (types & H5F_OBJ_ATTR) ) { olist.obj_type = H5I_ATTR; (void)H5I_search(H5I_ATTR, H5F_get_objects_cb, &olist); } /* Set the number of objects currently open */ - H5_ASSIGN_OVERFLOW(ret_value,obj_id_count,unsigned,int); + ret_value = obj_id_count; -#ifdef LATER -done: -#endif /* LATER */ FUNC_LEAVE_NOAPI(ret_value) } @@ -1233,39 +1241,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5F_equal - * - * Purpose: Compares NEEDLE to a file from the HAYSTACK. - * - * Return: Success: Returns positive if two files are equal, - * zero otherwise. - * - * Failure: Negative - * - * Programmer: Robb Matzke - * Monday, August 2, 1999 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -/* ARGSUSED */ -static int -H5F_equal(void *_haystack, hid_t UNUSED id, void *_needle) -{ - H5F_t *haystack = (H5F_t*)_haystack; - const H5FD_t *needle = (const H5FD_t*)_needle; - int retval; - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_equal) - - retval = (0==H5FD_cmp(haystack->shared->lf, needle)); - - FUNC_LEAVE_NOAPI(retval) -} - - -/*------------------------------------------------------------------------- * Function: H5F_locate_signature * * Purpose: Finds the HDF5 super block signature in a file. The signature @@ -1415,7 +1390,6 @@ static H5F_t * H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id) { H5F_t *f=NULL, *ret_value; - int n; H5P_genplist_t *plist; /* Property list */ FUNC_ENTER_NOAPI_NOINIT(H5F_new) @@ -1426,6 +1400,8 @@ H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id) if (shared) { f->shared = shared; } else { + int n; + f->shared = H5FL_CALLOC(H5F_file_t); f->shared->super_addr = HADDR_UNDEF; f->shared->base_addr = HADDR_UNDEF; @@ -1498,11 +1474,14 @@ H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id) /* Create the file's "open object" information */ if(H5FO_create(f)<0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create open object TBBT") + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create open object data structure") + + /* Add new "shared" struct to list of open files */ + if(H5F_shared_add(f->shared) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to append to list of open files") } /* end else */ f->shared->nrefs++; - f->nrefs = 1; /* Set return value */ ret_value = f; @@ -1559,77 +1538,83 @@ H5F_dest(H5F_t *f, hid_t dxpl_id) FUNC_ENTER_NOAPI_NOINIT(H5F_dest) - if (f && 1==f->nrefs) { - if (1==f->shared->nrefs) { - /* - * Do not close the root group since we didn't count it, but free - * the memory associated with it. - */ - if (f->shared->root_grp) { - /* Free the ID to name buffer */ - if(H5G_free_grp_name(f->shared->root_grp)<0) { - HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); - ret_value = FAIL; /*but keep going*/ - } /* end if */ - - /* Free the memory for the root group */ - if(H5G_free(f->shared->root_grp)<0) { - HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); - ret_value = FAIL; /*but keep going*/ - } /* end if */ - f->shared->root_grp=NULL; - } - if (H5AC_dest(f, dxpl_id)) { - HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); - ret_value = FAIL; /*but keep going*/ - } - if (H5FO_dest(f)<0) { + /* Sanity check */ + HDassert(f); + + if (1==f->shared->nrefs) { + /* Remove shared file struct from list of open files */ + if(H5F_shared_remove(f->shared) < 0) { + HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); + ret_value = FAIL; /*but keep going*/ + } /* end if */ + + /* + * Do not close the root group since we didn't count it, but free + * the memory associated with it. + */ + if (f->shared->root_grp) { + /* Free the ID to name buffer */ + if(H5G_free_grp_name(f->shared->root_grp)<0) { HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); ret_value = FAIL; /*but keep going*/ - } /* end if */ - f->shared->cwfs = H5MM_xfree (f->shared->cwfs); - if (H5G_node_close(f)<0) { + } /* end if */ + + /* Free the memory for the root group */ + if(H5G_free(f->shared->root_grp)<0) { HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); ret_value = FAIL; /*but keep going*/ - } /* end if */ - - /* Destroy file creation properties */ - if(H5I_GENPROP_LST != H5I_get_type(f->shared->fcpl_id)) - HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a property list") - if((ret_value=H5I_dec_ref(f->shared->fcpl_id)) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "can't close property list") - - /* Destroy shared file struct */ - if (H5FD_close(f->shared->lf)<0) { - HERROR(H5E_FILE, H5E_CANTINIT, "problems closing file"); - ret_value = FAIL; /*but keep going*/ - } - f->shared = H5FL_FREE(H5F_file_t,f->shared); - - } else if (f->shared->nrefs>0) { - /* - * There are other references to the shared part of the file. - * Only decrement the reference count. - */ - --f->shared->nrefs; - } + } /* end if */ + f->shared->root_grp=NULL; + } + if (H5AC_dest(f, dxpl_id)) { + HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); + ret_value = FAIL; /*but keep going*/ + } + if (H5FO_dest(f)<0) { + HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); + ret_value = FAIL; /*but keep going*/ + } /* end if */ + f->shared->cwfs = H5MM_xfree (f->shared->cwfs); + if (H5G_node_close(f)<0) { + HERROR(H5E_FILE, H5E_CANTRELEASE, "problems closing file"); + ret_value = FAIL; /*but keep going*/ + } /* end if */ - /* Free the non-shared part of the file */ - f->name = H5MM_xfree(f->name); - f->mtab.child = H5MM_xfree(f->mtab.child); - f->mtab.nalloc = 0; - H5FL_FREE(H5F_t,f); - } else if (f && f->nrefs>0) { - /* - * There are other references to this file. Only decrement the - * reference count. - */ - --f->nrefs; + /* Destroy file creation properties */ + if(H5I_GENPROP_LST != H5I_get_type(f->shared->fcpl_id)) { + HERROR(H5E_PLIST, H5E_BADTYPE, "not a property list"); + ret_value = FAIL; /*but keep going*/ + } /* end if */ + if((ret_value=H5I_dec_ref(f->shared->fcpl_id)) < 0) { + HERROR(H5E_PLIST, H5E_CANTFREE, "can't close property list"); + ret_value = FAIL; /*but keep going*/ + } /* end if */ + + /* Close low-level file */ + if (H5FD_close(f->shared->lf)<0) { + HERROR(H5E_FILE, H5E_CANTINIT, "problems closing file"); + ret_value = FAIL; /*but keep going*/ + } + + /* Destroy shared file struct */ + f->shared = H5FL_FREE(H5F_file_t,f->shared); + + } else if (f->shared->nrefs>0) { + /* + * There are other references to the shared part of the file. + * Only decrement the reference count. + */ + --f->shared->nrefs; } -done: + /* Free the non-shared part of the file */ + f->name = H5MM_xfree(f->name); + f->mtab.child = H5MM_xfree(f->mtab.child); + f->mtab.nalloc = 0; + H5FL_FREE(H5F_t,f); + FUNC_LEAVE_NOAPI(ret_value) -} +} /* end H5F_dest() */ /*------------------------------------------------------------------------- @@ -1767,8 +1752,7 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t d } /* end if */ /* Is the file already open? */ - if ((file=H5I_search(H5I_FILE, H5F_equal, lf))!=NULL || - (file=H5I_search(H5I_FILE_CLOSING, H5F_equal, lf))!=NULL) { + if ((shared = H5F_shared_search(lf)) != NULL) { /* * The file is already open, so use that one instead of the one we * just opened. We only one one H5FD_t* per file so one doesn't @@ -1778,24 +1762,17 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t d * exists), or if the new request adds write access (since the * readers don't expect the file to change under them). */ - if(H5FD_close(lf)<0) { - file = NULL; /*to prevent destruction of wrong file*/ + if(H5FD_close(lf)<0) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to close low-level file info") - } /* end if */ - if (flags & H5F_ACC_TRUNC) { - file = NULL; /*to prevent destruction of wrong file*/ + if (flags & H5F_ACC_TRUNC) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to truncate a file which is already open") - } - if (flags & H5F_ACC_EXCL) { - file = NULL; /*to prevent destruction of wrong file*/ + if (flags & H5F_ACC_EXCL) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file exists") - } - if ((flags & H5F_ACC_RDWR) && 0==(file->intent & H5F_ACC_RDWR)) { - file = NULL; /*to prevent destruction of wrong file*/ + if ((flags & H5F_ACC_RDWR) && 0 == (shared->flags & H5F_ACC_RDWR)) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "file is already open for read-only") - } - if ((file = H5F_new(file->shared, fcpl_id, fapl_id)) == NULL) + /* Allocate new "high-level" file struct */ + if ((file = H5F_new(shared, fcpl_id, fapl_id)) == NULL) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to create new file object") lf = file->shared->lf; @@ -2384,26 +2361,58 @@ H5F_close(H5F_t *f) FUNC_ENTER_NOAPI_NOINIT(H5F_close) - assert(f->nrefs>0); + /* Sanity check */ + HDassert(f); + HDassert(f->file_id > 0); /* This routine should only be called when a file ID's ref count drops to zero */ - /* - * If this file is referenced more than once then just decrement the - * count and return. - */ - if (f->nrefs>1) { - /* Decrement reference counts */ - if (H5F_dest(f, H5AC_dxpl_id)<0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file") - HGOTO_DONE(SUCCEED) - } /* end if */ + /* Reset the file ID for this file */ + f->file_id = -1; - /* Double-check that this file should be closed */ - assert(1==f->nrefs); - - /* if close degree if "semi" and there are objects left open and we are - * holding open the file with this file ID, fail now */ - if(f->shared->fc_degree==H5F_CLOSE_SEMI && f->nopen_objs>0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file, there are objects still open") + /* Attempt to close the file/mount hierarchy */ + if(H5F_try_close(f) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F_close() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_try_close + * + * Purpose: Attempts to close a file due to one of several actions: + * - The reference count on the file ID dropped to zero + * - The last open object was closed in the file + * - The file was unmounted + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, July 19, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_try_close(H5F_t *f) +{ + unsigned nopen_files = 0; /* Number of open files in file/mount hierarchy */ + unsigned nopen_objs = 0; /* Number of open objects in file/mount hierarchy */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5F_try_close) + + /* Sanity check */ + HDassert(f); + + /* Check if this file is already in the process of closing */ + if(f->closing) + HGOTO_DONE(SUCCEED) + + /* Get the number of open objects and open files on this file/mount hierarchy */ + if(H5F_mount_count_ids(f, &nopen_files, &nopen_objs) < 0) + HGOTO_ERROR(H5E_SYM, H5E_MOUNT, FAIL, "problem checking mount hierarchy") /* * Close file according to close degree: @@ -2418,138 +2427,84 @@ H5F_close(H5F_t *f) switch(f->shared->fc_degree) { case H5F_CLOSE_WEAK: /* - * If object headers are still open then delay deletion of + * If file or object IDS are still open then delay deletion of * resources until they have all been closed. Flush all - * caches and update the object eader anyway so that failing toi - * close all objects isn't a major problem. If the file is on - * the H5I_FILE list then move it to the H5I_FILE_CLOSING list - * instead. + * caches and update the object header anyway so that failing to + * close all objects isn't a major problem. */ - if (f->nopen_objs>0) { -#ifdef H5F_DEBUG - if (H5DEBUG(F)) { - fprintf(H5DEBUG(F), "H5F: H5F_close(%s): %u object header%s still " - "open (file close will complete when %s closed)\n", - f->name, - f->nopen_objs, - 1 == f->nopen_objs?" is":"s are", - 1 == f->nopen_objs?"that header is":"those headers are"); - } -#endif - /* If the only open objects are the groups that are mount points, */ - /* allow the file to close and shut things down */ - if(f->nopen_objs == f->mtab.nmounts) { - unsigned u; /* Local index variable */ - hbool_t really_close; /* Whether to delay the file close by going to a "closing" state */ - - /* Check for open groups on mount points */ - really_close = TRUE; - for(u = 0; u < f->mtab.nmounts; u++) { - if(H5G_get_shared_count(f->mtab.child[u].group) > 1) { - really_close = FALSE; - break; - } /* end if */ - } /* end for */ - - /* If we really want to close this file now */ - if(really_close) - break; - } /* end if */ - - /* Register an ID for closing the file later */ - if (!f->closing) - f->closing = H5I_register(H5I_FILE_CLOSING, f); - - /* Invalidate file ID */ - f->file_id = -1; - + if ((nopen_files + nopen_objs) > 0) HGOTO_DONE(SUCCEED) - } else { - if (f->closing) { - -#ifdef H5F_DEBUG - if (H5DEBUG(F)) - fprintf(H5DEBUG(F), "H5F: H5F_close: operation completing\n"); -#endif - } /* end if */ - } /* end else */ break; case H5F_CLOSE_SEMI: + /* Can leave safely if file IDs are still open on this file */ + if (nopen_files > 0) + HGOTO_DONE(SUCCEED) + + /* Sanity check: If close degree if "semi" and we have gotten this + * far and there are objects left open, bail out now */ + HDassert(nopen_files == 0 && nopen_objs == 0); + /* If we've gotten this far (ie. there are no open objects in the file), fall through to flush & close */ break; case H5F_CLOSE_STRONG: - /* Force to close all opened objects in file */ - while(f->nopen_objs > 0) { - int obj_count; /* # of open objects */ - hid_t objs[128]; /* Array of objects to close */ - int i; /* Local index variable */ - - /* Get the list of IDs of open dataset objects */ - while((obj_count=H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_DATASET, (int)(sizeof(objs)/sizeof(objs[0])), objs))!=0) { - - /* Try to close all the open objects */ - for(i=0; i<obj_count; i++) - if(H5I_dec_ref(objs[i]) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") - } /* end while */ - - /* Get the list of IDs of open group objects */ - while((obj_count=H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_GROUP, (int)(sizeof(objs)/sizeof(objs[0])), objs))!=0) { - - /* Try to close all the open objects */ - for(i=0; i<obj_count; i++) - if(H5I_dec_ref(objs[i]) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") - } /* end while */ - - /* Get the list of IDs of open named datatype objects */ - while((obj_count=H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_DATATYPE, (int)(sizeof(objs)/sizeof(objs[0])), objs))!=0) { - - /* Try to close all the open objects */ - for(i=0; i<obj_count; i++) - if(H5I_dec_ref(objs[i]) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") - } /* end while */ - - /* Get the list of IDs of open attribute objects */ - while((obj_count=H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_ATTR, (int)(sizeof(objs)/sizeof(objs[0])), objs))!=0) { - - /* Try to close all the open objects */ - for(i=0; i<obj_count; i++) - if(H5I_dec_ref(objs[i]) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") - } /* end while */ - } /* end while */ + /* If there are other open files in the hierarchy, we can leave now */ + if(nopen_files > 0) + HGOTO_DONE(SUCCEED) + + /* If we've gotten this far (ie. there are no open file IDs in the file/mount hierarchy), fall through to flush & close */ break; default: HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file, unknown file close degree") } /* end switch */ - /* - * Unmount and close each child before closing the current file. - */ - assert(NULL==f->mtab.parent); - if(H5F_close_mounts(f) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't unmount child file") + /* Mark this file as closing (prevents re-entering file shutdown code below) */ + f->closing = TRUE; - /* Invalidate file ID */ - f->file_id = -1; + /* If the file close degree is "strong", close all the open objects in this file */ + if(f->shared->fc_degree == H5F_CLOSE_STRONG) { + HDassert(nopen_files == 0); - /* Flush at this point since the file will be closed */ + /* Forced close of all opened objects in this file */ + if(f->nopen_objs > 0) { + unsigned obj_count; /* # of open objects */ + hid_t objs[128]; /* Array of objects to close */ + unsigned u; /* Local index variable */ + + /* Get the list of IDs of open dataset, group, named datatype & attribute objects */ + while((obj_count = H5F_get_obj_ids(f, H5F_OBJ_LOCAL|H5F_OBJ_DATASET|H5F_OBJ_GROUP|H5F_OBJ_DATATYPE|H5F_OBJ_ATTR, (int)(sizeof(objs)/sizeof(objs[0])), objs)) != 0) { + + /* Try to close all the open objects in this file */ + for(u = 0; u < obj_count; u++) + if(H5I_dec_ref(objs[u]) < 0) + HGOTO_ERROR(H5E_ATOM, H5E_CLOSEERROR, FAIL, "can't close object") + } /* end while */ + } /* end if */ + } /* end if */ + + /* Check if this is a child file in a mounting hierarchy & proceed up the + * hierarchy if so. + */ + if(f->mtab.parent) + if(H5F_try_close(f->mtab.parent) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close parent file") + + /* Unmount and close each child before closing the current file. */ + if(H5F_close_mounts(f) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't unmount child files") - /* Dump debugging info */ #if H5AC_DUMP_STATS_ON_CLOSE + /* Dump debugging info */ H5AC_stats(f); #endif /* H5AC_DUMP_STATS_ON_CLOSE */ - /* Only try to flush the file if it was opened with write access */ + /* Flush at this point since the file will be closed */ + /* (Only try to flush the file if it was opened with write access) */ if(f->intent&H5F_ACC_RDWR) { /* Flush and destroy all caches */ - if (H5F_flush(f, H5AC_dxpl_id, H5F_SCOPE_LOCAL, - H5F_FLUSH_INVALIDATE | H5F_FLUSH_CLOSING) < 0) + if (H5F_flush(f, H5AC_dxpl_id, H5F_SCOPE_LOCAL, H5F_FLUSH_INVALIDATE | H5F_FLUSH_CLOSING) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache") } /* end if */ @@ -2558,12 +2513,12 @@ H5F_close(H5F_t *f) * shared H5F_file_t struct. If the reference count for the H5F_file_t * struct reaches zero then destroy it also. */ - if (H5F_dest(f,H5AC_dxpl_id)<0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file") + if (H5F_dest(f, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5F_close() */ +} /* end H5F_try_close() */ /*------------------------------------------------------------------------- @@ -2590,14 +2545,42 @@ done: herr_t H5Fclose(hid_t file_id) { + H5F_t *f; herr_t ret_value = SUCCEED; FUNC_ENTER_API(H5Fclose, FAIL) H5TRACE1("e","i",file_id); /* Check/fix arguments. */ - if (NULL==H5I_object_verify(file_id,H5I_FILE)) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file atom") + if (NULL == (f = H5I_object_verify(file_id,H5I_FILE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file ID") + + /* Perform checks for "semi" file close degree here, since closing the + * file ID will mess things up if we need to return FAIL */ + if(f->shared->fc_degree == H5F_CLOSE_SEMI) { + int ref_count; /* Reference count for file's ID */ + + /* Get the reference count for this ID */ + if((ref_count = H5I_get_ref(file_id)) < 0) + HGOTO_ERROR (H5E_ATOM, H5E_CANTGET, FAIL, "can't get ID ref count") + + /* If we will be decrementing the reference count to zero, check for objects open */ + if(ref_count == 1) { + unsigned nopen_files = 0; /* Number of open files in file/mount hierarchy */ + unsigned nopen_objs = 0; /* Number of open objects in file/mount hierarchy */ + + /* Get the number of open objects and open files on this file/mount hierarchy */ + if(H5F_mount_count_ids(f, &nopen_files, &nopen_objs) < 0) + HGOTO_ERROR(H5E_SYM, H5E_MOUNT, FAIL, "problem checking mount hierarchy") + + /* If there are no other file IDs open on this file/mount hier., but + * there are still open objects, issue an error and bail out now, + * before decrementing the file ID's reference count and triggering + * a "real" attempt at closing the file */ + if(nopen_files == 1 && nopen_objs > 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file, there are objects still open") + } /* end if */ + } /* end if */ /* * Decrement reference count on atom. When it reaches zero the file will @@ -2653,6 +2636,9 @@ H5Freopen(hid_t file_id) /* Keep old file's read/write intent in new file */ new_file->intent=old_file->intent; + /* Duplicate old file's name */ + new_file->name = H5MM_xstrdup(old_file->name); + if ((ret_value=H5I_register(H5I_FILE, new_file))<0) HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file handle") @@ -2661,7 +2647,7 @@ H5Freopen(hid_t file_id) done: if (ret_value<0 && new_file) - if(H5F_close(new_file)<0) + if(H5F_dest(new_file, H5AC_dxpl_id)<0) HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file") FUNC_LEAVE_API(ret_value) } @@ -3047,15 +3033,9 @@ H5F_get_id(H5F_t *file) assert(file); if(file->file_id == -1) { - if(H5I_remove(file->closing)==NULL) - HGOTO_ERROR(H5E_ATOM, H5E_READERROR, FAIL, "unable to remove from closing list") - /* Get an atom for the file */ if ((file->file_id = H5I_register(H5I_FILE, file))<0) HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to atomize file") - - /* Indicate file is not closing */ - file->closing = 0; } else { /* Increment reference count on atom. */ if (H5I_inc_ref(file->file_id)<0) @@ -3615,21 +3595,33 @@ done: ssize_t H5Fget_name(hid_t obj_id, char *name/*out*/, size_t size) { - H5G_entry_t *ent; /*symbol table entry */ + H5G_entry_t *ent; /*symbol table entry */ + H5F_t *f; /* Top file in mount hierarchy */ size_t len=0; ssize_t ret_value; FUNC_ENTER_API (H5Fget_name, FAIL) H5TRACE3("Zs","ixz",obj_id,name,size); - /* get symbol table entry */ - if((ent = H5G_loc(obj_id))==NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid object ID") + /* For file IDs, get the file object directly */ + /* (This prevents the H5G_loc() call from returning the file pointer for + * the top file in a mount hierarchy) + */ + if(H5I_get_type(obj_id) == H5I_FILE ) { + if (NULL==(f=H5I_object(obj_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") + } /* end if */ + else { + /* Get symbol table entry */ + if((ent = H5G_loc(obj_id))==NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid object ID") + f = ent->file; + } /* end else */ - len = HDstrlen(ent->file->name); + len = HDstrlen(f->name); if(name) { - HDstrncpy(name, ent->file->name, MIN(len+1,size)); + HDstrncpy(name, f->name, MIN(len+1,size)); if(len >= size) name[size-1]='\0'; } /* end if */ @@ -3640,3 +3632,143 @@ H5Fget_name(hid_t obj_id, char *name/*out*/, size_t size) done: FUNC_LEAVE_API(ret_value) } /* end H5Fget_name() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_shared_add + * + * Purpose: Add a "shared" file struct to the list of open files + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * Monday, July 18, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F_shared_add(H5F_file_t *shared) +{ + H5F_sfile_node_t *new; /* New shared file node */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5F_shared_add) + + /* Sanity check */ + HDassert(shared); + + /* Allocate new shared file node */ + if (NULL == (new = H5FL_CALLOC(H5F_sfile_node_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Set shared file value */ + new->shared = shared; + + /* Prepend to list of shared files open */ + new->next = H5F_sfile_head_g; + H5F_sfile_head_g = new; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F_shared_add() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_shared_search + * + * Purpose: Search for a "shared" file with low-level file info that + * matches + * + * Return: Non-NULL on success / NULL on failure + * + * Programmer: Quincey Koziol + * Monday, July 18, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static H5F_file_t * +H5F_shared_search(H5FD_t *lf) +{ + H5F_sfile_node_t *curr; /* Current shared file node */ + H5F_file_t *ret_value = NULL; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_shared_search) + + /* Sanity check */ + HDassert(lf); + + /* Iterate through low-level files for matching low-level file info */ + curr = H5F_sfile_head_g; + while(curr) { + /* Check for match */ + if(0==H5FD_cmp(curr->shared->lf, lf)) + HGOTO_DONE(curr->shared) + + /* Advance to next shared file node */ + curr = curr->next; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F_shared_search() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_shared_remove + * + * Purpose: Remove a "shared" file struct from the list of open files + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * Monday, July 18, 2005 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F_shared_remove(H5F_file_t *shared) +{ + H5F_sfile_node_t *curr; /* Current shared file node */ + H5F_sfile_node_t *last; /* Last shared file node */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5F_shared_remove) + + /* Sanity check */ + HDassert(shared); + + /* Locate shared file node with correct shared file */ + last = NULL; + curr = H5F_sfile_head_g; + while(curr && curr->shared != shared) { + /* Advance to next node */ + last = curr; + curr = curr->next; + } /* end while */ + + /* Indicate error if the node wasn't found */ + if(curr == NULL) + HGOTO_ERROR(H5E_FILE, H5E_NOTFOUND, FAIL, "can't find shared file info") + + /* Remove node found from list */ + if(last != NULL) + /* Removing middle or tail node in list */ + last->next = curr->next; + else + /* Removing head node in list */ + H5F_sfile_head_g = curr->next; + + /* Release the shared file node struct */ + /* (the shared file info itself is freed elsewhere) */ + H5FL_FREE(H5F_sfile_node_t, curr); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F_shared_remove() */ + |