Address issue with object headers being created getting evicted from
the metadata cache cache before they are completely initialized. This is
done by pinning the object header in the cache until it is completely
initialized and attached to a group.
Tested on:
FreeBSD/32 6.3 (duty) in debug mode
FreeBSD/64 6.3 (liberty) w/C++ & FORTRAN, in debug mode
Linux/32 2.6 (jam) w/PGI compilers, w/default API=1.8.x,
w/C++ & FORTRAN, w/threadsafe, in debug mode
Linux/64-amd64 2.6 (amani) w/Intel compilers, w/default API=1.6.x,
w/C++ & FORTRAN, in production mode
Solaris/32 2.10 (linew) w/deprecated symbols disabled, w/C++ & FORTRAN,
w/szip filter, w/threadsafe, in production mode
Linux/PPC 2.6 (heiwa) w/C++ & FORTRAN, w/threadsafe, in debug mode
Linux/64-ia64 2.6 (cobalt) w/Intel compilers, w/C++ & FORTRAN,
in production mode
Linux/64-amd64 2.6 (abe) w/parallel, w/FORTRAN, in debug mode
Mac OS X/32 10.6.4 (amazon) in debug mode
Mac OS X/32 10.6.4 (amazon) w/C++ & FORTRAN, w/threadsafe,
in production mode
Mac OS X/32 10.6.4 (amazon) w/parallel, in debug mode
280 lines
12 KiB
C
280 lines
12 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
* Copyright by The HDF Group. *
|
||
* 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://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
|
||
* access to either file, you may request a copy from help@hdfgroup.org. *
|
||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
||
/*-------------------------------------------------------------------------
|
||
*
|
||
* Created: H5Gobj.c
|
||
* Apr 8 2009
|
||
* Neil Fortner <nfortne2@hdfgroup.org>
|
||
*
|
||
* Purpose: Functions for operating on the root group.
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
|
||
/****************/
|
||
/* Module Setup */
|
||
/****************/
|
||
|
||
#define H5F_PACKAGE /*suppress error about including H5Fpkg */
|
||
#define H5G_PACKAGE /*suppress error about including H5Gpkg */
|
||
|
||
|
||
/***********/
|
||
/* Headers */
|
||
/***********/
|
||
#include "H5private.h" /* Generic Functions */
|
||
#include "H5Eprivate.h" /* Error handling */
|
||
#include "H5Fpkg.h" /* File access */
|
||
#include "H5Gpkg.h" /* Groups */
|
||
#include "H5Iprivate.h" /* IDs */
|
||
#include "H5MMprivate.h" /* Memory management */
|
||
#include "H5Pprivate.h" /* Property Lists */
|
||
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5G_rootof
|
||
*
|
||
* Purpose: Return a pointer to the root group of the file. If the file
|
||
* is part of a virtual file then the root group of the virtual
|
||
* file is returned.
|
||
*
|
||
* Return: Success: Ptr to the root group of the file. Do not
|
||
* free the pointer -- it points directly into
|
||
* the file struct.
|
||
*
|
||
* Failure: NULL
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Tuesday, October 13, 1998
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
H5G_t *
|
||
H5G_rootof(H5F_t *f)
|
||
{
|
||
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_rootof)
|
||
|
||
while(f->parent)
|
||
f = f->parent;
|
||
|
||
FUNC_LEAVE_NOAPI(f->shared->root_grp)
|
||
} /* end H5G_rootof() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5G_mkroot
|
||
*
|
||
* Purpose: Creates a root group in an empty file and opens it. If a
|
||
* root group is already open then this function immediately
|
||
* returns. If ENT is non-null then it's the symbol table
|
||
* entry for an existing group which will be opened as the root
|
||
* group. Otherwise a new root group is created and then
|
||
* opened.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 11 1997
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5G_mkroot(H5F_t *f, hid_t dxpl_id, hbool_t create_root)
|
||
{
|
||
H5G_loc_t root_loc; /* Root location information */
|
||
H5G_obj_create_t gcrt_info; /* Root group object creation info */
|
||
htri_t stab_exists = -1; /* Whether the symbol table exists */
|
||
hbool_t sblock_dirty = FALSE; /* Whether superblock was dirtied */
|
||
hbool_t path_init = FALSE; /* Whether path was initialized */
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5G_mkroot, FAIL)
|
||
|
||
/* check args */
|
||
HDassert(f);
|
||
HDassert(f->shared);
|
||
HDassert(f->shared->sblock);
|
||
|
||
/* Check if the root group is already initialized */
|
||
if(f->shared->root_grp)
|
||
HGOTO_DONE(SUCCEED)
|
||
|
||
/* Create information needed for group nodes */
|
||
if(H5G_node_init(f) < 0)
|
||
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group node info")
|
||
|
||
/*
|
||
* Create the group pointer
|
||
*/
|
||
if(NULL == (f->shared->root_grp = H5FL_CALLOC(H5G_t)))
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
|
||
if(NULL == (f->shared->root_grp->shared = H5FL_CALLOC(H5G_shared_t))) {
|
||
f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp);
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
|
||
} /* end if */
|
||
|
||
/* Initialize the root_loc structure to point to fields in the newly created
|
||
* f->shared->root_grp structure */
|
||
root_loc.oloc = &(f->shared->root_grp->oloc);
|
||
root_loc.path = &(f->shared->root_grp->path);
|
||
H5G_loc_reset(&root_loc);
|
||
|
||
/*
|
||
* If there is no root object then create one. The root group always starts
|
||
* with a hard link count of one since it's pointed to by the superblock.
|
||
*/
|
||
if(create_root) {
|
||
/* Create root group */
|
||
/* (Pass the FCPL which is a sub-class of the group creation property class) */
|
||
gcrt_info.gcpl_id = f->shared->fcpl_id;
|
||
gcrt_info.cache_type = H5G_NOTHING_CACHED;
|
||
if(H5G_obj_create(f, dxpl_id, &gcrt_info, root_loc.oloc/*out*/) < 0)
|
||
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group entry")
|
||
if(1 != H5O_link(root_loc.oloc, 1, dxpl_id))
|
||
HGOTO_ERROR(H5E_SYM, H5E_LINKCOUNT, FAIL, "internal error (wrong link count)")
|
||
|
||
/* Decrement refcount on root group's object header in memory */
|
||
if(H5O_dec_rc_by_loc(root_loc.oloc, dxpl_id) < 0)
|
||
HGOTO_ERROR(H5E_SYM, H5E_CANTDEC, FAIL, "unable to decrement refcount on root group's object header")
|
||
|
||
/* Mark superblock dirty, so root group info is flushed */
|
||
sblock_dirty = TRUE;
|
||
|
||
/* Create the root group symbol table entry */
|
||
HDassert(!f->shared->sblock->root_ent);
|
||
if(f->shared->sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) {
|
||
/* Allocate space for the root group symbol table entry */
|
||
if(NULL == (f->shared->sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t))))
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate space for symbol table entry")
|
||
|
||
/* Initialize the root group symbol table entry */
|
||
f->shared->sblock->root_ent->type = gcrt_info.cache_type;
|
||
if(gcrt_info.cache_type != H5G_NOTHING_CACHED)
|
||
f->shared->sblock->root_ent->cache = gcrt_info.cache;
|
||
f->shared->sblock->root_ent->name_off = 0; /* No name (yet) */
|
||
f->shared->sblock->root_ent->header = root_loc.oloc->addr;
|
||
} /* end if */
|
||
} /* end if */
|
||
else {
|
||
/* Create root group object location from f */
|
||
root_loc.oloc->addr = f->shared->sblock->root_addr;
|
||
root_loc.oloc->file = f;
|
||
|
||
/*
|
||
* Open the root object as a group.
|
||
*/
|
||
if(H5O_open(root_loc.oloc) < 0)
|
||
HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open root group")
|
||
|
||
/* Actions to take if the symbol table information is cached */
|
||
if(f->shared->sblock->root_ent && f->shared->sblock->root_ent->type == H5G_CACHED_STAB) {
|
||
/* Check for the situation where the symbol table is cached but does
|
||
* not exist. This can happen if, for example, an external link is
|
||
* added to the root group. */
|
||
if((stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID, dxpl_id)) < 0)
|
||
HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists")
|
||
|
||
/* Remove the cache if the stab does not exist */
|
||
if(!stab_exists)
|
||
f->shared->sblock->root_ent->type = H5G_NOTHING_CACHED;
|
||
#ifndef H5_STRICT_FORMAT_CHECKS
|
||
/* If symbol table information is cached, check if we should replace the
|
||
* symbol table message with the cached symbol table information */
|
||
else if(H5F_INTENT(f) & H5F_ACC_RDWR) {
|
||
H5O_stab_t cached_stab;
|
||
|
||
/* Retrieve the cached symbol table information */
|
||
cached_stab.btree_addr = f->shared->sblock->root_ent->cache.stab.btree_addr;
|
||
cached_stab.heap_addr = f->shared->sblock->root_ent->cache.stab.heap_addr;
|
||
|
||
/* Check if the symbol table message is valid, and replace with the
|
||
* cached symbol table if necessary */
|
||
if(H5G_stab_valid(root_loc.oloc, dxpl_id, &cached_stab) < 0)
|
||
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to verify symbol table")
|
||
} /* end if */
|
||
#endif /* H5_STRICT_FORMAT_CHECKS */
|
||
} /* end if */
|
||
} /* end else */
|
||
|
||
/* Cache the root group's symbol table information in the root group symbol
|
||
* table entry. It will have been allocated by now if it needs to be
|
||
* present, so we don't need to check the superblock version. We do this if
|
||
* we have write access, the root entry has been allocated (i.e.
|
||
* super_vers < 2) and the stab info is not already cached. */
|
||
if((H5F_INTENT(f) & H5F_ACC_RDWR) && stab_exists != FALSE && f->shared->sblock->root_ent
|
||
&& f->shared->sblock->root_ent->type != H5G_CACHED_STAB) {
|
||
H5O_stab_t stab; /* Symbol table */
|
||
|
||
/* Check if the stab message exists. It's possible for the root group
|
||
* to use the latest version while the superblock is an old version.
|
||
* If stab_exists is not -1 then we have already checked. */
|
||
if(stab_exists == -1 && (stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID, dxpl_id)) < 0)
|
||
HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists")
|
||
|
||
if(stab_exists) {
|
||
/* Read the root group's symbol table message */
|
||
if(NULL == H5O_msg_read(root_loc.oloc, H5O_STAB_ID, &stab, dxpl_id))
|
||
HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message")
|
||
|
||
/* Update the root group symbol table entry */
|
||
f->shared->sblock->root_ent->type = H5G_CACHED_STAB;
|
||
f->shared->sblock->root_ent->cache.stab.btree_addr = stab.btree_addr;
|
||
f->shared->sblock->root_ent->cache.stab.heap_addr = stab.heap_addr;
|
||
|
||
/* Mark superblock dirty, so root group info is flushed */
|
||
sblock_dirty = TRUE;
|
||
} /* end if */
|
||
} /* end if */
|
||
|
||
/* Create the path names for the root group's entry */
|
||
H5G_name_init(root_loc.path, "/");
|
||
path_init = TRUE;
|
||
|
||
f->shared->root_grp->shared->fo_count = 1;
|
||
/* The only other open object should be the superblock extension, if it
|
||
* exists. Don't count either the superblock extension or the root group
|
||
* in the number of open objects in the file.
|
||
*/
|
||
HDassert((1 == f->nopen_objs) ||
|
||
(2 == f->nopen_objs && HADDR_UNDEF != f->shared->sblock->ext_addr));
|
||
f->nopen_objs--;
|
||
|
||
done:
|
||
/* In case of error, free various memory locations that may have been
|
||
* allocated */
|
||
if(ret_value < 0) {
|
||
if(f->shared->root_grp) {
|
||
if(path_init)
|
||
H5G_name_free(root_loc.path);
|
||
if(f->shared->root_grp->shared)
|
||
f->shared->root_grp->shared = H5FL_FREE(H5G_shared_t, f->shared->root_grp->shared);
|
||
f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp);
|
||
} /* end if */
|
||
if(f->shared->sblock)
|
||
f->shared->sblock->root_ent = (H5G_entry_t *)H5MM_xfree(f->shared->sblock->root_ent);
|
||
} /* end if */
|
||
|
||
/* Mark superblock dirty in cache, if necessary */
|
||
if(sblock_dirty)
|
||
if(H5AC_mark_entry_dirty(f->shared->sblock) < 0)
|
||
HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty")
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5G_mkroot() */
|
||
|