mirror of
https://github.com/HDFGroup/hdf5.git
synced 2025-03-01 16:28:09 +08:00
Code cleanup Description: Clean up compiler warnings, especially the 'FUNC' variable not used which comes out in production mode. Solution: Had to add a new FUNC_ENTER_NOAPI_NOINIT_NOFUNC macro for those non-API functions which don't need the 'FUNC' variable defined. (This will be _so_ much easier when C99 is standard on all our supposed platforms, since it has a __FUNC__ macro... ) Platforms tested: FreeBSD 4.9 (sleipnir) too minor for h5committest (although there were lots of files changed, the change was minor in each one)
3573 lines
112 KiB
C
3573 lines
112 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
* 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. *
|
||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
||
/*-------------------------------------------------------------------------
|
||
*
|
||
* Created: H5O.c
|
||
* Aug 5 1997
|
||
* Robb Matzke <matzke@llnl.gov>
|
||
*
|
||
* Purpose: Object header virtual functions.
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
|
||
#define H5F_PACKAGE /*suppress error about including H5Fpkg */
|
||
#define H5O_PACKAGE /*suppress error about including H5Opkg */
|
||
|
||
#include "H5private.h" /* Generic Functions */
|
||
#include "H5ACprivate.h" /* Metadata cache */
|
||
#include "H5Eprivate.h" /* Error handling */
|
||
#include "H5Fpkg.h" /* File access */
|
||
#include "H5FLprivate.h" /* Free lists */
|
||
#include "H5Iprivate.h" /* IDs */
|
||
#include "H5MFprivate.h" /* File memory management */
|
||
#include "H5MMprivate.h" /* Memory management */
|
||
#include "H5Opkg.h" /* Object headers */
|
||
#include "H5Pprivate.h" /* Property lists */
|
||
|
||
#ifdef H5_HAVE_GETTIMEOFDAY
|
||
#include <sys/time.h>
|
||
#endif /* H5_HAVE_GETTIMEOFDAY */
|
||
|
||
#define PABLO_MASK H5O_mask
|
||
|
||
/* PRIVATE PROTOTYPES */
|
||
static herr_t H5O_init(H5F_t *f, hid_t dxpl_id, size_t size_hint,
|
||
H5G_entry_t *ent/*out*/, haddr_t header);
|
||
static herr_t H5O_reset_real(const H5O_class_t *type, void *native);
|
||
static void * H5O_copy_real(const H5O_class_t *type, const void *mesg,
|
||
void *dst);
|
||
static int H5O_count_real (H5G_entry_t *ent, const H5O_class_t *type,
|
||
hid_t dxpl_id);
|
||
static htri_t H5O_exists_real(H5G_entry_t *ent, const H5O_class_t *type,
|
||
int sequence, hid_t dxpl_id);
|
||
#ifdef NOT_YET
|
||
static herr_t H5O_share(H5F_t *f, hid_t dxpl_id, const H5O_class_t *type, const void *mesg,
|
||
H5HG_t *hobj/*out*/);
|
||
#endif /* NOT_YET */
|
||
static unsigned H5O_find_in_ohdr(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
|
||
const H5O_class_t **type_p, int sequence);
|
||
static int H5O_modify_real(H5G_entry_t *ent, const H5O_class_t *type,
|
||
int overwrite, unsigned flags, unsigned update_time, const void *mesg,
|
||
hid_t dxpl_id);
|
||
static int H5O_append_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
|
||
const H5O_class_t *type, unsigned flags, const void *mesg);
|
||
static herr_t H5O_remove_real(H5G_entry_t *ent, const H5O_class_t *type,
|
||
int sequence, hid_t dxpl_id);
|
||
static unsigned H5O_alloc(H5F_t *f, H5O_t *oh, const H5O_class_t *type,
|
||
size_t size);
|
||
static unsigned H5O_alloc_extend_chunk(H5O_t *oh, unsigned chunkno, size_t size);
|
||
static unsigned H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size);
|
||
static herr_t H5O_delete_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh);
|
||
static herr_t H5O_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_mesg_t *mesg);
|
||
static unsigned H5O_new_mesg(H5F_t *f, H5O_t *oh, unsigned *flags,
|
||
const H5O_class_t *orig_type, const void *orig_mesg, H5O_shared_t *sh_mesg,
|
||
const H5O_class_t **new_type, const void **new_mesg, hid_t dxpl_id);
|
||
static herr_t H5O_write_mesg(H5O_t *oh, unsigned idx, const H5O_class_t *type,
|
||
const void *mesg, unsigned flags);
|
||
|
||
/* Metadata cache callbacks */
|
||
static H5O_t *H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_udata1,
|
||
void *_udata2);
|
||
static herr_t H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5O_t *oh);
|
||
static herr_t H5O_dest(H5F_t *f, H5O_t *oh);
|
||
static herr_t H5O_clear(H5F_t *f, H5O_t *oh, hbool_t destroy);
|
||
|
||
/* H5O inherits cache-like properties from H5AC */
|
||
static const H5AC_class_t H5AC_OHDR[1] = {{
|
||
H5AC_OHDR_ID,
|
||
(H5AC_load_func_t)H5O_load,
|
||
(H5AC_flush_func_t)H5O_flush,
|
||
(H5AC_dest_func_t)H5O_dest,
|
||
(H5AC_clear_func_t)H5O_clear,
|
||
}};
|
||
|
||
/* Interface initialization */
|
||
static int interface_initialize_g = 0;
|
||
#define INTERFACE_INIT H5O_init_interface
|
||
static herr_t H5O_init_interface(void);
|
||
|
||
/* ID to type mapping */
|
||
static const H5O_class_t *const message_type_g[] = {
|
||
H5O_NULL, /*0x0000 Null */
|
||
H5O_SDSPACE, /*0x0001 Simple Dimensionality */
|
||
NULL, /*0x0002 Data space (fiber bundle?) */
|
||
H5O_DTYPE, /*0x0003 Data Type */
|
||
H5O_FILL, /*0x0004 Old data storage -- fill value */
|
||
H5O_FILL_NEW, /*0x0005 New Data storage -- fill value */
|
||
NULL, /*0x0006 Data storage -- compact object */
|
||
H5O_EFL, /*0x0007 Data storage -- external data files */
|
||
H5O_LAYOUT, /*0x0008 Data Layout */
|
||
#ifdef H5O_ENABLE_BOGUS
|
||
H5O_BOGUS, /*0x0009 "Bogus" */
|
||
#else /* H5O_ENABLE_BOGUS */
|
||
NULL, /*0x0009 "Bogus" */
|
||
#endif /* H5O_ENABLE_BOGUS */
|
||
NULL, /*0x000A Not assigned */
|
||
H5O_PLINE, /*0x000B Data storage -- filter pipeline */
|
||
H5O_ATTR, /*0x000C Attribute list */
|
||
H5O_NAME, /*0x000D Object name */
|
||
H5O_MTIME, /*0x000E Object modification date and time */
|
||
H5O_SHARED, /*0x000F Shared header message */
|
||
H5O_CONT, /*0x0010 Object header continuation */
|
||
H5O_STAB, /*0x0011 Symbol table */
|
||
H5O_MTIME_NEW, /*0x0012 New Object modification date and time */
|
||
};
|
||
|
||
/*
|
||
* An array of functions indexed by symbol table entry cache type
|
||
* (H5G_type_t) that are called to retrieve constant messages cached in the
|
||
* symbol table entry.
|
||
*/
|
||
static void *(*H5O_fast_g[H5G_NCACHED]) (const H5G_cache_t *,
|
||
const H5O_class_t *,
|
||
void *);
|
||
|
||
/* Declare a free list to manage the H5O_t struct */
|
||
H5FL_DEFINE_STATIC(H5O_t);
|
||
|
||
/* Declare a PQ free list to manage the H5O_mesg_t array information */
|
||
H5FL_ARR_DEFINE_STATIC(H5O_mesg_t,-1);
|
||
|
||
/* Declare a PQ free list to manage the H5O_chunk_t array information */
|
||
H5FL_ARR_DEFINE_STATIC(H5O_chunk_t,-1);
|
||
|
||
/* Declare a PQ free list to manage the chunk image information */
|
||
H5FL_BLK_DEFINE_STATIC(chunk_image);
|
||
|
||
/* Declare external the free list for time_t's */
|
||
H5FL_EXTERN(time_t);
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_init_interface
|
||
*
|
||
* Purpose: Initialize the H5O interface.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Tuesday, January 6, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_init_interface(void)
|
||
{
|
||
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_init_interface);
|
||
|
||
/*
|
||
* Initialize functions that decode messages from symbol table entries.
|
||
*/
|
||
H5O_fast_g[H5G_CACHED_STAB] = H5O_stab_fast;
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_create
|
||
*
|
||
* Purpose: Creates a new object header. Allocates space for it and
|
||
* then calls an initialization function. The object header
|
||
* is opened for write access and should eventually be
|
||
* closed by calling H5O_close().
|
||
*
|
||
* Return: Success: Non-negative, the ENT argument contains
|
||
* information about the object header,
|
||
* including its address.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 5 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
* Bill Wendling, 1. November 2002
|
||
* Separated the create function into two different functions. One
|
||
* which allocates space and an initialization function which
|
||
* does the rest of the work (initializes, caches, and opens the
|
||
* object header).
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, H5G_entry_t *ent/*out*/)
|
||
{
|
||
haddr_t header;
|
||
herr_t ret_value = SUCCEED; /* return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_create, FAIL);
|
||
|
||
/* check args */
|
||
assert(f);
|
||
assert(ent);
|
||
|
||
size_hint = H5O_ALIGN (MAX (H5O_MIN_SIZE, size_hint));
|
||
|
||
/* allocate disk space for header and first chunk */
|
||
if (HADDR_UNDEF == (header = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id,
|
||
(hsize_t)H5O_SIZEOF_HDR(f) + size_hint)))
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
|
||
"file allocation failed for object header header");
|
||
|
||
/* initialize the object header */
|
||
if (H5O_init(f, dxpl_id, size_hint, ent, header) != SUCCEED)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to initialize object header");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_init
|
||
*
|
||
* Purpose: Initialize a new object header, sets the link count to 0,
|
||
* and caches the header. The object header is opened for
|
||
* write access and should eventually be closed by calling
|
||
* H5O_close().
|
||
*
|
||
* Return: Success: SUCCEED, the ENT argument contains
|
||
* information about the object header,
|
||
* including its address.
|
||
* Failure: FAIL
|
||
*
|
||
* Programmer: Bill Wendling
|
||
* 1, November 2002
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_init(H5F_t *f, hid_t dxpl_id, size_t size_hint, H5G_entry_t *ent/*out*/, haddr_t header)
|
||
{
|
||
H5O_t *oh = NULL;
|
||
haddr_t tmp_addr;
|
||
herr_t ret_value = SUCCEED; /* return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_init);
|
||
|
||
/* check args */
|
||
assert(f);
|
||
assert(ent);
|
||
|
||
size_hint = H5O_ALIGN(MAX(H5O_MIN_SIZE, size_hint));
|
||
ent->file = f;
|
||
ent->header = header;
|
||
|
||
/* allocate the object header and fill in header fields */
|
||
if (NULL == (oh = H5FL_MALLOC(H5O_t)))
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
|
||
|
||
oh->cache_info.dirty = TRUE;
|
||
oh->version = H5O_VERSION;
|
||
oh->nlink = 0;
|
||
|
||
/* create the chunk list and initialize the first chunk */
|
||
oh->nchunks = 1;
|
||
oh->alloc_nchunks = H5O_NCHUNKS;
|
||
|
||
if (NULL == (oh->chunk = H5FL_ARR_MALLOC(H5O_chunk_t, oh->alloc_nchunks)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
|
||
|
||
tmp_addr = ent->header + (hsize_t)H5O_SIZEOF_HDR(f);
|
||
oh->chunk[0].dirty = TRUE;
|
||
oh->chunk[0].addr = tmp_addr;
|
||
oh->chunk[0].size = size_hint;
|
||
|
||
if (NULL == (oh->chunk[0].image = H5FL_BLK_CALLOC(chunk_image, size_hint)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
|
||
|
||
/* create the message list and initialize the first message */
|
||
oh->nmesgs = 1;
|
||
oh->alloc_nmesgs = H5O_NMESGS;
|
||
|
||
if (NULL == (oh->mesg = H5FL_ARR_CALLOC(H5O_mesg_t, oh->alloc_nmesgs)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
|
||
|
||
oh->mesg[0].type = H5O_NULL;
|
||
oh->mesg[0].dirty = TRUE;
|
||
oh->mesg[0].native = NULL;
|
||
oh->mesg[0].raw = oh->chunk[0].image + H5O_SIZEOF_MSGHDR(f);
|
||
oh->mesg[0].raw_size = size_hint - H5O_SIZEOF_MSGHDR(f);
|
||
oh->mesg[0].chunkno = 0;
|
||
|
||
/* cache it */
|
||
if (H5AC_set(f, dxpl_id, H5AC_OHDR, ent->header, oh) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to cache object header");
|
||
|
||
/* open it */
|
||
if (H5O_open(ent) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object header");
|
||
|
||
done:
|
||
if(ret_value<0 && oh) {
|
||
if(H5O_dest(f,oh)<0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data");
|
||
} /* end if */
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_open
|
||
*
|
||
* Purpose: Opens an object header which is described by the symbol table
|
||
* entry OBJ_ENT.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Monday, January 5, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_open(H5G_entry_t *obj_ent)
|
||
{
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_open, FAIL);
|
||
|
||
/* Check args */
|
||
assert(obj_ent);
|
||
assert(obj_ent->file);
|
||
|
||
#ifdef H5O_DEBUG
|
||
if (H5DEBUG(O))
|
||
HDfprintf(H5DEBUG(O), "> %a\n", obj_ent->header);
|
||
#endif
|
||
|
||
/* Increment open-lock counters */
|
||
obj_ent->file->nopen_objs++;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_close
|
||
*
|
||
* Purpose: Closes an object header that was previously open.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Monday, January 5, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
* Pedro Vicente, <pvn@ncsa.uiuc.edu> 22 Aug 2002
|
||
* Added `id to name' support.
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_close(H5G_entry_t *obj_ent)
|
||
{
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_close, FAIL);
|
||
|
||
/* Check args */
|
||
assert(obj_ent);
|
||
assert(obj_ent->file);
|
||
assert(obj_ent->file->nopen_objs > 0);
|
||
|
||
/* Decrement open-lock counters */
|
||
--obj_ent->file->nopen_objs;
|
||
|
||
#ifdef H5O_DEBUG
|
||
if (H5DEBUG(O)) {
|
||
if (obj_ent->file->closing && 1==obj_ent->file->shared->nrefs) {
|
||
HDfprintf(H5DEBUG(O), "< %a auto %lu remaining\n",
|
||
obj_ent->header,
|
||
(unsigned long)(obj_ent->file->nopen_objs));
|
||
} else {
|
||
HDfprintf(H5DEBUG(O), "< %a\n", obj_ent->header);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/*
|
||
* If the file open-lock count has reached zero and the file has a close
|
||
* pending then close the file and remove it from the H5I_FILE_CLOSING ID
|
||
* group.
|
||
*/
|
||
if (0==obj_ent->file->nopen_objs && obj_ent->file->closing)
|
||
H5I_dec_ref(obj_ent->file->closing);
|
||
|
||
|
||
/* Free the ID to name buffers */
|
||
H5G_free_ent_name(obj_ent);
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_load
|
||
*
|
||
* Purpose: Loads an object header from disk.
|
||
*
|
||
* Return: Success: Pointer to the new object header.
|
||
*
|
||
* Failure: NULL
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 5 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
* Robb Matzke, 1997-08-30
|
||
* Plugged memory leaks that occur during error handling.
|
||
*
|
||
* Robb Matzke, 1998-01-07
|
||
* Able to distinguish between constant and variable messages.
|
||
*
|
||
* Robb Matzke, 1999-07-28
|
||
* The ADDR argument is passed by value.
|
||
*
|
||
* Quincey Koziol, 2002-7-180
|
||
* Added dxpl parameter to allow more control over I/O from metadata
|
||
* cache.
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static H5O_t *
|
||
H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
|
||
void UNUSED * _udata2)
|
||
{
|
||
H5O_t *oh = NULL;
|
||
H5O_t *ret_value;
|
||
uint8_t buf[16], *p;
|
||
size_t mesg_size;
|
||
size_t hdr_size;
|
||
unsigned id;
|
||
int mesgno;
|
||
unsigned curmesg = 0, nmesgs;
|
||
unsigned chunkno;
|
||
haddr_t chunk_addr;
|
||
size_t chunk_size;
|
||
uint8_t flags;
|
||
|
||
FUNC_ENTER_NOAPI(H5O_load, NULL);
|
||
|
||
/* check args */
|
||
assert(f);
|
||
assert(H5F_addr_defined(addr));
|
||
assert(!_udata1);
|
||
assert(!_udata2);
|
||
|
||
/* allocate ohdr and init chunk list */
|
||
if (NULL==(oh = H5FL_CALLOC(H5O_t)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
|
||
|
||
/* read fixed-lenth part of object header */
|
||
hdr_size = H5O_SIZEOF_HDR(f);
|
||
assert(hdr_size<=sizeof(buf));
|
||
if (H5F_block_read(f, H5FD_MEM_OHDR, addr, hdr_size, dxpl_id, buf) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header");
|
||
p = buf;
|
||
|
||
/* decode version */
|
||
oh->version = *p++;
|
||
if (H5O_VERSION != oh->version)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header version number");
|
||
|
||
/* reserved */
|
||
p++;
|
||
|
||
/* decode number of messages */
|
||
UINT16DECODE(p, nmesgs);
|
||
|
||
/* decode link count */
|
||
UINT32DECODE(p, oh->nlink);
|
||
|
||
/* decode first chunk info */
|
||
chunk_addr = addr + (hsize_t)hdr_size;
|
||
UINT32DECODE(p, chunk_size);
|
||
|
||
/* build the message array */
|
||
oh->alloc_nmesgs = MAX(H5O_NMESGS, nmesgs);
|
||
if (NULL==(oh->mesg=H5FL_ARR_CALLOC(H5O_mesg_t,oh->alloc_nmesgs)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
|
||
|
||
/* read each chunk from disk */
|
||
while (H5F_addr_defined(chunk_addr)) {
|
||
/* increase chunk array size */
|
||
if (oh->nchunks >= oh->alloc_nchunks) {
|
||
unsigned na = oh->alloc_nchunks + H5O_NCHUNKS;
|
||
H5O_chunk_t *x = H5FL_ARR_REALLOC (H5O_chunk_t, oh->chunk, na);
|
||
|
||
if (!x)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
|
||
oh->alloc_nchunks = na;
|
||
oh->chunk = x;
|
||
}
|
||
|
||
/* read the chunk raw data */
|
||
chunkno = oh->nchunks++;
|
||
oh->chunk[chunkno].dirty = FALSE;
|
||
oh->chunk[chunkno].addr = chunk_addr;
|
||
oh->chunk[chunkno].size = chunk_size;
|
||
if (NULL==(oh->chunk[chunkno].image = H5FL_BLK_MALLOC(chunk_image,chunk_size)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
|
||
if (H5F_block_read(f, H5FD_MEM_OHDR, chunk_addr, chunk_size, dxpl_id,
|
||
oh->chunk[chunkno].image) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header data");
|
||
|
||
/* load messages from this chunk */
|
||
for (p = oh->chunk[chunkno].image; p < oh->chunk[chunkno].image + chunk_size; p += mesg_size) {
|
||
UINT16DECODE(p, id);
|
||
UINT16DECODE(p, mesg_size);
|
||
assert (mesg_size==H5O_ALIGN (mesg_size));
|
||
flags = *p++;
|
||
p += 3; /*reserved*/
|
||
|
||
/* Try to detect invalidly formatted object header messages */
|
||
if (p + mesg_size > oh->chunk[chunkno].image + chunk_size)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "corrupt object header");
|
||
|
||
/* Skip header messages we don't know about */
|
||
/* (Usually from future versions of the library */
|
||
if (id >= NELMTS(message_type_g) || NULL == message_type_g[id])
|
||
continue;
|
||
|
||
if (H5O_NULL_ID == id && oh->nmesgs > 0 &&
|
||
H5O_NULL_ID == oh->mesg[oh->nmesgs - 1].type->id &&
|
||
oh->mesg[oh->nmesgs - 1].chunkno == chunkno) {
|
||
/* combine adjacent null messages */
|
||
mesgno = oh->nmesgs - 1;
|
||
oh->mesg[mesgno].raw_size += H5O_SIZEOF_MSGHDR(f) + mesg_size;
|
||
} else {
|
||
/* new message */
|
||
if (oh->nmesgs >= nmesgs)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header");
|
||
mesgno = oh->nmesgs++;
|
||
oh->mesg[mesgno].type = message_type_g[id];
|
||
oh->mesg[mesgno].dirty = FALSE;
|
||
oh->mesg[mesgno].flags = flags;
|
||
oh->mesg[mesgno].native = NULL;
|
||
oh->mesg[mesgno].raw = p;
|
||
oh->mesg[mesgno].raw_size = mesg_size;
|
||
oh->mesg[mesgno].chunkno = chunkno;
|
||
}
|
||
}
|
||
|
||
assert(p == oh->chunk[chunkno].image + chunk_size);
|
||
|
||
/* decode next object header continuation message */
|
||
for (chunk_addr = HADDR_UNDEF; !H5F_addr_defined(chunk_addr) && curmesg < oh->nmesgs; ++curmesg) {
|
||
if (H5O_CONT_ID == oh->mesg[curmesg].type->id) {
|
||
H5O_cont_t *cont;
|
||
|
||
cont = (H5O_CONT->decode) (f, dxpl_id, oh->mesg[curmesg].raw, NULL);
|
||
oh->mesg[curmesg].native = cont;
|
||
chunk_addr = cont->addr;
|
||
chunk_size = cont->size;
|
||
cont->chunkno = oh->nchunks; /*the next chunk to allocate */
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Set return value */
|
||
ret_value = oh;
|
||
|
||
done:
|
||
if (!ret_value && oh) {
|
||
if(H5O_dest(f,oh)<0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, NULL, "unable to destroy object header data");
|
||
}
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_flush
|
||
*
|
||
* Purpose: Flushes (and destroys) an object header.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 5 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
* Robb Matzke, 1998-01-07
|
||
* Handles constant vs non-constant messages.
|
||
*
|
||
* rky, 1998-08-28
|
||
* Only p0 writes metadata to disk.
|
||
*
|
||
* Robb Matzke, 1999-07-28
|
||
* The ADDR argument is passed by value.
|
||
*
|
||
* Quincey Koziol, 2002-7-180
|
||
* Added dxpl parameter to allow more control over I/O from metadata
|
||
* cache.
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5O_t *oh)
|
||
{
|
||
uint8_t buf[16], *p;
|
||
int id;
|
||
unsigned u;
|
||
H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
|
||
H5O_cont_t *cont = NULL;
|
||
herr_t (*encode)(H5F_t*, uint8_t*, const void*) = NULL;
|
||
unsigned combine=0; /* Whether to combine the object header prefix & the first chunk */
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_flush, FAIL);
|
||
|
||
/* check args */
|
||
assert(f);
|
||
assert(H5F_addr_defined(addr));
|
||
assert(oh);
|
||
|
||
/* flush */
|
||
if (oh->cache_info.dirty) {
|
||
p = buf;
|
||
|
||
/* encode version */
|
||
*p++ = oh->version;
|
||
|
||
/* reserved */
|
||
*p++ = 0;
|
||
|
||
/* encode number of messages */
|
||
UINT16ENCODE(p, oh->nmesgs);
|
||
|
||
/* encode link count */
|
||
UINT32ENCODE(p, oh->nlink);
|
||
|
||
/* encode body size */
|
||
UINT32ENCODE(p, oh->chunk[0].size);
|
||
|
||
/* zero to alignment */
|
||
HDmemset (p, 0, H5O_SIZEOF_HDR(f)-12);
|
||
|
||
/* write the object header prefix */
|
||
|
||
/* Check if we can combine the object header prefix & the first chunk into one I/O operation */
|
||
if(oh->chunk[0].dirty && (addr+H5O_SIZEOF_HDR(f))==oh->chunk[0].addr) {
|
||
combine=1;
|
||
} /* end if */
|
||
else {
|
||
if (H5F_block_write(f, H5FD_MEM_OHDR, addr, H5O_SIZEOF_HDR(f),
|
||
dxpl_id, buf) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header hdr to disk");
|
||
} /* end else */
|
||
|
||
/* encode messages */
|
||
for (u = 0, curr_msg=&oh->mesg[0]; u < oh->nmesgs; u++,curr_msg++) {
|
||
if (curr_msg->dirty) {
|
||
p = curr_msg->raw - H5O_SIZEOF_MSGHDR(f);
|
||
|
||
id = curr_msg->type->id;
|
||
UINT16ENCODE(p, id);
|
||
assert (curr_msg->raw_size<H5O_MAX_SIZE);
|
||
UINT16ENCODE(p, curr_msg->raw_size);
|
||
*p++ = curr_msg->flags;
|
||
*p++ = 0; /*reserved*/
|
||
*p++ = 0; /*reserved*/
|
||
*p++ = 0; /*reserved*/
|
||
|
||
if (curr_msg->native) {
|
||
assert(curr_msg->type->encode);
|
||
|
||
/* allocate file space for chunks that have none yet */
|
||
if (H5O_CONT_ID == curr_msg->type->id &&
|
||
!H5F_addr_defined(((H5O_cont_t *)(curr_msg->native))->addr)) {
|
||
cont = (H5O_cont_t *) (curr_msg->native);
|
||
assert(cont->chunkno < oh->nchunks);
|
||
assert(!H5F_addr_defined(oh->chunk[cont->chunkno].addr));
|
||
cont->size = oh->chunk[cont->chunkno].size;
|
||
if (HADDR_UNDEF==(cont->addr=H5MF_alloc(f,
|
||
H5FD_MEM_OHDR, dxpl_id, (hsize_t)cont->size)))
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate space for object header data");
|
||
oh->chunk[cont->chunkno].addr = cont->addr;
|
||
}
|
||
|
||
/*
|
||
* Encode the message. If the message is shared then we
|
||
* encode a Shared Object message instead of the object
|
||
* which is being shared.
|
||
*/
|
||
assert(curr_msg->raw >=
|
||
oh->chunk[curr_msg->chunkno].image);
|
||
assert (curr_msg->raw_size ==
|
||
H5O_ALIGN (curr_msg->raw_size));
|
||
assert(curr_msg->raw + curr_msg->raw_size <=
|
||
oh->chunk[curr_msg->chunkno].image +
|
||
oh->chunk[curr_msg->chunkno].size);
|
||
if (curr_msg->flags & H5O_FLAG_SHARED) {
|
||
encode = H5O_SHARED->encode;
|
||
} else {
|
||
encode = curr_msg->type->encode;
|
||
}
|
||
if ((encode)(f, curr_msg->raw, curr_msg->native)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message");
|
||
}
|
||
curr_msg->dirty = FALSE;
|
||
oh->chunk[curr_msg->chunkno].dirty = TRUE;
|
||
}
|
||
}
|
||
|
||
/* write each chunk to disk */
|
||
for (u = 0; u < oh->nchunks; u++) {
|
||
if (oh->chunk[u].dirty) {
|
||
assert(H5F_addr_defined(oh->chunk[u].addr));
|
||
if(u==0 && combine) {
|
||
/* Allocate space for the combined prefix and first chunk */
|
||
if((p=H5FL_BLK_MALLOC(chunk_image,(H5O_SIZEOF_HDR(f)+oh->chunk[u].size)))==NULL)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
|
||
|
||
/* Copy in the prefix */
|
||
HDmemcpy(p,buf,H5O_SIZEOF_HDR(f));
|
||
|
||
/* Copy in the first chunk */
|
||
HDmemcpy(p+H5O_SIZEOF_HDR(f),oh->chunk[u].image,oh->chunk[u].size);
|
||
|
||
/* Write the combined prefix/chunk out */
|
||
if (H5F_block_write(f, H5FD_MEM_OHDR, addr,
|
||
(H5O_SIZEOF_HDR(f)+oh->chunk[u].size),
|
||
dxpl_id, p) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header data to disk");
|
||
|
||
/* Release the memory for the combined prefix/chunk */
|
||
p = H5FL_BLK_FREE(chunk_image,p);
|
||
} /* end if */
|
||
else {
|
||
if (H5F_block_write(f, H5FD_MEM_OHDR, oh->chunk[u].addr,
|
||
(oh->chunk[u].size),
|
||
dxpl_id, oh->chunk[u].image) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header data to disk");
|
||
} /* end else */
|
||
oh->chunk[u].dirty = FALSE;
|
||
} /* end if */
|
||
} /* end for */
|
||
oh->cache_info.dirty = FALSE;
|
||
}
|
||
|
||
if (destroy) {
|
||
if(H5O_dest(f,oh)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data");
|
||
}
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_dest
|
||
*
|
||
* Purpose: Destroys an object header.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Jan 15 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_dest(H5F_t UNUSED *f, H5O_t *oh)
|
||
{
|
||
unsigned i;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_dest);
|
||
|
||
/* check args */
|
||
assert(oh);
|
||
|
||
/* Verify that node is clean */
|
||
assert (oh->cache_info.dirty==0);
|
||
|
||
/* destroy chunks */
|
||
for (i = 0; i < oh->nchunks; i++) {
|
||
/* Verify that chunk is clean */
|
||
assert (oh->chunk[i].dirty==0);
|
||
|
||
oh->chunk[i].image = H5FL_BLK_FREE(chunk_image,oh->chunk[i].image);
|
||
}
|
||
oh->chunk = H5FL_ARR_FREE(H5O_chunk_t,oh->chunk);
|
||
|
||
/* destroy messages */
|
||
for (i = 0; i < oh->nmesgs; i++) {
|
||
/* Verify that message is clean */
|
||
assert (oh->mesg[i].dirty==0);
|
||
|
||
if (oh->mesg[i].flags & H5O_FLAG_SHARED)
|
||
H5O_free_real(H5O_SHARED, oh->mesg[i].native);
|
||
else
|
||
H5O_free_real(oh->mesg[i].type, oh->mesg[i].native);
|
||
}
|
||
oh->mesg = H5FL_ARR_FREE(H5O_mesg_t,oh->mesg);
|
||
|
||
/* destroy object header */
|
||
H5FL_FREE(H5O_t,oh);
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED);
|
||
} /* end H5O_dest() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_clear
|
||
*
|
||
* Purpose: Mark a object header in memory as non-dirty.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Mar 20 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_clear(H5F_t *f, H5O_t *oh, hbool_t destroy)
|
||
{
|
||
unsigned u; /* Local index variable */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_clear);
|
||
|
||
/* check args */
|
||
assert(oh);
|
||
|
||
/* Mark chunks as clean */
|
||
for (u = 0; u < oh->nchunks; u++)
|
||
oh->chunk[u].dirty=FALSE;
|
||
|
||
/* Mark messages as clean */
|
||
for (u = 0; u < oh->nmesgs; u++)
|
||
oh->mesg[u].dirty=FALSE;
|
||
|
||
/* Mark whole header as clean */
|
||
oh->cache_info.dirty=FALSE;
|
||
|
||
if (destroy)
|
||
if (H5O_dest(f, oh) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_clear() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_reset
|
||
*
|
||
* Purpose: Some message data structures have internal fields that
|
||
* need to be freed. This function does that if appropriate
|
||
* but doesn't free NATIVE.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 12 1997
|
||
*
|
||
* Modifications:
|
||
* Changed to use IDs for types, instead of type objects, then
|
||
* call "real" routine.
|
||
* Quincey Koziol
|
||
* Feb 14 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_reset(hid_t type_id, void *native)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
herr_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_reset,FAIL);
|
||
|
||
/* check args */
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert(type);
|
||
|
||
/* Call the "real" reset routine */
|
||
if((ret_value=H5O_reset_real(type, native))<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_READERROR, FAIL, "unable to reset object header");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_reset() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_reset_real
|
||
*
|
||
* Purpose: Some message data structures have internal fields that
|
||
* need to be freed. This function does that if appropriate
|
||
* but doesn't free NATIVE.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 12 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_reset_real(const H5O_class_t *type, void *native)
|
||
{
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_reset_real);
|
||
|
||
/* check args */
|
||
assert(type);
|
||
|
||
if (native) {
|
||
if (type->reset) {
|
||
if ((type->reset) (native) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "reset method failed");
|
||
} else {
|
||
HDmemset(native, 0, type->native_size);
|
||
}
|
||
}
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_reset_real() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_free
|
||
*
|
||
* Purpose: Similar to H5O_reset() except it also frees the message
|
||
* pointer.
|
||
*
|
||
* Return: Success: NULL
|
||
*
|
||
* Failure: NULL
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Thursday, May 21, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
void *
|
||
H5O_free (hid_t type_id, void *mesg)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
void * ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_free, NULL);
|
||
|
||
/* check args */
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert(type);
|
||
|
||
/* Call the "real" free routine */
|
||
ret_value=H5O_free_real(type, mesg);
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_free() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_free_real
|
||
*
|
||
* Purpose: Similar to H5O_reset() except it also frees the message
|
||
* pointer.
|
||
*
|
||
* Return: Success: NULL
|
||
*
|
||
* Failure: NULL
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Thursday, May 21, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
void *
|
||
H5O_free_real(const H5O_class_t *type, void *mesg)
|
||
{
|
||
void * ret_value=NULL; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_free_real);
|
||
|
||
/* check args */
|
||
assert(type);
|
||
|
||
if (mesg) {
|
||
H5O_reset_real(type, mesg);
|
||
if (NULL!=(type->free))
|
||
(type->free)(mesg);
|
||
else
|
||
H5MM_xfree (mesg);
|
||
}
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_free_real() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_copy
|
||
*
|
||
* Purpose: Copies a message. If MESG is is the null pointer then a null
|
||
* pointer is returned with no error.
|
||
*
|
||
* Return: Success: Ptr to the new message
|
||
*
|
||
* Failure: NULL
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Thursday, May 21, 1998
|
||
*
|
||
* Modifications:
|
||
* Changed to use IDs for types, instead of type objects, then
|
||
* call "real" routine.
|
||
* Quincey Koziol
|
||
* Feb 14 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
void *
|
||
H5O_copy (hid_t type_id, const void *mesg, void *dst)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
void *ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_copy, NULL);
|
||
|
||
/* check args */
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert(type);
|
||
|
||
/* Call the "real" copy routine */
|
||
if((ret_value=H5O_copy_real(type, mesg, dst))==NULL)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy object header message");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_copy() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_copy_real
|
||
*
|
||
* Purpose: Copies a message. If MESG is is the null pointer then a null
|
||
* pointer is returned with no error.
|
||
*
|
||
* Return: Success: Ptr to the new message
|
||
*
|
||
* Failure: NULL
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Thursday, May 21, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static void *
|
||
H5O_copy_real (const H5O_class_t *type, const void *mesg, void *dst)
|
||
{
|
||
void *ret_value = NULL;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_copy_real);
|
||
|
||
/* check args */
|
||
assert (type);
|
||
assert (type->copy);
|
||
|
||
if (mesg) {
|
||
if (NULL==(ret_value=(type->copy)(mesg, dst)))
|
||
HGOTO_ERROR (H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy object header message");
|
||
}
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_copy_real() */
|
||
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_link
|
||
*
|
||
* Purpose: Adjust the link count for an object header by adding
|
||
* ADJUST to the link count.
|
||
*
|
||
* Return: Success: New link count
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 5 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
* Robb Matzke, 1998-08-27
|
||
* This function can also be used to obtain the current number of links
|
||
* if zero is passed for ADJUST. If that's the case then we don't check
|
||
* for write access on the file.
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
int
|
||
H5O_link(const H5G_entry_t *ent, int adjust, hid_t dxpl_id)
|
||
{
|
||
H5O_t *oh = NULL;
|
||
hbool_t deleted=FALSE; /* Whether the object was deleted as a result of this action */
|
||
int ret_value = FAIL;
|
||
|
||
FUNC_ENTER_NOAPI(H5O_link, FAIL);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
if (adjust!=0 && 0==(ent->file->intent & H5F_ACC_RDWR))
|
||
HGOTO_ERROR (H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file");
|
||
|
||
/* get header */
|
||
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header,
|
||
NULL, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
|
||
|
||
/* adjust link count */
|
||
if (adjust<0) {
|
||
if (oh->nlink + adjust < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "link count would be negative");
|
||
oh->nlink += adjust;
|
||
oh->cache_info.dirty = TRUE;
|
||
|
||
/* Check if the object should be deleted */
|
||
if(oh->nlink==0) {
|
||
/* Check if the object is still open by the user */
|
||
if(H5FO_opened(ent->file,ent->header)>=0) {
|
||
/* Flag the object to be deleted when it's closed */
|
||
if(H5FO_mark(ent->file,ent->header)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't mark object for deletion");
|
||
} /* end if */
|
||
else {
|
||
/* Delete object right now */
|
||
if(H5O_delete_oh(ent->file,dxpl_id,oh)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file");
|
||
|
||
/* Mark the object header as deleted */
|
||
deleted=TRUE;
|
||
} /* end else */
|
||
} /* end if */
|
||
} else if (adjust>0) {
|
||
oh->nlink += adjust;
|
||
oh->cache_info.dirty = TRUE;
|
||
}
|
||
|
||
/* Set return value */
|
||
ret_value = oh->nlink;
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, deleted) < 0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_count
|
||
*
|
||
* Purpose: Counts the number of messages in an object header which are a
|
||
* certain type.
|
||
*
|
||
* Return: Success: Number of messages of specified type.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Tuesday, April 21, 1998
|
||
*
|
||
* Modifications:
|
||
* Changed to use IDs for types, instead of type objects, then
|
||
* call "real" routine.
|
||
* Quincey Koziol
|
||
* Feb 14 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
int
|
||
H5O_count (H5G_entry_t *ent, hid_t type_id, hid_t dxpl_id)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
int ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_count_real, FAIL);
|
||
|
||
/* Check args */
|
||
assert (ent);
|
||
assert (ent->file);
|
||
assert (H5F_addr_defined(ent->header));
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert (type);
|
||
|
||
/* Call the "real" count routine */
|
||
if((ret_value=H5O_count_real(ent, type, dxpl_id))<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, FAIL, "unable to count object header messages");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_count() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_count_real
|
||
*
|
||
* Purpose: Counts the number of messages in an object header which are a
|
||
* certain type.
|
||
*
|
||
* Return: Success: Number of messages of specified type.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Tuesday, April 21, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static int
|
||
H5O_count_real (H5G_entry_t *ent, const H5O_class_t *type, hid_t dxpl_id)
|
||
{
|
||
H5O_t *oh = NULL;
|
||
int acc;
|
||
unsigned u;
|
||
int ret_value;
|
||
|
||
FUNC_ENTER_NOAPI(H5O_count_real, FAIL);
|
||
|
||
/* Check args */
|
||
assert (ent);
|
||
assert (ent->file);
|
||
assert (H5F_addr_defined(ent->header));
|
||
assert (type);
|
||
|
||
/* Load the object header */
|
||
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, NULL, NULL, H5AC_READ)))
|
||
HGOTO_ERROR (H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
|
||
|
||
/* Loop over all messages, counting the ones of the type looked for */
|
||
for (u=acc=0; u<oh->nmesgs; u++)
|
||
if (oh->mesg[u].type==type)
|
||
acc++;
|
||
|
||
/* Set return value */
|
||
ret_value=acc;
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) != SUCCEED)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_count_real() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_exists
|
||
*
|
||
* Purpose: Determines if a particular message exists in an object
|
||
* header without trying to decode the message.
|
||
*
|
||
* Return: Success: FALSE if the message does not exist; TRUE if
|
||
* th message exists.
|
||
*
|
||
* Failure: FAIL if the existence of the message could
|
||
* not be determined due to some error such as
|
||
* not being able to read the object header.
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Monday, November 2, 1998
|
||
*
|
||
* Modifications:
|
||
* Changed to use IDs for types, instead of type objects, then
|
||
* call "real" routine.
|
||
* Quincey Koziol
|
||
* Feb 14 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
htri_t
|
||
H5O_exists(H5G_entry_t *ent, hid_t type_id, int sequence, hid_t dxpl_id)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
htri_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_exists, FAIL);
|
||
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert(type);
|
||
assert(sequence>=0);
|
||
|
||
/* Call the "real" exists routine */
|
||
if((ret_value=H5O_exists_real(ent, type, sequence, dxpl_id))<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_READERROR, FAIL, "unable to verify object header message");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_exists() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_exists_real
|
||
*
|
||
* Purpose: Determines if a particular message exists in an object
|
||
* header without trying to decode the message.
|
||
*
|
||
* Return: Success: FALSE if the message does not exist; TRUE if
|
||
* th message exists.
|
||
*
|
||
* Failure: FAIL if the existence of the message could
|
||
* not be determined due to some error such as
|
||
* not being able to read the object header.
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Monday, November 2, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static htri_t
|
||
H5O_exists_real(H5G_entry_t *ent, const H5O_class_t *type, int sequence, hid_t dxpl_id)
|
||
{
|
||
H5O_t *oh=NULL;
|
||
unsigned u;
|
||
htri_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_exists_real);
|
||
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(type);
|
||
assert(sequence>=0);
|
||
|
||
/* Load the object header */
|
||
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, NULL, NULL, H5AC_READ)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
|
||
|
||
/* Scan through the messages looking for the right one */
|
||
for (u=0; u<oh->nmesgs; u++) {
|
||
if (type->id!=oh->mesg[u].type->id)
|
||
continue;
|
||
if (--sequence<0)
|
||
break;
|
||
}
|
||
|
||
/* Set return value */
|
||
ret_value=(sequence<0);
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) != SUCCEED)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_exists_real() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_read
|
||
*
|
||
* Purpose: Reads a message from an object header and returns a pointer
|
||
* to it. The caller will usually supply the memory through
|
||
* MESG and the return value will be MESG. But if MESG is
|
||
* the null pointer, then this function will malloc() memory
|
||
* to hold the result and return its pointer instead.
|
||
*
|
||
* Return: Success: Ptr to message in native format. The message
|
||
* should be freed by calling H5O_reset(). If
|
||
* MESG is a null pointer then the caller should
|
||
* also call H5MM_xfree() on the return value
|
||
* after calling H5O_reset().
|
||
*
|
||
* Failure: NULL
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 6 1997
|
||
*
|
||
* Modifications:
|
||
* Changed to use IDs for types, instead of type objects, then
|
||
* call "real" routine.
|
||
* Quincey Koziol
|
||
* Feb 14 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
void *
|
||
H5O_read(H5G_entry_t *ent, hid_t type_id, int sequence, void *mesg, hid_t dxpl_id)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
void *ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_read, NULL);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert(type);
|
||
assert(sequence >= 0);
|
||
|
||
/* Call the "real" read routine */
|
||
if((ret_value=H5O_read_real(ent, type, sequence, mesg, dxpl_id))==NULL)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to load object header");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_read() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_read_real
|
||
*
|
||
* Purpose: Reads a message from an object header and returns a pointer
|
||
* to it. The caller will usually supply the memory through
|
||
* MESG and the return value will be MESG. But if MESG is
|
||
* the null pointer, then this function will malloc() memory
|
||
* to hold the result and return its pointer instead.
|
||
*
|
||
* Return: Success: Ptr to message in native format. The message
|
||
* should be freed by calling H5O_reset(). If
|
||
* MESG is a null pointer then the caller should
|
||
* also call H5MM_xfree() on the return value
|
||
* after calling H5O_reset().
|
||
*
|
||
* Failure: NULL
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 6 1997
|
||
*
|
||
* Modifications:
|
||
* Bill Wendling, 2003-09-30
|
||
* Protect the object header and pass it into the H5O_find_in_ohdr
|
||
* function. This is done because the H5O_find_in_ohdr used to
|
||
* protect the ohdr, find the message, and then unprotect it. This
|
||
* saves time and also helps the FPHDF5 stuff, where unprotecting
|
||
* actually destroys the object in the cache.
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
void *
|
||
H5O_read_real(H5G_entry_t *ent, const H5O_class_t *type, int sequence, void *mesg, hid_t dxpl_id)
|
||
{
|
||
H5O_t *oh = NULL;
|
||
int idx;
|
||
H5G_cache_t *cache = NULL;
|
||
H5G_type_t cache_type;
|
||
void *ret_value = NULL;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_read_real);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
assert(type);
|
||
assert(sequence >= 0);
|
||
|
||
/* can we get it from the symbol table entry? */
|
||
cache = H5G_ent_cache(ent, &cache_type);
|
||
|
||
if (H5O_fast_g[cache_type]) {
|
||
ret_value = (H5O_fast_g[cache_type]) (cache, type, mesg);
|
||
if (ret_value)
|
||
HGOTO_DONE(ret_value);
|
||
H5E_clear(NULL); /*don't care, try reading from header */
|
||
}
|
||
|
||
/* copy the message to the user-supplied buffer */
|
||
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, NULL, NULL, H5AC_READ)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unable to load object header");
|
||
|
||
/* can we get it from the object header? */
|
||
if ((idx = H5O_find_in_ohdr(ent->file, dxpl_id, oh, &type, sequence)) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, NULL, "unable to find message in object header");
|
||
|
||
if (oh->mesg[idx].flags & H5O_FLAG_SHARED) {
|
||
/*
|
||
* If the message is shared then then the native pointer points to an
|
||
* H5O_SHARED message. We use that information to look up the real
|
||
* message in the global heap or some other object header.
|
||
*/
|
||
H5O_shared_t *shared;
|
||
|
||
shared = (H5O_shared_t *)(oh->mesg[idx].native);
|
||
ret_value=H5O_shared_read(ent->file,dxpl_id,shared,type,mesg);
|
||
} else {
|
||
/*
|
||
* The message is not shared, but rather exists in the object
|
||
* header. The object header caches the native message (along with
|
||
* the raw message) so we must copy the native message before
|
||
* returning.
|
||
*/
|
||
if (NULL==(ret_value = (type->copy) (oh->mesg[idx].native, mesg)))
|
||
HGOTO_ERROR (H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy message to user space");
|
||
}
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, NULL, "unable to release object header");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_read_real() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_find_in_ohdr
|
||
*
|
||
* Purpose: Find a message in the object header without consulting
|
||
* a symbol table entry.
|
||
*
|
||
* Return: Success: Index number of message.
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 6 1997
|
||
*
|
||
* Modifications:
|
||
* Robb Matzke, 1999-07-28
|
||
* The ADDR argument is passed by value.
|
||
*
|
||
* Bill Wendling, 2003-09-30
|
||
* Modified so that the object header needs to be AC_protected
|
||
* before calling this function.
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static unsigned
|
||
H5O_find_in_ohdr(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_class_t **type_p, int sequence)
|
||
{
|
||
unsigned u;
|
||
const H5O_class_t *type = NULL;
|
||
unsigned ret_value;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_find_in_ohdr);
|
||
|
||
/* Check args */
|
||
assert(f);
|
||
assert(oh);
|
||
assert(type_p);
|
||
|
||
/* Scan through the messages looking for the right one */
|
||
for (u = 0; u < oh->nmesgs; u++) {
|
||
if (*type_p && (*type_p)->id != oh->mesg[u].type->id)
|
||
continue;
|
||
if (--sequence < 0)
|
||
break;
|
||
}
|
||
|
||
if (sequence >= 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, UFAIL, "unable to find object header message");
|
||
|
||
/*
|
||
* Decode the message if necessary. If the message is shared then decode
|
||
* a shared message, ignoring the message type.
|
||
*/
|
||
if (oh->mesg[u].flags & H5O_FLAG_SHARED) {
|
||
type = H5O_SHARED;
|
||
} else {
|
||
type = oh->mesg[u].type;
|
||
}
|
||
|
||
if (NULL == oh->mesg[u].native) {
|
||
assert(type->decode);
|
||
oh->mesg[u].native = (type->decode) (f, dxpl_id, oh->mesg[u].raw, NULL);
|
||
if (NULL == oh->mesg[u].native)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, UFAIL, "unable to decode message");
|
||
}
|
||
|
||
/*
|
||
* Return the message type. If this is a shared message then return the
|
||
* pointed-to type.
|
||
*/
|
||
*type_p = oh->mesg[u].type;
|
||
|
||
/* Set return value */
|
||
ret_value=u;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_modify
|
||
*
|
||
* Purpose: Modifies an existing message or creates a new message.
|
||
* The cache fields in that symbol table entry ENT are *not*
|
||
* updated, you must do that separately because they often
|
||
* depend on multiple object header messages. Besides, we
|
||
* don't know which messages will be constant and which will
|
||
* not.
|
||
*
|
||
* The OVERWRITE argument is either a sequence number of a
|
||
* message to overwrite (usually zero) or the constant
|
||
* H5O_NEW_MESG (-1) to indicate that a new message is to
|
||
* be created. If the message to overwrite doesn't exist then
|
||
* it is created (but only if it can be inserted so its sequence
|
||
* number is OVERWRITE; that is, you can create a message with
|
||
* the sequence number 5 if there is no message with sequence
|
||
* number 4).
|
||
*
|
||
* The UPDATE_TIME argument is a boolean that allows the caller
|
||
* to skip updating the modification time. This is useful when
|
||
* several calls to H5O_modify will be made in a sequence.
|
||
*
|
||
* Return: Success: The sequence number of the message that
|
||
* was modified or created.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 6 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
* Robb Matzke, 7 Jan 1998
|
||
* Handles constant vs non-constant messages. Once a message is made
|
||
* constant it can never become non-constant. Constant messages cannot
|
||
* be modified.
|
||
*
|
||
* Changed to use IDs for types, instead of type objects, then
|
||
* call "real" routine.
|
||
* Quincey Koziol
|
||
* Feb 14 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
int
|
||
H5O_modify(H5G_entry_t *ent, hid_t type_id, int overwrite,
|
||
unsigned flags, unsigned update_time, const void *mesg, hid_t dxpl_id)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
int ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_modify, FAIL);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert(type);
|
||
assert(mesg);
|
||
assert (0==(flags & ~H5O_FLAG_BITS));
|
||
|
||
/* Call the "real" modify routine */
|
||
if((ret_value= H5O_modify_real(ent, type, overwrite, flags, update_time, mesg, dxpl_id))<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_modify() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_modify_real
|
||
*
|
||
* Purpose: Modifies an existing message or creates a new message.
|
||
* The cache fields in that symbol table entry ENT are *not*
|
||
* updated, you must do that separately because they often
|
||
* depend on multiple object header messages. Besides, we
|
||
* don't know which messages will be constant and which will
|
||
* not.
|
||
*
|
||
* The OVERWRITE argument is either a sequence number of a
|
||
* message to overwrite (usually zero) or the constant
|
||
* H5O_NEW_MESG (-1) to indicate that a new message is to
|
||
* be created. If the message to overwrite doesn't exist then
|
||
* it is created (but only if it can be inserted so its sequence
|
||
* number is OVERWRITE; that is, you can create a message with
|
||
* the sequence number 5 if there is no message with sequence
|
||
* number 4).
|
||
*
|
||
* The UPDATE_TIME argument is a boolean that allows the caller
|
||
* to skip updating the modification time. This is useful when
|
||
* several calls to H5O_modify will be made in a sequence.
|
||
*
|
||
* Return: Success: The sequence number of the message that
|
||
* was modified or created.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 6 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
* Robb Matzke, 7 Jan 1998
|
||
* Handles constant vs non-constant messages. Once a message is made
|
||
* constant it can never become non-constant. Constant messages cannot
|
||
* be modified.
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static int
|
||
H5O_modify_real(H5G_entry_t *ent, const H5O_class_t *type, int overwrite,
|
||
unsigned flags, unsigned update_time, const void *mesg, hid_t dxpl_id)
|
||
{
|
||
H5O_t *oh=NULL;
|
||
int sequence;
|
||
unsigned idx; /* Index of message to modify */
|
||
H5O_mesg_t *idx_msg; /* Pointer to message to modify */
|
||
H5O_shared_t sh_mesg;
|
||
int ret_value;
|
||
|
||
FUNC_ENTER_NOAPI(H5O_modify_real, FAIL);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
assert(type);
|
||
assert(mesg);
|
||
assert (0==(flags & ~H5O_FLAG_BITS));
|
||
|
||
if (0==(ent->file->intent & H5F_ACC_RDWR))
|
||
HGOTO_ERROR (H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file");
|
||
|
||
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, NULL, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
|
||
|
||
/* Count similar messages */
|
||
for (idx = 0, sequence = -1, idx_msg=&oh->mesg[0]; idx < oh->nmesgs; idx++, idx_msg++) {
|
||
if (type->id != idx_msg->type->id)
|
||
continue;
|
||
if (++sequence == overwrite)
|
||
break;
|
||
} /* end for */
|
||
|
||
/* Was the right message found? */
|
||
if (overwrite >= 0 && (idx >= oh->nmesgs || sequence != overwrite)) {
|
||
/* But can we insert a new one with this sequence number? */
|
||
if (overwrite == sequence + 1)
|
||
overwrite = -1;
|
||
else
|
||
HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "message not found");
|
||
} /* end if */
|
||
|
||
/* 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))==UFAIL)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to create new message");
|
||
|
||
/* Set the correct sequence number for the message created */
|
||
sequence++;
|
||
|
||
} else if (oh->mesg[idx].flags & H5O_FLAG_CONSTANT) {
|
||
HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to modify constant message");
|
||
} else if (oh->mesg[idx].flags & H5O_FLAG_SHARED) {
|
||
HGOTO_ERROR (H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to modify shared (constant) message");
|
||
}
|
||
|
||
/* Write the information to the message */
|
||
if(H5O_write_mesg(oh,idx,type,mesg,flags)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to write message");
|
||
|
||
/* Update the modification time message if any */
|
||
if(update_time)
|
||
H5O_touch_oh(ent->file, oh, FALSE);
|
||
|
||
/* Set return value */
|
||
ret_value = sequence;
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_modify_real() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_protect
|
||
*
|
||
* Purpose: Wrapper around H5AC_protect for use during a H5O_protect->
|
||
* H5O_append->...->H5O_append->H5O_unprotect sequence of calls
|
||
* during an object's creation.
|
||
*
|
||
* Return: Success: Pointer to the object header structure for the
|
||
* object.
|
||
*
|
||
* Failure: NULL
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Dec 31 2002
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
H5O_t *
|
||
H5O_protect(H5G_entry_t *ent, hid_t dxpl_id)
|
||
{
|
||
H5O_t *ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_protect, NULL);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
|
||
if (0==(ent->file->intent & H5F_ACC_RDWR))
|
||
HGOTO_ERROR (H5E_OHDR, H5E_WRITEERROR, NULL, "no write intent on file");
|
||
|
||
if (NULL == (ret_value = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, NULL, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unable to load object header");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_protect() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_unprotect
|
||
*
|
||
* Purpose: Wrapper around H5AC_unprotect for use during a H5O_protect->
|
||
* H5O_append->...->H5O_append->H5O_unprotect sequence of calls
|
||
* during an object's creation.
|
||
*
|
||
* Return: Success: Non-negative
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Dec 31 2002
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_unprotect(H5G_entry_t *ent, H5O_t *oh, hid_t dxpl_id)
|
||
{
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_unprotect, FAIL);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
assert(oh);
|
||
|
||
if (H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
oh = NULL;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_unprotect() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_append
|
||
*
|
||
* Purpose: Simplified version of H5O_modify, used when creating a new
|
||
* object header message (usually during object creation)
|
||
*
|
||
* Return: Success: The sequence number of the message that
|
||
* was created.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Dec 31 2002
|
||
*
|
||
* Modifications:
|
||
* Changed to use IDs for types, instead of type objects, then
|
||
* call "real" routine.
|
||
* Quincey Koziol
|
||
* Feb 14 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
int
|
||
H5O_append(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hid_t type_id, unsigned flags,
|
||
const void *mesg)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
int ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_append,FAIL);
|
||
|
||
/* check args */
|
||
assert(f);
|
||
assert(oh);
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert(type);
|
||
assert(0==(flags & ~H5O_FLAG_BITS));
|
||
assert(mesg);
|
||
|
||
/* Call the "real" append routine */
|
||
if((ret_value=H5O_append_real( f, dxpl_id, oh, type, flags, mesg))<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to append to object header");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_append() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_append_real
|
||
*
|
||
* Purpose: Simplified version of H5O_modify, used when creating a new
|
||
* object header message (usually during object creation)
|
||
*
|
||
* Return: Success: The sequence number of the message that
|
||
* was created.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Dec 31 2002
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static int
|
||
H5O_append_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_class_t *type,
|
||
unsigned flags, const void *mesg)
|
||
{
|
||
unsigned idx; /* Index of message to modify */
|
||
H5O_shared_t sh_mesg;
|
||
int ret_value = FAIL;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_append_real);
|
||
|
||
/* check args */
|
||
assert(f);
|
||
assert(oh);
|
||
assert(type);
|
||
assert(0==(flags & ~H5O_FLAG_BITS));
|
||
assert(mesg);
|
||
|
||
/* Create a new message */
|
||
if((idx=H5O_new_mesg(f,oh,&flags,type,mesg,&sh_mesg,&type,&mesg,dxpl_id))==UFAIL)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to create new message");
|
||
|
||
/* Write the information to the message */
|
||
if(H5O_write_mesg(oh,idx,type,mesg,flags)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to write message");
|
||
|
||
/* Set return value */
|
||
ret_value = idx;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_append_real () */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_new_mesg
|
||
*
|
||
* Purpose: Create a new message in an object header
|
||
*
|
||
* Return: Success: Index of message
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Friday, September 3, 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static unsigned
|
||
H5O_new_mesg(H5F_t *f, H5O_t *oh, unsigned *flags, const H5O_class_t *orig_type,
|
||
const void *orig_mesg, H5O_shared_t *sh_mesg, const H5O_class_t **new_type,
|
||
const void **new_mesg, hid_t dxpl_id)
|
||
{
|
||
size_t size; /* Size of space allocated for object header */
|
||
unsigned ret_value=UFAIL; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_new_mesg);
|
||
|
||
/* check args */
|
||
assert(f);
|
||
assert(oh);
|
||
assert(flags);
|
||
assert(orig_type);
|
||
assert(orig_mesg);
|
||
assert(sh_mesg);
|
||
assert(new_mesg);
|
||
assert(new_type);
|
||
|
||
/* Check for shared message */
|
||
if (*flags & H5O_FLAG_SHARED) {
|
||
HDmemset(sh_mesg,0,sizeof(H5O_shared_t));
|
||
|
||
if (NULL==orig_type->get_share)
|
||
HGOTO_ERROR (H5E_OHDR, H5E_UNSUPPORTED, UFAIL, "message class is not sharable");
|
||
if ((orig_type->get_share)(f, orig_mesg, sh_mesg/*out*/)<0) {
|
||
/*
|
||
* If the message isn't shared then turn off the shared bit
|
||
* and treat it as an unshared message.
|
||
*/
|
||
H5E_clear (NULL);
|
||
*flags &= ~H5O_FLAG_SHARED;
|
||
} else {
|
||
/* Change type & message to use shared information */
|
||
*new_type=H5O_SHARED;
|
||
*new_mesg=sh_mesg;
|
||
} /* end else */
|
||
} /* end if */
|
||
else {
|
||
*new_type=orig_type;
|
||
*new_mesg=orig_mesg;
|
||
} /* end else */
|
||
|
||
/* Compute the size needed to store the message on disk */
|
||
if ((size = ((*new_type)->raw_size) (f, *new_mesg)) >=H5O_MAX_SIZE)
|
||
HGOTO_ERROR (H5E_OHDR, H5E_CANTINIT, UFAIL, "object header message is too large (16k max)");
|
||
|
||
/* Allocate space in the object headed for the message */
|
||
if ((ret_value = H5O_alloc(f, oh, orig_type, size)) == UFAIL)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, UFAIL, "unable to allocate space for message");
|
||
|
||
/* Increment any links in message */
|
||
if((*new_type)->link && ((*new_type)->link)(f,dxpl_id,(*new_mesg))<0)
|
||
HGOTO_ERROR (H5E_OHDR, H5E_LINK, UFAIL, "unable to adjust shared object link count");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_new_mesg() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_write_mesg
|
||
*
|
||
* Purpose: Write message to object header
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Friday, September 3, 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_write_mesg(H5O_t *oh, unsigned idx, const H5O_class_t *type,
|
||
const void *mesg, unsigned flags)
|
||
{
|
||
H5O_mesg_t *idx_msg; /* Pointer to message to modify */
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_write_mesg);
|
||
|
||
/* check args */
|
||
assert(oh);
|
||
assert(type);
|
||
assert(mesg);
|
||
|
||
/* Set pointer to the correct message */
|
||
idx_msg=&oh->mesg[idx];
|
||
|
||
/* Reset existing native information */
|
||
H5O_reset_real(type, idx_msg->native);
|
||
|
||
/* Copy the native value for the message */
|
||
if (NULL == (idx_msg->native = (type->copy) (mesg, idx_msg->native)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to copy message to object header");
|
||
|
||
idx_msg->flags = flags;
|
||
idx_msg->dirty = TRUE;
|
||
oh->cache_info.dirty = TRUE;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_write_mesg() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_touch_oh
|
||
*
|
||
* Purpose: If FORCE is non-zero then create a modification time message
|
||
* unless one already exists. Then update any existing
|
||
* modification time message with the current time.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Monday, July 27, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_touch_oh(H5F_t *f, H5O_t *oh, hbool_t force)
|
||
{
|
||
unsigned idx;
|
||
#ifdef H5_HAVE_GETTIMEOFDAY
|
||
struct timeval now_tv;
|
||
#endif /* H5_HAVE_GETTIMEOFDAY */
|
||
time_t now;
|
||
size_t size;
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_touch_oh);
|
||
|
||
assert(oh);
|
||
|
||
/* Look for existing message */
|
||
for (idx=0; idx<oh->nmesgs; idx++) {
|
||
if (H5O_MTIME==oh->mesg[idx].type || H5O_MTIME_NEW==oh->mesg[idx].type)
|
||
break;
|
||
}
|
||
|
||
#ifdef H5_HAVE_GETTIMEOFDAY
|
||
HDgettimeofday(&now_tv,NULL);
|
||
now=now_tv.tv_sec;
|
||
#else /* H5_HAVE_GETTIMEOFDAY */
|
||
now = HDtime(NULL);
|
||
#endif /* H5_HAVE_GETTIMEOFDAY */
|
||
|
||
/* Create a new message */
|
||
if (idx==oh->nmesgs) {
|
||
if (!force)
|
||
HGOTO_DONE(SUCCEED); /*nothing to do*/
|
||
size = (H5O_MTIME_NEW->raw_size)(f, &now);
|
||
if ((idx=H5O_alloc(f, oh, H5O_MTIME_NEW, size))==UFAIL)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for modification time message");
|
||
}
|
||
|
||
/* Update the native part */
|
||
if (NULL==oh->mesg[idx].native) {
|
||
if (NULL==(oh->mesg[idx].native = H5FL_MALLOC(time_t)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "memory allocation failed for modification time message");
|
||
}
|
||
*((time_t*)(oh->mesg[idx].native)) = now;
|
||
oh->mesg[idx].dirty = TRUE;
|
||
oh->cache_info.dirty = TRUE;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_touch
|
||
*
|
||
* Purpose: Touch an object by setting the modification time to the
|
||
* current time and marking the object as dirty. Unless FORCE
|
||
* is non-zero, nothing happens if there is no MTIME message in
|
||
* the object header.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Monday, July 27, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_touch(H5G_entry_t *ent, hbool_t force, hid_t dxpl_id)
|
||
{
|
||
H5O_t *oh = NULL;
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_touch, FAIL);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
if (0==(ent->file->intent & H5F_ACC_RDWR))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file");
|
||
|
||
/* Get the object header */
|
||
if (NULL==(oh=H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, NULL, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
|
||
|
||
/* Create/Update the modification time message */
|
||
if (H5O_touch_oh(ent->file, oh, force)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to update object modificaton time");
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE)<0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
#ifdef H5O_ENABLE_BOGUS
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_bogus_oh
|
||
*
|
||
* Purpose: Create a "bogus" message unless one already exists.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* <koziol@ncsa.uiuc.edu>
|
||
* Tuesday, January 21, 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_bogus_oh(H5F_t *f, H5O_t *oh)
|
||
{
|
||
int idx;
|
||
size_t size;
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER(H5O_bogus_oh, FAIL);
|
||
|
||
assert(f);
|
||
assert(oh);
|
||
|
||
/* Look for existing message */
|
||
for (idx=0; idx<oh->nmesgs; idx++)
|
||
if (H5O_BOGUS==oh->mesg[idx].type)
|
||
break;
|
||
|
||
/* Create a new message */
|
||
if (idx==oh->nmesgs) {
|
||
size = (H5O_BOGUS->raw_size)(f, NULL);
|
||
if ((idx=H5O_alloc(f, oh, H5O_BOGUS, size))<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for 'bogus' message");
|
||
|
||
/* Allocate the native message in memory */
|
||
if (NULL==(oh->mesg[idx].native = H5MM_malloc(sizeof(H5O_bogus_t))))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "memory allocation failed for 'bogus' message");
|
||
|
||
/* Update the native part */
|
||
((H5O_bogus_t *)(oh->mesg[idx].native))->u = H5O_BOGUS_VALUE;
|
||
|
||
/* Mark the message and object header as dirty */
|
||
oh->mesg[idx].dirty = TRUE;
|
||
oh->dirty = TRUE;
|
||
} /* end if */
|
||
|
||
done:
|
||
FUNC_LEAVE(ret_value);
|
||
} /* end H5O_bogus_oh() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_bogus
|
||
*
|
||
* Purpose: Create a "bogus" message in an object.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* <koziol@ncsa.uiuc.edu>
|
||
* Tuesday, January 21, 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_bogus(H5G_entry_t *ent, hid_t dxpl_id)
|
||
{
|
||
H5O_t *oh = NULL;
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER(H5O_bogus, FAIL);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
|
||
/* Verify write access to the file */
|
||
if (0==(ent->file->intent & H5F_ACC_RDWR))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file");
|
||
|
||
/* Get the object header */
|
||
if (NULL==(oh=H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, NULL, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
|
||
|
||
/* Create the "bogus" message */
|
||
if (H5O_bogus_oh(ent->file, oh)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to update object 'bogus' message");
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE)<0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
FUNC_LEAVE(ret_value);
|
||
} /* end H5O_bogus() */
|
||
#endif /* H5O_ENABLE_BOGUS */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_remove
|
||
*
|
||
* Purpose: Removes the specified message from the object header.
|
||
* If sequence is H5O_ALL (-1) then all messages of the
|
||
* specified type are removed. Removing a message causes
|
||
* the sequence numbers to change for subsequent messages of
|
||
* the same type.
|
||
*
|
||
* No attempt is made to join adjacent free areas of the
|
||
* object header into a single larger free area.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 28 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
* Robb Matzke, 7 Jan 1998
|
||
* Does not remove constant messages.
|
||
*
|
||
* Changed to use IDs for types, instead of type objects, then
|
||
* call "real" routine.
|
||
* Quincey Koziol
|
||
* Feb 14 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_remove(H5G_entry_t *ent, hid_t type_id, int sequence, hid_t dxpl_id)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
herr_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_remove, FAIL);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert(type);
|
||
|
||
/* Call the "real" remove routine */
|
||
if((ret_value=H5O_remove_real(ent, type, sequence, dxpl_id))<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove object header message");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_remove() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_remove_real
|
||
*
|
||
* Purpose: Removes the specified message from the object header.
|
||
* If sequence is H5O_ALL (-1) then all messages of the
|
||
* specified type are removed. Removing a message causes
|
||
* the sequence numbers to change for subsequent messages of
|
||
* the same type.
|
||
*
|
||
* No attempt is made to join adjacent free areas of the
|
||
* object header into a single larger free area.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 28 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
* Robb Matzke, 7 Jan 1998
|
||
* Does not remove constant messages.
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_remove_real(H5G_entry_t *ent, const H5O_class_t *type, int sequence, hid_t dxpl_id)
|
||
{
|
||
H5O_t *oh = NULL;
|
||
H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
|
||
int seq, nfailed = 0;
|
||
unsigned u;
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_remove_real);
|
||
|
||
/* check args */
|
||
assert(ent);
|
||
assert(ent->file);
|
||
assert(H5F_addr_defined(ent->header));
|
||
assert(type);
|
||
|
||
if (0==(ent->file->intent & H5F_ACC_RDWR))
|
||
HGOTO_ERROR (H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file");
|
||
|
||
/* load the object header */
|
||
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, NULL, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
|
||
|
||
for (u = seq = 0, curr_msg=&oh->mesg[0]; u < oh->nmesgs; u++,curr_msg++) {
|
||
if (type->id != curr_msg->type->id)
|
||
continue;
|
||
if (seq++ == sequence || H5O_ALL == sequence) {
|
||
|
||
/*
|
||
* Keep track of how many times we failed trying to remove constant
|
||
* messages.
|
||
*/
|
||
if (curr_msg->flags & H5O_FLAG_CONSTANT) {
|
||
nfailed++;
|
||
continue;
|
||
} /* end if */
|
||
|
||
/* Free any space referred to in the file from this message */
|
||
if(H5O_delete_mesg(ent->file,dxpl_id,curr_msg)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message");
|
||
|
||
/* change message type to nil and zero it */
|
||
curr_msg->type = H5O_NULL;
|
||
HDmemset(curr_msg->raw, 0, curr_msg->raw_size);
|
||
if(curr_msg->flags & H5O_FLAG_SHARED)
|
||
curr_msg->native = H5O_free_real(H5O_SHARED, curr_msg->native);
|
||
else
|
||
curr_msg->native = H5O_free_real(type, curr_msg->native);
|
||
curr_msg->dirty = TRUE;
|
||
oh->cache_info.dirty = TRUE;
|
||
H5O_touch_oh(ent->file, oh, FALSE);
|
||
}
|
||
}
|
||
|
||
/* Fail if we tried to remove any constant messages */
|
||
if (nfailed)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to remove constant message(s)");
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_remove_real() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_alloc_extend_chunk
|
||
*
|
||
* Purpose: Extends a chunk which hasn't been allocated on disk yet
|
||
* to make the chunk large enough to contain a message whose
|
||
* data size is exactly SIZE bytes (SIZE need not be aligned).
|
||
*
|
||
* If the last message of the chunk is the null message, then
|
||
* that message will be extended with the chunk. Otherwise a
|
||
* new null message is created.
|
||
*
|
||
* Return: Success: Message index for null message which
|
||
* is large enough to hold SIZE bytes.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 7 1997
|
||
*
|
||
* Modifications:
|
||
* Robb Matzke, 1999-08-26
|
||
* If new memory is allocated as a multiple of some alignment
|
||
* then we're careful to initialize the part of the new memory
|
||
* from the end of the expected message to the end of the new
|
||
* memory.
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static unsigned
|
||
H5O_alloc_extend_chunk(H5O_t *oh, unsigned chunkno, size_t size)
|
||
{
|
||
unsigned u;
|
||
unsigned idx;
|
||
size_t delta, old_size;
|
||
size_t aligned_size = H5O_ALIGN(size);
|
||
uint8_t *old_addr;
|
||
unsigned ret_value;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_extend_chunk);
|
||
|
||
/* check args */
|
||
assert(oh);
|
||
assert(chunkno < oh->nchunks);
|
||
assert(size > 0);
|
||
|
||
if (H5F_addr_defined(oh->chunk[chunkno].addr))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, UFAIL, "chunk is on disk");
|
||
|
||
/* try to extend a null message */
|
||
for (idx=0; idx<oh->nmesgs; idx++) {
|
||
if (oh->mesg[idx].chunkno==chunkno) {
|
||
if ( H5O_NULL_ID == oh->mesg[idx].type->id &&
|
||
(oh->mesg[idx].raw + oh->mesg[idx].raw_size ==
|
||
oh->chunk[chunkno].image + oh->chunk[chunkno].size)) {
|
||
|
||
delta = MAX (H5O_MIN_SIZE, aligned_size - oh->mesg[idx].raw_size);
|
||
assert (delta=H5O_ALIGN (delta));
|
||
oh->mesg[idx].dirty = TRUE;
|
||
oh->mesg[idx].raw_size += delta;
|
||
|
||
old_addr = oh->chunk[chunkno].image;
|
||
|
||
/* Be careful not to indroduce garbage */
|
||
oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image,old_addr,
|
||
(oh->chunk[chunkno].size + delta));
|
||
if (NULL==oh->chunk[chunkno].image)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
|
||
HDmemset(oh->chunk[chunkno].image + oh->chunk[chunkno].size,
|
||
0, delta);
|
||
oh->chunk[chunkno].size += delta;
|
||
|
||
/* adjust raw addresses for messages of this chunk */
|
||
if (old_addr != oh->chunk[chunkno].image) {
|
||
for (u = 0; u < oh->nmesgs; u++) {
|
||
if (oh->mesg[u].chunkno == chunkno)
|
||
oh->mesg[u].raw = oh->chunk[chunkno].image +
|
||
(oh->mesg[u].raw - old_addr);
|
||
}
|
||
}
|
||
HGOTO_DONE(idx);
|
||
}
|
||
} /* end if */
|
||
}
|
||
|
||
/* create a new null message */
|
||
if (oh->nmesgs >= oh->alloc_nmesgs) {
|
||
unsigned na = oh->alloc_nmesgs + H5O_NMESGS;
|
||
H5O_mesg_t *x = H5FL_ARR_REALLOC (H5O_mesg_t, oh->mesg, na);
|
||
|
||
if (NULL==x)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
|
||
oh->alloc_nmesgs = na;
|
||
oh->mesg = x;
|
||
}
|
||
delta = MAX(H5O_MIN_SIZE, aligned_size+H5O_SIZEOF_MSGHDR(f));
|
||
delta = H5O_ALIGN(delta);
|
||
idx = oh->nmesgs++;
|
||
oh->mesg[idx].type = H5O_NULL;
|
||
oh->mesg[idx].dirty = TRUE;
|
||
oh->mesg[idx].native = NULL;
|
||
oh->mesg[idx].raw = oh->chunk[chunkno].image +
|
||
oh->chunk[chunkno].size +
|
||
H5O_SIZEOF_MSGHDR(f);
|
||
oh->mesg[idx].raw_size = delta - H5O_SIZEOF_MSGHDR(f);
|
||
oh->mesg[idx].chunkno = chunkno;
|
||
|
||
old_addr = oh->chunk[chunkno].image;
|
||
old_size = oh->chunk[chunkno].size;
|
||
oh->chunk[chunkno].size += delta;
|
||
oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image,old_addr,
|
||
oh->chunk[chunkno].size);
|
||
if (NULL==oh->chunk[chunkno].image)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
|
||
HDmemset(oh->chunk[chunkno].image+old_size, 0,
|
||
oh->chunk[chunkno].size - old_size);
|
||
|
||
/* adjust raw addresses for messages of this chunk */
|
||
if (old_addr != oh->chunk[chunkno].image) {
|
||
for (u = 0; u < oh->nmesgs; u++) {
|
||
if (oh->mesg[u].chunkno == chunkno)
|
||
oh->mesg[u].raw = oh->chunk[chunkno].image +
|
||
(oh->mesg[u].raw - old_addr);
|
||
}
|
||
}
|
||
|
||
/* Set return value */
|
||
ret_value=idx;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_alloc_new_chunk
|
||
*
|
||
* Purpose: Allocates a new chunk for the object header but doen't
|
||
* give the new chunk a file address yet. One of the other
|
||
* chunks will get an object continuation message. If there
|
||
* isn't room in any other chunk for the object continuation
|
||
* message, then some message from another chunk is moved into
|
||
* this chunk to make room.
|
||
*
|
||
* SIZE need not be aligned.
|
||
*
|
||
* Return: Success: Index number of the null message for the
|
||
* new chunk. The null message will be at
|
||
* least SIZE bytes not counting the message
|
||
* ID or size fields.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 7 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static unsigned
|
||
H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size)
|
||
{
|
||
size_t cont_size; /*continuation message size */
|
||
int found_null = (-1); /*best fit null message */
|
||
int found_other = (-1); /*best fit other message */
|
||
unsigned idx; /*message number */
|
||
uint8_t *p = NULL; /*ptr into new chunk */
|
||
H5O_cont_t *cont = NULL; /*native continuation message */
|
||
int chunkno;
|
||
unsigned u;
|
||
unsigned ret_value; /*return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_new_chunk);
|
||
|
||
/* check args */
|
||
assert (oh);
|
||
assert (size > 0);
|
||
size = H5O_ALIGN(size);
|
||
|
||
/*
|
||
* Find the smallest null message that will hold an object
|
||
* continuation message. Failing that, find the smallest message
|
||
* that could be moved to make room for the continuation message.
|
||
* Don't ever move continuation message from one chunk to another.
|
||
*/
|
||
cont_size = H5O_ALIGN (H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f));
|
||
for (u=0; u<oh->nmesgs; u++) {
|
||
if (H5O_NULL_ID == oh->mesg[u].type->id) {
|
||
if (cont_size == oh->mesg[u].raw_size) {
|
||
found_null = u;
|
||
break;
|
||
} else if (oh->mesg[u].raw_size >= cont_size &&
|
||
(found_null < 0 ||
|
||
(oh->mesg[u].raw_size <
|
||
oh->mesg[found_null].raw_size))) {
|
||
found_null = u;
|
||
}
|
||
} else if (H5O_CONT_ID == oh->mesg[u].type->id) {
|
||
/*don't consider continuation messages */
|
||
} else if (oh->mesg[u].raw_size >= cont_size &&
|
||
(found_other < 0 ||
|
||
oh->mesg[u].raw_size < oh->mesg[found_other].raw_size)) {
|
||
found_other = u;
|
||
}
|
||
}
|
||
assert(found_null >= 0 || found_other >= 0);
|
||
|
||
/*
|
||
* If we must move some other message to make room for the null
|
||
* message, then make sure the new chunk has enough room for that
|
||
* other message.
|
||
*/
|
||
if (found_null < 0)
|
||
size += H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
|
||
|
||
/*
|
||
* The total chunk size must include the requested space plus enough
|
||
* for the message header. This must be at least some minimum and a
|
||
* multiple of the alignment size.
|
||
*/
|
||
size = MAX(H5O_MIN_SIZE, size + H5O_SIZEOF_MSGHDR(f));
|
||
assert (size == H5O_ALIGN (size));
|
||
|
||
/*
|
||
* Create the new chunk without giving it a file address.
|
||
*/
|
||
if (oh->nchunks >= oh->alloc_nchunks) {
|
||
unsigned na = oh->alloc_nchunks + H5O_NCHUNKS;
|
||
H5O_chunk_t *x = H5FL_ARR_REALLOC (H5O_chunk_t, oh->chunk, na);
|
||
|
||
if (!x)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
|
||
oh->alloc_nchunks = na;
|
||
oh->chunk = x;
|
||
}
|
||
chunkno = oh->nchunks++;
|
||
oh->chunk[chunkno].dirty = TRUE;
|
||
oh->chunk[chunkno].addr = HADDR_UNDEF;
|
||
oh->chunk[chunkno].size = size;
|
||
if (NULL==(oh->chunk[chunkno].image = p = H5FL_BLK_CALLOC(chunk_image,size)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
|
||
|
||
/*
|
||
* Make sure we have enough space for all possible new messages
|
||
* that could be generated below.
|
||
*/
|
||
if (oh->nmesgs + 3 > oh->alloc_nmesgs) {
|
||
int old_alloc=oh->alloc_nmesgs;
|
||
unsigned na = oh->alloc_nmesgs + MAX (H5O_NMESGS, 3);
|
||
H5O_mesg_t *x = H5FL_ARR_REALLOC (H5O_mesg_t, oh->mesg, na);
|
||
|
||
if (!x)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
|
||
oh->alloc_nmesgs = na;
|
||
oh->mesg = x;
|
||
|
||
/* Set new object header info to zeros */
|
||
HDmemset(&oh->mesg[old_alloc], 0,
|
||
(oh->alloc_nmesgs-old_alloc)*sizeof(H5O_mesg_t));
|
||
}
|
||
|
||
/*
|
||
* Describe the messages of the new chunk.
|
||
*/
|
||
if (found_null < 0) {
|
||
found_null = u = oh->nmesgs++;
|
||
oh->mesg[u].type = H5O_NULL;
|
||
oh->mesg[u].dirty = TRUE;
|
||
oh->mesg[u].native = NULL;
|
||
oh->mesg[u].raw = oh->mesg[found_other].raw;
|
||
oh->mesg[u].raw_size = oh->mesg[found_other].raw_size;
|
||
oh->mesg[u].chunkno = oh->mesg[found_other].chunkno;
|
||
|
||
oh->mesg[found_other].dirty = TRUE;
|
||
/* Copy the message to the new location */
|
||
HDmemcpy(p+H5O_SIZEOF_MSGHDR(f),oh->mesg[found_other].raw,oh->mesg[found_other].raw_size);
|
||
oh->mesg[found_other].raw = p + H5O_SIZEOF_MSGHDR(f);
|
||
oh->mesg[found_other].chunkno = chunkno;
|
||
p += H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
|
||
size -= H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
|
||
}
|
||
idx = oh->nmesgs++;
|
||
oh->mesg[idx].type = H5O_NULL;
|
||
oh->mesg[idx].dirty = TRUE;
|
||
oh->mesg[idx].native = NULL;
|
||
oh->mesg[idx].raw = p + H5O_SIZEOF_MSGHDR(f);
|
||
oh->mesg[idx].raw_size = size - H5O_SIZEOF_MSGHDR(f);
|
||
oh->mesg[idx].chunkno = chunkno;
|
||
|
||
/*
|
||
* If the null message that will receive the continuation message
|
||
* is larger than the continuation message, then split it into
|
||
* two null messages.
|
||
*/
|
||
if (oh->mesg[found_null].raw_size > cont_size) {
|
||
u = oh->nmesgs++;
|
||
oh->mesg[u].type = H5O_NULL;
|
||
oh->mesg[u].dirty = TRUE;
|
||
oh->mesg[u].native = NULL;
|
||
oh->mesg[u].raw = oh->mesg[found_null].raw +
|
||
cont_size +
|
||
H5O_SIZEOF_MSGHDR(f);
|
||
oh->mesg[u].raw_size = oh->mesg[found_null].raw_size -
|
||
(cont_size + H5O_SIZEOF_MSGHDR(f));
|
||
oh->mesg[u].chunkno = oh->mesg[found_null].chunkno;
|
||
|
||
oh->mesg[found_null].dirty = TRUE;
|
||
oh->mesg[found_null].raw_size = cont_size;
|
||
}
|
||
|
||
/*
|
||
* Initialize the continuation message.
|
||
*/
|
||
oh->mesg[found_null].type = H5O_CONT;
|
||
oh->mesg[found_null].dirty = TRUE;
|
||
if (NULL==(cont = H5MM_calloc(sizeof(H5O_cont_t))))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
|
||
cont->addr = HADDR_UNDEF;
|
||
cont->size = 0;
|
||
cont->chunkno = chunkno;
|
||
oh->mesg[found_null].native = cont;
|
||
|
||
/* Set return value */
|
||
ret_value=idx;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_alloc
|
||
*
|
||
* Purpose: Allocate enough space in the object header for this message.
|
||
*
|
||
* Return: Success: Index of message
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 6 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static unsigned
|
||
H5O_alloc(H5F_t *f, H5O_t *oh, const H5O_class_t *type, size_t size)
|
||
{
|
||
unsigned idx;
|
||
H5O_mesg_t *msg; /* Pointer to newly allocated message */
|
||
size_t aligned_size = H5O_ALIGN(size);
|
||
unsigned ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_alloc);
|
||
|
||
/* check args */
|
||
assert (oh);
|
||
assert (type);
|
||
|
||
/* look for a null message which is large enough */
|
||
for (idx = 0; idx < oh->nmesgs; idx++) {
|
||
if (H5O_NULL_ID == oh->mesg[idx].type->id &&
|
||
oh->mesg[idx].raw_size >= aligned_size)
|
||
break;
|
||
}
|
||
|
||
#ifdef LATER
|
||
/*
|
||
* Perhaps if we join adjacent null messages we could make one
|
||
* large enough... we leave this as an exercise for future
|
||
* programmers :-) This isn't a high priority because when an
|
||
* object header is read from disk the null messages are combined
|
||
* anyway.
|
||
*/
|
||
#endif
|
||
|
||
/* if we didn't find one, then allocate more header space */
|
||
if (idx >= oh->nmesgs) {
|
||
unsigned chunkno;
|
||
|
||
/*
|
||
* Look for a chunk which hasn't had disk space allocated yet
|
||
* since we can just increase the size of that chunk.
|
||
*/
|
||
for (chunkno = 0; chunkno < oh->nchunks; chunkno++) {
|
||
if ((idx = H5O_alloc_extend_chunk(oh, chunkno, size)) != UFAIL) {
|
||
break;
|
||
}
|
||
H5E_clear(NULL);
|
||
}
|
||
|
||
/*
|
||
* Create a new chunk
|
||
*/
|
||
if (idx == UFAIL) {
|
||
if ((idx = H5O_alloc_new_chunk(f, oh, size)) == UFAIL)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, UFAIL, "unable to create a new object header data chunk");
|
||
}
|
||
}
|
||
|
||
/* Set pointer to newly allocated message */
|
||
msg=&oh->mesg[idx];
|
||
|
||
/* do we need to split the null message? */
|
||
if (msg->raw_size > aligned_size) {
|
||
H5O_mesg_t *null_msg; /* Pointer to null message */
|
||
size_t mesg_size = aligned_size+ H5O_SIZEOF_MSGHDR(f); /* Total size of newly allocated message */
|
||
|
||
assert(msg->raw_size - aligned_size >= H5O_SIZEOF_MSGHDR(f));
|
||
|
||
if (oh->nmesgs >= oh->alloc_nmesgs) {
|
||
int old_alloc=oh->alloc_nmesgs;
|
||
unsigned na = oh->alloc_nmesgs + H5O_NMESGS;
|
||
H5O_mesg_t *x = H5FL_ARR_REALLOC (H5O_mesg_t, oh->mesg, na);
|
||
|
||
if (!x)
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
|
||
oh->alloc_nmesgs = na;
|
||
oh->mesg = x;
|
||
|
||
/* Set new object header info to zeros */
|
||
HDmemset(&oh->mesg[old_alloc],0,
|
||
(oh->alloc_nmesgs-old_alloc)*sizeof(H5O_mesg_t));
|
||
|
||
/* "Retarget" local 'msg' pointer into newly allocated array of messages */
|
||
msg=&oh->mesg[idx];
|
||
}
|
||
null_msg=&oh->mesg[oh->nmesgs++];
|
||
null_msg->type = H5O_NULL;
|
||
null_msg->dirty = TRUE;
|
||
null_msg->native = NULL;
|
||
null_msg->raw = msg->raw + mesg_size;
|
||
null_msg->raw_size = msg->raw_size - mesg_size;
|
||
null_msg->chunkno = msg->chunkno;
|
||
msg->raw_size = aligned_size;
|
||
}
|
||
|
||
/* initialize the new message */
|
||
msg->type = type;
|
||
msg->dirty = TRUE;
|
||
msg->native = NULL;
|
||
|
||
oh->cache_info.dirty = TRUE;
|
||
|
||
/* Set return value */
|
||
ret_value=idx;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
|
||
#ifdef NOT_YET
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_share
|
||
*
|
||
* Purpose: Writes a message to the global heap.
|
||
*
|
||
* Return: Success: Non-negative, and HOBJ describes the global heap
|
||
* object.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Thursday, April 2, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_share (H5F_t *f, hid_t dxpl_id, const H5O_class_t *type, const void *mesg,
|
||
H5HG_t *hobj/*out*/)
|
||
{
|
||
size_t size;
|
||
void *buf = NULL;
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_share);
|
||
|
||
/* Check args */
|
||
assert (f);
|
||
assert (type);
|
||
assert (mesg);
|
||
assert (hobj);
|
||
|
||
/* Encode the message put it in the global heap */
|
||
if ((size = (type->raw_size)(f, mesg))>0) {
|
||
if (NULL==(buf = H5MM_malloc (size)))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
|
||
if ((type->encode)(f, buf, mesg)<0)
|
||
HGOTO_ERROR (H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode message");
|
||
if (H5HG_insert (f, dxpl_id, size, buf, hobj)<0)
|
||
HGOTO_ERROR (H5E_OHDR, H5E_CANTINIT, FAIL, "unable to store message in global heap");
|
||
}
|
||
|
||
done:
|
||
if(buf)
|
||
H5MM_xfree (buf);
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|
||
#endif /* NOT_YET */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_raw_size
|
||
*
|
||
* Purpose: Call the 'raw_size' method for a
|
||
* particular class of object header.
|
||
*
|
||
* Return: Size of message on success, 0 on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Feb 13 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
size_t
|
||
H5O_raw_size(hid_t type_id, H5F_t *f, const void *mesg)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
size_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_raw_size,0);
|
||
|
||
/* Check args */
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert (type);
|
||
assert (type->raw_size);
|
||
assert (f);
|
||
assert (mesg);
|
||
|
||
/* Compute the raw data size for the mesg */
|
||
if ((ret_value = (type->raw_size)(f, mesg))==0)
|
||
HGOTO_ERROR (H5E_OHDR, H5E_CANTCOUNT, 0, "unable to determine size of message");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_raw_size() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_get_share
|
||
*
|
||
* Purpose: Call the 'get_share' method for a
|
||
* particular class of object header.
|
||
*
|
||
* Return: Success: Non-negative, and SHARE describes the shared
|
||
* object.
|
||
*
|
||
* Failure: Negative
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Oct 2 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_get_share(hid_t type_id, H5F_t *f, const void *mesg, H5O_shared_t *share)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
herr_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_get_share,FAIL);
|
||
|
||
/* Check args */
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert (type);
|
||
assert (type->get_share);
|
||
assert (f);
|
||
assert (mesg);
|
||
assert (share);
|
||
|
||
/* Compute the raw data size for the mesg */
|
||
if ((ret_value = (type->get_share)(f, mesg, share))<0)
|
||
HGOTO_ERROR (H5E_OHDR, H5E_CANTGET, FAIL, "unable to retrieve shared message information");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_get_share() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_delete
|
||
*
|
||
* Purpose: Delete an object header from a file. This frees the file
|
||
* space used for the object header (and it's continuation blocks)
|
||
* and also walks through each header message and asks it to
|
||
* remove all the pieces of the file referenced by the header.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Mar 19 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr)
|
||
{
|
||
H5O_t *oh=NULL; /* Object header information */
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_delete,FAIL);
|
||
|
||
/* Check args */
|
||
assert (f);
|
||
assert(H5F_addr_defined(addr));
|
||
|
||
/* Get the object header information */
|
||
if (NULL == (oh = H5AC_protect(f, dxpl_id, H5AC_OHDR, addr, NULL, NULL, H5AC_WRITE)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
|
||
|
||
/* Delete object */
|
||
if(H5O_delete_oh(f,dxpl_id,oh)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file");
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, TRUE)<0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_delete() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_delete_oh
|
||
*
|
||
* Purpose: Internal function to:
|
||
* Delete an object header from a file. This frees the file
|
||
* space used for the object header (and it's continuation blocks)
|
||
* and also walks through each header message and asks it to
|
||
* remove all the pieces of the file referenced by the header.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Mar 19 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_delete_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh)
|
||
{
|
||
H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
|
||
H5O_chunk_t *curr_chk; /* Pointer to current chunk being operated on */
|
||
unsigned u;
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_delete_oh);
|
||
|
||
/* Check args */
|
||
assert (f);
|
||
assert (oh);
|
||
|
||
/* Walk through the list of object header messages, asking each one to
|
||
* delete any file space used
|
||
*/
|
||
for (u = 0, curr_msg=&oh->mesg[0]; u < oh->nmesgs; u++,curr_msg++) {
|
||
/* Free any space referred to in the file from this message */
|
||
if(H5O_delete_mesg(f,dxpl_id,curr_msg)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message");
|
||
} /* end for */
|
||
|
||
/* Free all the chunks for the object header */
|
||
for (u = 0, curr_chk=&oh->chunk[0]; u < oh->nchunks; u++,curr_chk++) {
|
||
haddr_t chk_addr; /* Actual address of chunk */
|
||
hsize_t chk_size; /* Actual size of chunk */
|
||
|
||
if(u==0) {
|
||
chk_addr = curr_chk->addr - H5O_SIZEOF_HDR(f);
|
||
chk_size = curr_chk->size + H5O_SIZEOF_HDR(f);
|
||
} /* end if */
|
||
else {
|
||
chk_addr = curr_chk->addr;
|
||
chk_size = curr_chk->size;
|
||
} /* end else */
|
||
|
||
/* Free the file space for the chunk */
|
||
if (H5MF_xfree(f, H5FD_MEM_OHDR, dxpl_id, chk_addr, chk_size)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free object header");
|
||
} /* end for */
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_delete_oh() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_delete_mesg
|
||
*
|
||
* Purpose: Internal function to:
|
||
* Delete an object header message from a file. This frees the file
|
||
* space used for anything referred to in the object header message.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* September 26 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5O_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_mesg_t *mesg)
|
||
{
|
||
const H5O_class_t *type; /* Type of object to free */
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT(H5O_delete_mesg);
|
||
|
||
/* Check args */
|
||
assert (f);
|
||
assert (mesg);
|
||
|
||
/* Get the message to free's type */
|
||
if(mesg->flags & H5O_FLAG_SHARED)
|
||
type=H5O_SHARED;
|
||
else
|
||
type = mesg->type;
|
||
|
||
/* Check if there is a file space deletion callback for this type of message */
|
||
if(type->del) {
|
||
/*
|
||
* Decode the message if necessary.
|
||
*/
|
||
if (NULL == mesg->native) {
|
||
assert(type->decode);
|
||
mesg->native = (type->decode) (f, dxpl_id, mesg->raw, NULL);
|
||
if (NULL == mesg->native)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode message");
|
||
} /* end if */
|
||
|
||
if ((type->del)(f, dxpl_id, mesg->native)<0)
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message");
|
||
} /* end if */
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_delete_msg() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_get_info
|
||
*
|
||
* Purpose: Retrieve information about an object header
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Oct 7 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_get_info(H5G_entry_t *ent, H5O_stat_t *ostat, hid_t dxpl_id)
|
||
{
|
||
H5O_t *oh=NULL; /* Object header information */
|
||
H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
|
||
hsize_t total_size; /* Total amount of space used in file */
|
||
hsize_t free_space; /* Free space in object header */
|
||
unsigned u; /* Local index variable */
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_get_info,FAIL);
|
||
|
||
/* Check args */
|
||
assert (ent);
|
||
assert (ostat);
|
||
|
||
/* Get the object header information */
|
||
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, NULL, NULL, H5AC_READ)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
|
||
|
||
/* Iterate over all the messages, accumulating the total size & free space */
|
||
total_size=H5O_SIZEOF_HDR(ent->file);
|
||
free_space=0;
|
||
for (u = 0, curr_msg=&oh->mesg[0]; u < oh->nmesgs; u++,curr_msg++) {
|
||
/* Accumulate the size for this message */
|
||
total_size+= H5O_SIZEOF_MSGHDR(ent->file) + curr_msg->raw_size;
|
||
|
||
/* Check for this message being free space */
|
||
if (H5O_NULL_ID == curr_msg->type->id)
|
||
free_space+= H5O_SIZEOF_MSGHDR(ent->file) + curr_msg->raw_size;
|
||
} /* end for */
|
||
|
||
/* Set the information for this object header */
|
||
ostat->size=total_size;
|
||
ostat->free=free_space;
|
||
ostat->nmesgs=oh->nmesgs;
|
||
ostat->nchunks=oh->nchunks;
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE)<0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_get_info() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_debug_id
|
||
*
|
||
* Purpose: Act as a proxy for calling the 'debug' method for a
|
||
* particular class of object header.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* koziol@ncsa.uiuc.edu
|
||
* Feb 13 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_debug_id(hid_t type_id, H5F_t *f, hid_t dxpl_id, const void *mesg, FILE *stream, int indent, int fwidth)
|
||
{
|
||
const H5O_class_t *type; /* Actual H5O class type for the ID */
|
||
herr_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5O_debug_id,FAIL);
|
||
|
||
/* Check args */
|
||
assert(type_id>=0 && type_id<(hid_t)(sizeof(message_type_g)/sizeof(message_type_g[0])));
|
||
type=message_type_g[type_id]; /* map the type ID to the actual type object */
|
||
assert(type);
|
||
assert(type->debug);
|
||
assert(f);
|
||
assert(mesg);
|
||
assert(stream);
|
||
assert(indent >= 0);
|
||
assert(fwidth >= 0);
|
||
|
||
/* Call the debug method in the class */
|
||
if ((ret_value = (type->debug)(f, dxpl_id, mesg, stream, indent, fwidth))<0)
|
||
HGOTO_ERROR (H5E_OHDR, H5E_BADTYPE, FAIL, "unable to debug message");
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5O_debug_id() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5O_debug
|
||
*
|
||
* Purpose: Prints debugging info about an object header.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* matzke@llnl.gov
|
||
* Aug 6 1997
|
||
*
|
||
* Modifications:
|
||
* Robb Matzke, 1999-07-28
|
||
* The ADDR argument is passed by value.
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth)
|
||
{
|
||
H5O_t *oh = NULL;
|
||
unsigned i, chunkno;
|
||
size_t mesg_total = 0, chunk_total = 0;
|
||
int *sequence;
|
||
haddr_t tmp_addr;
|
||
herr_t ret_value = SUCCEED;
|
||
void *(*decode)(H5F_t*, hid_t, const uint8_t*, H5O_shared_t*);
|
||
herr_t (*debug)(H5F_t*, hid_t, const void*, FILE*, int, int)=NULL;
|
||
|
||
FUNC_ENTER_NOAPI(H5O_debug, FAIL);
|
||
|
||
/* check args */
|
||
assert(f);
|
||
assert(H5F_addr_defined(addr));
|
||
assert(stream);
|
||
assert(indent >= 0);
|
||
assert(fwidth >= 0);
|
||
|
||
if (NULL == (oh = H5AC_protect(f, dxpl_id, H5AC_OHDR, addr, NULL, NULL, H5AC_READ)))
|
||
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
|
||
|
||
/* debug */
|
||
HDfprintf(stream, "%*sObject Header...\n", indent, "");
|
||
|
||
HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth,
|
||
"Dirty:",
|
||
(int) (oh->cache_info.dirty));
|
||
HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth,
|
||
"Version:",
|
||
(int) (oh->version));
|
||
HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
|
||
"Header size (in bytes):",
|
||
(unsigned) H5O_SIZEOF_HDR(f));
|
||
HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth,
|
||
"Number of links:",
|
||
(int) (oh->nlink));
|
||
HDfprintf(stream, "%*s%-*s %u (%u)\n", indent, "", fwidth,
|
||
"Number of messages (allocated):",
|
||
(unsigned) (oh->nmesgs), (unsigned) (oh->alloc_nmesgs));
|
||
HDfprintf(stream, "%*s%-*s %u (%u)\n", indent, "", fwidth,
|
||
"Number of chunks (allocated):",
|
||
(unsigned) (oh->nchunks), (unsigned) (oh->alloc_nchunks));
|
||
|
||
/* debug each chunk */
|
||
for (i=0, chunk_total=0; i<oh->nchunks; i++) {
|
||
chunk_total += oh->chunk[i].size;
|
||
HDfprintf(stream, "%*sChunk %d...\n", indent, "", i);
|
||
|
||
HDfprintf(stream, "%*s%-*s %d\n", indent + 3, "", MAX(0, fwidth - 3),
|
||
"Dirty:",
|
||
(int) (oh->chunk[i].dirty));
|
||
|
||
HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", MAX(0, fwidth - 3),
|
||
"Address:", oh->chunk[i].addr);
|
||
|
||
tmp_addr = addr + (hsize_t)H5O_SIZEOF_HDR(f);
|
||
if (0 == i && H5F_addr_ne(oh->chunk[i].addr, tmp_addr))
|
||
HDfprintf(stream, "*** WRONG ADDRESS!\n");
|
||
HDfprintf(stream, "%*s%-*s %lu\n", indent + 3, "", MAX(0, fwidth - 3),
|
||
"Size in bytes:",
|
||
(unsigned long) (oh->chunk[i].size));
|
||
}
|
||
|
||
/* debug each message */
|
||
if (NULL==(sequence = H5MM_calloc(NELMTS(message_type_g)*sizeof(int))))
|
||
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
|
||
for (i=0, mesg_total=0; i<oh->nmesgs; i++) {
|
||
mesg_total += H5O_SIZEOF_MSGHDR(f) + oh->mesg[i].raw_size;
|
||
HDfprintf(stream, "%*sMessage %d...\n", indent, "", i);
|
||
|
||
/* check for bad message id */
|
||
if (oh->mesg[i].type->id < 0 ||
|
||
oh->mesg[i].type->id >= (int)NELMTS(message_type_g)) {
|
||
HDfprintf(stream, "*** BAD MESSAGE ID 0x%04x\n",
|
||
oh->mesg[i].type->id);
|
||
continue;
|
||
}
|
||
|
||
/* message name and size */
|
||
HDfprintf(stream, "%*s%-*s 0x%04x `%s' (%d)\n",
|
||
indent + 3, "", MAX(0, fwidth - 3),
|
||
"Message ID (sequence number):",
|
||
(unsigned) (oh->mesg[i].type->id),
|
||
oh->mesg[i].type->name,
|
||
sequence[oh->mesg[i].type->id]++);
|
||
HDfprintf (stream, "%*s%-*s %s\n", indent+3, "", MAX (0, fwidth-3),
|
||
"Shared:",
|
||
(oh->mesg[i].flags & H5O_FLAG_SHARED) ? "Yes" : "No");
|
||
HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", MAX(0, fwidth - 3),
|
||
"Constant:",
|
||
(oh->mesg[i].flags & H5O_FLAG_CONSTANT) ? "Yes" : "No");
|
||
if (oh->mesg[i].flags & ~H5O_FLAG_BITS) {
|
||
HDfprintf (stream, "%*s%-*s 0x%02x\n", indent+3,"",MAX(0,fwidth-3),
|
||
"*** ADDITIONAL UNKNOWN FLAGS --->",
|
||
oh->mesg[i].flags & ~H5O_FLAG_BITS);
|
||
}
|
||
HDfprintf(stream, "%*s%-*s %lu bytes\n", indent+3, "", MAX(0,fwidth-3),
|
||
"Raw size in obj header:",
|
||
(unsigned long) (oh->mesg[i].raw_size));
|
||
HDfprintf(stream, "%*s%-*s %d\n", indent + 3, "", MAX(0, fwidth - 3),
|
||
"Chunk number:",
|
||
(int) (oh->mesg[i].chunkno));
|
||
chunkno = oh->mesg[i].chunkno;
|
||
if (chunkno >= oh->nchunks)
|
||
HDfprintf(stream, "*** BAD CHUNK NUMBER\n");
|
||
|
||
/* check the size */
|
||
if ((oh->mesg[i].raw + oh->mesg[i].raw_size >
|
||
oh->chunk[chunkno].image + oh->chunk[chunkno].size) ||
|
||
(oh->mesg[i].raw < oh->chunk[chunkno].image)) {
|
||
HDfprintf(stream, "*** BAD MESSAGE RAW ADDRESS\n");
|
||
}
|
||
|
||
/* decode the message */
|
||
if (oh->mesg[i].flags & H5O_FLAG_SHARED) {
|
||
decode = H5O_SHARED->decode;
|
||
debug = H5O_SHARED->debug;
|
||
} else {
|
||
decode = oh->mesg[i].type->decode;
|
||
debug = oh->mesg[i].type->debug;
|
||
}
|
||
if (NULL==oh->mesg[i].native && decode)
|
||
oh->mesg[i].native = (decode)(f, dxpl_id, oh->mesg[i].raw, NULL);
|
||
if (NULL==oh->mesg[i].native)
|
||
debug = NULL;
|
||
|
||
/* print the message */
|
||
HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3),
|
||
"Message Information:");
|
||
if (debug)
|
||
(debug)(f, dxpl_id, oh->mesg[i].native, stream, indent+6, MAX(0, fwidth-6));
|
||
else
|
||
HDfprintf(stream, "%*s<No info for this message>\n", indent + 6, "");
|
||
|
||
/* If the message is shared then also print the pointed-to message */
|
||
if (oh->mesg[i].flags & H5O_FLAG_SHARED) {
|
||
H5O_shared_t *shared = (H5O_shared_t*)(oh->mesg[i].native);
|
||
void *mesg = NULL;
|
||
if (shared->in_gh) {
|
||
void *p = H5HG_read (f, dxpl_id, oh->mesg[i].native, NULL);
|
||
mesg = (oh->mesg[i].type->decode)(f, dxpl_id, p, oh->mesg[i].native);
|
||
H5MM_xfree (p);
|
||
} else {
|
||
mesg = H5O_read_real(&(shared->u.ent), oh->mesg[i].type, 0, NULL, dxpl_id);
|
||
}
|
||
if (oh->mesg[i].type->debug) {
|
||
(oh->mesg[i].type->debug)(f, dxpl_id, mesg, stream, indent+3,
|
||
MAX (0, fwidth-3));
|
||
}
|
||
H5O_free_real(oh->mesg[i].type, mesg);
|
||
}
|
||
}
|
||
sequence = H5MM_xfree(sequence);
|
||
|
||
if (mesg_total != chunk_total)
|
||
HDfprintf(stream, "*** TOTAL SIZE DOES NOT MATCH ALLOCATED SIZE!\n");
|
||
|
||
done:
|
||
if (oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, FALSE) < 0)
|
||
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
}
|