summaryrefslogtreecommitdiffstats
path: root/src/H5O.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5O.c')
-rw-r--r--src/H5O.c1242
1 files changed, 1242 insertions, 0 deletions
diff --git a/src/H5O.c b/src/H5O.c
new file mode 100644
index 0000000..6e899fc
--- /dev/null
+++ b/src/H5O.c
@@ -0,0 +1,1242 @@
+/*-------------------------------------------------------------------------
+ * Copyright (C) 1997 National Center for Supercomputing Applications.
+ * All rights reserved.
+ *
+ *-------------------------------------------------------------------------
+ *
+ * Created: H5O.c
+ * Aug 5 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Object header virtual functions.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <assert.h>
+
+#include "hdf5.h"
+
+#include "H5private.h"
+#include "H5ACprivate.h"
+#include "H5Fprivate.h"
+#include "H5MFprivate.h"
+#include "H5MMprivate.h"
+#include "H5Oprivate.h"
+
+#define PABLO_MASK H5O_mask
+
+/* PRIVATE PROTOTYPES */
+static herr_t H5O_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr,
+ H5O_t *oh);
+static H5O_t *H5O_load (hdf5_file_t *f, haddr_t addr, const void *_data);
+static intn H5O_find_in_ohdr (hdf5_file_t *f, haddr_t addr,
+ const H5O_class_t **type_p, intn sequence);
+static intn H5O_alloc (hdf5_file_t *f, H5O_t *oh, const H5O_class_t *type,
+ size_t size);
+static intn H5O_alloc_extend_chunk (H5O_t *oh, intn chunkno, size_t size);
+static intn H5O_alloc_new_chunk (hdf5_file_t *f, H5O_t *oh, size_t size);
+
+/* H5O inherits cache-like properties from H5AC */
+static const H5AC_class_t H5AC_OHDR[1] = {{
+ (void*(*)(hdf5_file_t*,haddr_t,const void*))H5O_load,
+ (herr_t(*)(hdf5_file_t*,hbool_t,haddr_t,void*))H5O_flush,
+}};
+
+/* Is the interface initialized? */
+static intn interface_initialize_g = FALSE;
+
+/* ID to type mapping */
+static const H5O_class_t *const message_type_g[] = {
+ H5O_NULL, /*0x0000 Null */
+ NULL, /*0x0001 Simple dimensionality */
+ NULL, /*0x0002 Data space (fiber bundle?) */
+ NULL, /*0x0003 Simple data type */
+ NULL, /*0x0004 Compound data type */
+ NULL, /*0x0005 Data storage -- standard object */
+ NULL, /*0x0006 Data storage -- compact object */
+ NULL, /*0x0007 Data storage -- external object */
+ NULL, /*0x0008 Data storage -- indexed object */
+ NULL, /*0x0009 Data storage -- chunked object */
+ NULL, /*0x000A Data storage -- sparse object */
+ NULL, /*0x000B Data storage -- compressed object */
+ NULL, /*0x000C Attribute list */
+ NULL, /*0x000D Object name */
+ NULL, /*0x000E Object modification date and time */
+ NULL, /*0x000F Shared header message */
+ H5O_CONT, /*0x0010 Object header continuation */
+ H5O_STAB, /*0x0011 Symbol table */
+};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_new
+ *
+ * Purpose: Creates a new object header, sets the link count
+ * to NLINK, and caches the header.
+ *
+ * Return: Success: Address of new header.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 5 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5O_new (hdf5_file_t *f, intn nlink, size_t size_hint)
+{
+ size_t size; /*total size of object header */
+ haddr_t addr = FAIL; /*address of object header */
+ H5O_t *oh = NULL;
+
+ FUNC_ENTER (H5O_new, NULL, FAIL);
+
+ /* check args */
+ assert (f);
+ assert (nlink>0);
+ if (size_hint<H5O_MIN_SIZE) size_hint = H5O_MIN_SIZE;
+ H5O_ALIGN (size_hint, H5O_ALIGNMENT);
+
+ /* allocate disk space for header and first chunk */
+ size = H5O_SIZEOF_HDR(f) + size_hint;
+ if ((addr = H5MF_alloc (f, size))<0) {
+ HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL);
+ }
+
+ /* allocate the object header in fill in header fields */
+ oh = H5MM_xcalloc (1, sizeof(H5O_t));
+ oh->dirty = TRUE;
+ oh->version = H5O_VERSION;
+ oh->alignment = H5O_ALIGNMENT;
+ oh->nlink = nlink;
+
+ /* create the chunk list and initialize the first chunk */
+ oh->nchunks = 1;
+ oh->alloc_nchunks = H5O_NCHUNKS;
+ oh->chunk = H5MM_xmalloc (oh->alloc_nchunks * sizeof (H5O_chunk_t));
+
+ oh->chunk[0].dirty = TRUE;
+ oh->chunk[0].addr = addr + H5O_SIZEOF_HDR(f);
+ oh->chunk[0].size = size_hint;
+ oh->chunk[0].image = H5MM_xmalloc (size_hint);
+
+ /* create the message list and initialize the first message */
+ oh->nmesgs = 1;
+ oh->alloc_nmesgs = H5O_NMESGS;
+ oh->mesg = H5MM_xcalloc (oh->alloc_nmesgs, sizeof(H5O_mesg_t));
+
+ oh->mesg[0].type = H5O_NULL;
+ oh->mesg[0].dirty = TRUE;
+ oh->mesg[0].native = NULL;
+ oh->mesg[0].raw = oh->chunk[0].image + 4; /*skip id and size fields */
+ oh->mesg[0].raw_size = size_hint - 4;
+ oh->mesg[0].chunkno = 0;
+
+ /* cache it */
+ if (H5AC_set (f, H5AC_OHDR, addr, oh)<0) {
+ H5MM_xfree (oh);
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTINIT, FAIL);
+ }
+
+ FUNC_LEAVE (addr);
+}
+
+
+/*-------------------------------------------------------------------------
+ * 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:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5O_t *
+H5O_load (hdf5_file_t *f, haddr_t addr, const void *_data)
+{
+ H5O_t *oh = NULL;
+ uint8 buf[16], *p;
+ size_t hdr_size, mesg_size;
+ uintn id;
+ intn mesgno, chunkno, curmesg=0, nmesgs;
+ haddr_t chunk_addr;
+ size_t chunk_size;
+ H5O_cont_t *cont=NULL;
+
+ FUNC_ENTER (H5O_load, NULL, NULL);
+
+ /* check args */
+ assert (f);
+ assert (addr>=0);
+ assert (!_data);
+
+ /* allocate ohdr and init chunk list */
+ oh = H5MM_xcalloc (1, sizeof(H5O_t));
+
+ /* read fixed-lenth part of object header */
+ hdr_size = H5O_SIZEOF_HDR (f);
+ if (H5F_block_read (f, addr, hdr_size, buf)<0) {
+ HRETURN_ERROR (H5E_OHDR, H5E_READERROR, NULL);
+ }
+ p = buf;
+
+ /* decode version */
+ oh->version = *p++;
+ if (H5O_VERSION!=oh->version) {
+ HRETURN_ERROR (H5E_OHDR, H5E_VERSION, NULL);
+ }
+
+ /* decode alignment */
+ oh->alignment = *p++;
+ if (4!=oh->alignment) {
+ HRETURN_ERROR (H5E_OHDR, H5E_ALIGNMENT, NULL);
+ }
+
+ /* decode number of messages */
+ UINT16DECODE (p, nmesgs);
+
+ /* decode link count */
+ UINT32DECODE (p, oh->nlink);
+
+ /* decode first chunk info */
+ chunk_addr = addr + H5O_SIZEOF_HDR(f);
+ UINT32DECODE (p, chunk_size);
+
+ /* build the message array */
+ oh->alloc_nmesgs = MAX (H5O_NMESGS, nmesgs);
+ oh->mesg = H5MM_xcalloc (oh->alloc_nmesgs, sizeof(H5O_mesg_t));
+
+ /* read each chunk from disk */
+ while (chunk_addr) {
+
+ /* increase chunk array size */
+ if (oh->nchunks>=oh->alloc_nchunks) {
+ oh->alloc_nchunks += H5O_NCHUNKS;
+ oh->chunk = H5MM_xrealloc (oh->chunk,
+ oh->alloc_nchunks * sizeof(H5O_chunk_t));
+ }
+
+ /* 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;
+ oh->chunk[chunkno].image = H5MM_xmalloc (chunk_size);
+ if (H5F_block_read (f, chunk_addr, chunk_size,
+ oh->chunk[chunkno].image)<0) {
+ HRETURN_ERROR (H5E_OHDR, H5E_READERROR, NULL);
+ }
+
+
+ /* 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);
+
+ if (id>=NELMTS(message_type_g) || NULL==message_type_g[id]) {
+ HRETURN_ERROR (H5E_OHDR, H5E_BADMESG, NULL);
+ }
+ if (p + mesg_size > oh->chunk[chunkno].image + chunk_size) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTINIT, NULL);
+ }
+
+ mesgno = oh->nmesgs++;
+ if (mesgno>=nmesgs) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, NULL);
+ }
+ oh->mesg[mesgno].type = message_type_g[id];
+ oh->mesg[mesgno].dirty = FALSE;
+ 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=0; 0==chunk_addr && curmesg<oh->nmesgs; curmesg++) {
+ if (H5O_CONT_ID==oh->mesg[curmesg].type->id) {
+ uint8 *p2 = oh->mesg[curmesg].raw;
+ oh->mesg[curmesg].native = (H5O_CONT->decode)(f, p2);
+ cont = (H5O_cont_t*)(oh->mesg[curmesg].native);
+ chunk_addr = cont->addr;
+ chunk_size = cont->size;
+ cont->chunkno = oh->nchunks; /*the next chunk to allocate*/
+ }
+ }
+ }
+
+ FUNC_LEAVE (oh);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_flush
+ *
+ * Purpose: Flushes (and destroys) an object header.
+ *
+ * Return: Success: SUCCESS
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 5 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5O_t *oh)
+{
+ uint8 buf[16], *p;
+ int i;
+ H5O_cont_t *cont = NULL;
+
+ FUNC_ENTER (H5O_flush, NULL, FAIL);
+
+ /* check args */
+ assert (f);
+ assert (addr>=0);
+ assert (oh);
+
+ /* flush */
+ if (oh->dirty) {
+ p = buf;
+
+ /* encode version */
+ *p++ = oh->version;
+
+ /* encode alingment */
+ *p++ = oh->alignment;
+
+ /* encode number of messages */
+ UINT16ENCODE (p, oh->nmesgs);
+
+ /* encode link count */
+ UINT32ENCODE (p, oh->nlink);
+
+ /* encode body size */
+ UINT32ENCODE (p, oh->chunk[0].size);
+
+ /* write the object header header */
+ if (H5F_block_write (f, addr, H5O_SIZEOF_HDR(f), buf)<0) {
+ HRETURN_ERROR (H5E_OHDR, H5E_WRITEERROR, FAIL);
+ }
+
+ /* encode messages */
+ for (i=0; i<oh->nmesgs; i++) {
+ if (oh->mesg[i].dirty) {
+ p = oh->mesg[i].raw - 4;
+ UINT16ENCODE (p, oh->mesg[i].type->id);
+ UINT16ENCODE (p, oh->mesg[i].raw_size);
+ if (oh->mesg[i].native) {
+ assert (oh->mesg[i].type->encode);
+
+ /* allocate file space for chunks that have none yet */
+ if (H5O_CONT_ID==oh->mesg[i].type->id &&
+ ((H5O_cont_t*)(oh->mesg[i].native))->addr<0) {
+ cont = (H5O_cont_t*)(oh->mesg[i].native);
+ assert (cont->chunkno >= 0);
+ assert (cont->chunkno < oh->nchunks);
+ assert (oh->chunk[cont->chunkno].addr<0);
+ cont->size = oh->chunk[cont->chunkno].size;
+ cont->addr = H5MF_alloc (f, cont->size);
+ if (cont->addr<0) {
+ HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL);
+ }
+ oh->chunk[cont->chunkno].addr = cont->addr;
+ }
+
+ /* encode the message */
+ assert (oh->mesg[i].raw >=
+ oh->chunk[oh->mesg[i].chunkno].image);
+ assert (oh->mesg[i].raw + oh->mesg[i].raw_size <=
+ oh->chunk[oh->mesg[i].chunkno].image +
+ oh->chunk[oh->mesg[i].chunkno].size);
+ if ((oh->mesg[i].type->encode)(f, oh->mesg[i].raw_size,
+ oh->mesg[i].raw,
+ oh->mesg[i].native)<0) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTENCODE, FAIL);
+ }
+ }
+ oh->mesg[i].dirty = FALSE;
+ oh->chunk[oh->mesg[i].chunkno].dirty = TRUE;
+ }
+ }
+
+ /* write each chunk to disk */
+ for (i=0; i<oh->nchunks; i++) {
+ if (oh->chunk[i].dirty) {
+ assert (oh->chunk[i].addr>0);
+ if (H5F_block_write (f, oh->chunk[i].addr, oh->chunk[i].size,
+ oh->chunk[i].image)<0) {
+ HRETURN_ERROR (H5E_OHDR, H5E_WRITEERROR, FAIL);
+ }
+ oh->chunk[i].dirty = FALSE;
+ }
+ }
+ oh->dirty = FALSE;
+ }
+
+
+ if (destroy) {
+ /* destroy chunks */
+ for (i=0; i<oh->nchunks; i++) {
+ oh->chunk[i].image = H5MM_xfree (oh->chunk[i].image);
+ }
+ oh->chunk = H5MM_xfree (oh->chunk);
+
+ /* destroy messages */
+ for (i=0; i<oh->nmesgs; i++) {
+ if (oh->mesg[i].native) {
+ if (oh->mesg[i].type->free) {
+ (oh->mesg[i].type->free)(oh->mesg[i].native);
+ oh->mesg[i].native = NULL;
+ } else {
+ oh->mesg[i].native = H5MM_xfree (oh->mesg[i].native);
+ }
+ }
+ }
+ oh->mesg = H5MM_xfree (oh->mesg);
+
+ /* destroy object header */
+ H5MM_xfree (oh);
+ }
+
+ FUNC_LEAVE (SUCCEED);
+}
+
+
+/*-------------------------------------------------------------------------
+ * 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: FAIL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 5 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+intn
+H5O_link (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, intn adjust)
+{
+ H5O_t *oh = NULL;
+
+ FUNC_ENTER (H5O_link, NULL, FAIL);
+
+ /* check args */
+ assert (f);
+ assert (addr>=0);
+
+ /* get header */
+ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, FAIL);
+ }
+
+ /* adjust link count */
+ if (adjust<0) {
+ if (oh->nlink + adjust < 0) {
+ HRETURN_ERROR (H5E_OHDR, H5E_LINKCOUNT, FAIL);
+ }
+ oh->nlink += adjust;
+ if (1==oh->nlink && ent) {
+ fprintf (stderr, "H5O_link: no symbol table entry caching "
+ "(not implemented yet)\n");
+ }
+ } else {
+ oh->nlink += adjust;
+ if (oh->nlink>1 && ent) ent->type = H5G_NOTHING_CACHED;
+ }
+
+
+ oh->dirty = TRUE;
+ FUNC_LEAVE (oh->nlink);
+}
+
+
+/*-------------------------------------------------------------------------
+ * 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.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5O_read (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent,
+ const H5O_class_t *type, intn sequence, void *mesg)
+{
+ H5O_t *oh = NULL;
+ void *retval = NULL;
+ intn idx;
+
+ FUNC_ENTER (H5O_read, NULL, NULL);
+
+ /* check args */
+ assert (f);
+ assert (addr>=0);
+ assert (sequence>=0);
+
+ /* can we get it from the symbol table? */
+ if (ent && H5G_NOTHING_CACHED!=ent->type && type && type->fast) {
+ retval = (type->fast)(ent, mesg);
+ if (retval) HRETURN (retval);
+ H5ECLEAR;
+ }
+
+ /* can we get it from the object header? */
+ if ((idx = H5O_find_in_ohdr (f, addr, &type, sequence))<0) {
+ HRETURN_ERROR (H5E_OHDR, H5E_NOTFOUND, NULL);
+ }
+
+ /* copy the message to the user-supplied buffer */
+ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, NULL);
+ }
+ retval = (type->copy)(oh->mesg[idx].native, mesg);
+ if (!retval) HRETURN_ERROR (H5E_OHDR, H5E_CANTINIT, NULL);
+
+ FUNC_LEAVE (retval);
+}
+
+
+/*-------------------------------------------------------------------------
+ * 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: FAIL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static intn
+H5O_find_in_ohdr (hdf5_file_t *f, haddr_t addr, const H5O_class_t **type_p,
+ intn sequence)
+{
+ H5O_t *oh = NULL;
+ int i;
+
+ FUNC_ENTER (H5O_find_in_ohdr, NULL, FAIL);
+
+ /* check args */
+ assert (f);
+ assert (addr>=0);
+ assert (type_p);
+
+ /* load the object header */
+ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, FAIL);
+ }
+
+ /* scan through the messages looking for the right one */
+ for (i=0; i<oh->nmesgs; i++) {
+ if (*type_p && (*type_p)->id!=oh->mesg[i].type->id) continue;
+ if (--sequence<0) break;
+ }
+ if (sequence>=0) HRETURN_ERROR (H5E_OHDR, H5E_NOTFOUND, FAIL);
+
+ /* decode the message if necessary */
+ if (NULL==oh->mesg[i].native) {
+ assert (oh->mesg[i].type->decode);
+ oh->mesg[i].native = (oh->mesg[i].type->decode)(f, oh->mesg[i].raw);
+ if (NULL==oh->mesg[i].native) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTDECODE, FAIL);
+ }
+ }
+
+ /*return the message type */
+ *type_p = oh->mesg[i].type;
+
+ FUNC_LEAVE (i);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_peek
+ *
+ * Purpose: Returns a pointer to a message stored in native format.
+ * The returned memory is read-only, and points directly into
+ * the cache. It is therefore valid only until the next cache
+ * function is called.
+ *
+ * Return: Success: Ptr to read-only message in native format.
+ * The pointer is guranteed to be valid only
+ * until the next call (directly or indirectly)
+ * to an H5AC function.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+const void *
+H5O_peek (hdf5_file_t *f, haddr_t addr, const H5O_class_t *type,
+ intn sequence)
+{
+ intn idx;
+ H5O_t *oh = NULL;
+
+ FUNC_ENTER (H5O_peek, NULL, NULL);
+
+ /* check args */
+ assert (f);
+ assert (addr>=0);
+
+ if ((idx = H5O_find_in_ohdr (f, addr, &type, sequence))<0) {
+ HRETURN_ERROR (H5E_OHDR, H5E_NOTFOUND, NULL);
+ }
+ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, NULL);
+ }
+
+ FUNC_LEAVE (oh->mesg[idx].native);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_modify
+ *
+ * Purpose: Modifies an existing message or creates a new message.
+ * The object header is at file address ADDR of file F. An
+ * optional symbol table entry ENT can be supplied in which
+ * case the cache fields in that symbol table are updated if
+ * appropriate. If the symbol table entry changes then the
+ * optional ENT_MODIFIED arg will point to a non-zero value.
+ *
+ * The OVERWRITE argument is either a sequence number of a
+ * message to overwrite (usually zero) or the constant
+ * H5O_NEW_MESSAGE (-1) to indicate that a new message is to
+ * be created.
+ *
+ * Return: Success: The sequence number of the message that
+ * was modified or created.
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+intn
+H5O_modify (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent,
+ hbool_t *ent_modified, const H5O_class_t *type,
+ intn overwrite, const void *mesg)
+{
+ H5O_t *oh = NULL;
+ intn idx, sequence;
+ size_t size;
+
+ FUNC_ENTER (H5O_modify, NULL, FAIL);
+
+ /* check args */
+ assert (f);
+ assert (addr>=0);
+ assert (type);
+ assert (mesg);
+
+ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, FAIL);
+ }
+
+ /* Count similar messages */
+ for (idx=sequence=0; idx<oh->nmesgs; idx++) {
+ if (type->id != oh->mesg[idx].type->id) continue;
+ if (sequence==overwrite) break;
+ sequence++;
+ }
+
+ /* Was the right message found? */
+ if (overwrite>=0 && sequence!=overwrite) {
+ HRETURN_ERROR (H5E_OHDR, H5E_NOTFOUND, FAIL);
+ }
+
+ /* Allocate space for the new message */
+ if (overwrite<0) {
+ size = (type->size)(f, mesg);
+ H5O_ALIGN (size, oh->alignment);
+ idx = H5O_alloc (f, oh, type, size);
+ if (idx<0) HRETURN_ERROR (H5E_OHDR, H5E_CANTINIT, FAIL);
+ }
+
+ /* Copy the native value into the object header */
+ oh->mesg[idx].native = (type->copy)(mesg, oh->mesg[idx].native);
+ if (NULL==oh->mesg[idx].native) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTINIT, FAIL);
+ }
+ oh->mesg[idx].dirty = TRUE;
+ oh->dirty = TRUE;
+
+ /* Copy into the symbol table entry */
+ if (1==oh->nlink && ent && type->cache) {
+ hbool_t modified = (type->cache)(ent, mesg);
+ if (ent_modified) *ent_modified = modified;
+ }
+
+ FUNC_LEAVE (sequence);
+}
+
+
+/*-------------------------------------------------------------------------
+ * 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 at least SIZE bytes.
+ *
+ * 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: FAIL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 7 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static intn
+H5O_alloc_extend_chunk (H5O_t *oh, intn chunkno, size_t size)
+{
+ intn idx, i;
+ size_t delta;
+ uint8 *old_addr;
+
+ FUNC_ENTER (H5O_alloc_extend_chunk, NULL, FAIL);
+
+ /* check args */
+ assert (oh);
+ assert (chunkno>=0 && chunkno<oh->nchunks);
+ assert (size>0);
+
+ if (H5O_NO_ADDR!=oh->chunk[chunkno].addr) {
+ HRETURN_ERROR (H5E_OHDR, H5E_NOSPACE, FAIL); /*chunk is on disk*/
+ }
+
+ /* try to extend a null message */
+ for (idx=0; idx<oh->nmesgs; idx++) {
+ 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, size-oh->mesg[idx].raw_size);
+ H5O_ALIGN (delta, oh->alignment);
+ oh->mesg[idx].dirty = TRUE;
+ oh->mesg[idx].raw_size += delta;
+
+ old_addr = oh->chunk[chunkno].image;
+ oh->chunk[chunkno].size += delta;
+ oh->chunk[chunkno].image = H5MM_xrealloc (old_addr,
+ oh->chunk[chunkno].size);
+
+ /* adjust raw addresses for messages of this chunk */
+ if (old_addr != oh->chunk[chunkno].image) {
+ for (i=0; i<oh->nmesgs; i++) {
+ if (oh->mesg[i].chunkno==chunkno) {
+ oh->mesg[i].raw = oh->chunk[chunkno].image +
+ (oh->mesg[i].raw - old_addr);
+ }
+ }
+ }
+ HRETURN (idx);
+ }
+ }
+
+ /* create a new null message */
+ if (oh->nmesgs >= oh->alloc_nmesgs) {
+ oh->alloc_nmesgs += H5O_NMESGS;
+ oh->mesg = H5MM_xrealloc (oh->mesg,
+ oh->alloc_nmesgs * sizeof(H5O_mesg_t));
+ }
+
+ delta = MAX (H5O_MIN_SIZE, 4+size);
+ H5O_ALIGN (delta, oh->alignment);
+ 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 + 4;
+ oh->mesg[idx].raw_size = delta-4;
+ oh->mesg[idx].chunkno = chunkno;
+
+ old_addr = oh->chunk[chunkno].image;
+ oh->chunk[chunkno].size += delta;
+ oh->chunk[chunkno].image = H5MM_xrealloc (old_addr,
+ oh->chunk[chunkno].size);
+
+ /* adjust raw addresses for messages of this chunk */
+ if (old_addr != oh->chunk[chunkno].image) {
+ for (i=0; i<oh->nmesgs; i++) {
+ if (oh->mesg[i].chunkno==chunkno) {
+ oh->mesg[i].raw = oh->chunk[chunkno].image +
+ (oh->mesg[i].raw - old_addr);
+ }
+ }
+ }
+
+ FUNC_LEAVE (idx);
+}
+
+
+/*-------------------------------------------------------------------------
+ * 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.
+ *
+ * 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: FAIL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 7 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static intn
+H5O_alloc_new_chunk (hdf5_file_t *f, H5O_t *oh, size_t size)
+{
+ size_t cont_size; /*continuation message size */
+ intn found_null=(-1); /*best fit null message */
+ intn found_other=(-1); /*best fit other message */
+ intn idx=FAIL; /*message number return value */
+ uint8 *p = NULL; /*ptr into new chunk */
+ H5O_cont_t *cont = NULL; /*native continuation message */
+ intn i, chunkno;
+
+ FUNC_ENTER (H5O_alloc_new_chunk, NULL, FAIL);
+
+ /* check args */
+ assert (oh);
+ assert (size>0);
+
+ /*
+ * 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 = H5F_SIZEOF_OFFSET(f) + H5F_SIZEOF_SIZE(f);
+ for (i=0; i<oh->nmesgs; i++) {
+ if (H5O_NULL_ID == oh->mesg[i].type->id) {
+ if (cont_size == oh->mesg[i].raw_size) {
+ found_null = i;
+ break;
+ } else if (oh->mesg[i].raw_size >= cont_size &&
+ (found_null<0 ||
+ oh->mesg[i].raw_size < oh->mesg[found_null].raw_size)) {
+ found_null = i;
+ }
+ } else if (H5O_CONT_ID == oh->mesg[i].type->id) {
+ /*don't consider continuation messages */
+ } else if (oh->mesg[i].raw_size >= cont_size &&
+ (found_other<0 ||
+ oh->mesg[i].raw_size < oh->mesg[found_other].raw_size)) {
+ found_other = i;
+ }
+ }
+ 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 += 4 + 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+4);
+ H5O_ALIGN (size, oh->alignment);
+
+ /*
+ * Create the new chunk without giving it a file address.
+ */
+ if (oh->nchunks >= oh->alloc_nchunks) {
+ oh->alloc_nchunks += H5O_NCHUNKS;
+ oh->chunk = H5MM_xrealloc (oh->chunk,
+ oh->alloc_nchunks * sizeof(H5O_chunk_t));
+ }
+ chunkno = oh->nchunks++;
+ oh->chunk[chunkno].dirty = TRUE;
+ oh->chunk[chunkno].addr = H5O_NO_ADDR;
+ oh->chunk[chunkno].size = size;
+ oh->chunk[chunkno].image = p = H5MM_xmalloc (size);
+
+ /*
+ * Make sure we have enough space for all possible new messages
+ * that could be generated below.
+ */
+ if (oh->nmesgs+3 > oh->alloc_nmesgs) {
+ oh->alloc_nmesgs += MAX (H5O_NMESGS, 3);
+ oh->mesg = H5MM_xrealloc (oh->mesg,
+ oh->alloc_nmesgs * sizeof(H5O_mesg_t));
+ }
+
+ /*
+ * Describe the messages of the new chunk.
+ */
+ if (found_null<0) {
+ found_null = i = oh->nmesgs++;
+ oh->mesg[i].type = H5O_NULL;
+ oh->mesg[i].dirty = TRUE;
+ oh->mesg[i].native = NULL;
+ oh->mesg[i].raw = oh->mesg[found_other].raw;
+ oh->mesg[i].raw_size = oh->mesg[found_other].raw_size;
+ oh->mesg[i].chunkno = oh->mesg[found_other].chunkno;
+
+ oh->mesg[found_other].dirty = TRUE;
+ oh->mesg[found_other].raw = p+4;
+ oh->mesg[found_other].chunkno = chunkno;
+ p += 4 + oh->mesg[found_other].raw_size;
+ size -= 4 + 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+4;
+ oh->mesg[idx].raw_size = size-4;
+ 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) {
+ i = oh->nmesgs++;
+ oh->mesg[i].type = H5O_NULL;
+ oh->mesg[i].dirty = TRUE;
+ oh->mesg[i].native = NULL;
+ oh->mesg[i].raw = oh->mesg[found_null].raw + cont_size + 4;
+ oh->mesg[i].raw_size = oh->mesg[found_null].raw_size - (cont_size+4);
+ oh->mesg[i].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;
+ cont = H5MM_xcalloc (1, sizeof(H5O_cont_t));
+ cont->addr = H5O_NO_ADDR;
+ cont->size = 0;
+ cont->chunkno = chunkno;
+ oh->mesg[found_null].native = cont;
+
+
+ FUNC_LEAVE (idx);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_alloc
+ *
+ * Purpose: Allocate enough space in the object header for this message.
+ *
+ * Return: Success: Index of message
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static intn
+H5O_alloc (hdf5_file_t *f, H5O_t *oh, const H5O_class_t *type, size_t size)
+{
+ intn chunkno;
+ intn idx;
+ intn null_idx;
+
+ FUNC_ENTER (H5O_alloc, NULL, FAIL);
+
+ /* check args */
+ assert (oh);
+ assert (type);
+ assert (size>=0);
+ H5O_ALIGN (size, oh->alignment);
+
+ /* 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>=size) break;
+ }
+
+ /* if we didn't find one, then allocate more header space */
+ if (idx>=oh->nmesgs) {
+
+ /*
+ * 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))>=0) break;
+ H5ECLEAR;
+ }
+
+ /*
+ * Create a new chunk
+ */
+ if (idx<0) {
+ if ((idx=H5O_alloc_new_chunk (f, oh, size))<0) {
+ HRETURN_ERROR (H5E_OHDR, H5E_NOSPACE, FAIL);
+ }
+ }
+ }
+
+ /* do we need to split the null message? */
+ if (oh->mesg[idx].raw_size > size) {
+ assert (oh->mesg[idx].raw_size - size >= 4); /*room for type & size */
+
+ if (oh->nmesgs >= oh->alloc_nmesgs) {
+ oh->alloc_nmesgs += H5O_NMESGS;
+ oh->mesg = H5MM_xrealloc (oh->mesg,
+ oh->alloc_nmesgs * sizeof(H5O_mesg_t));
+ }
+
+ null_idx = oh->nmesgs++;
+ oh->mesg[null_idx].type = H5O_NULL;
+ oh->mesg[null_idx].dirty = TRUE;
+ oh->mesg[null_idx].native = NULL;
+ oh->mesg[null_idx].raw = oh->mesg[idx].raw + size + 4;
+ oh->mesg[null_idx].raw_size = oh->mesg[idx].raw_size - (size + 4);
+ oh->mesg[null_idx].chunkno = oh->mesg[idx].chunkno;
+ oh->mesg[idx].raw_size = size;
+ }
+
+ /* initialize the new message */
+ oh->mesg[idx].type = type;
+ oh->mesg[idx].dirty = TRUE;
+ oh->mesg[idx].native = NULL;
+
+ oh->dirty = TRUE;
+ FUNC_LEAVE (idx);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_debug
+ *
+ * Purpose: Prints debugging info about an object header.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * matzke@llnl.gov
+ * Aug 6 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_debug (hdf5_file_t *f, haddr_t addr, FILE *stream,
+ intn indent, intn fwidth)
+{
+ H5O_t *oh = NULL;
+ intn i, chunkno;
+ size_t mesg_total=0, chunk_total=0;
+ int *sequence;
+
+ FUNC_ENTER (H5O_debug, NULL, FAIL);
+
+ /* check args */
+ assert (f);
+ assert (addr>=0);
+ assert (stream);
+ assert (indent>=0);
+ assert (fwidth>=0);
+
+ if (NULL==(oh=H5AC_find (f, H5AC_OHDR, addr, NULL))) {
+ HRETURN_ERROR (H5E_OHDR, H5E_CANTLOAD, FAIL);
+ }
+
+ /* debug */
+ fprintf (stream, "%*sObject Header...\n", indent, "");
+
+ fprintf (stream, "%*s%-*s %d\n", indent, "", fwidth,
+ "Dirty:",
+ (int)(oh->dirty));
+ fprintf (stream, "%*s%-*s %d\n", indent, "", fwidth,
+ "Version:",
+ (int)(oh->version));
+ fprintf (stream, "%*s%-*s %d\n", indent, "", fwidth,
+ "Alignment:",
+ (int)(oh->alignment));
+ fprintf (stream, "%*s%-*s %d\n", indent, "", fwidth,
+ "Number of links:",
+ (int)(oh->nlink));
+ fprintf (stream, "%*s%-*s %d (%d)\n", indent, "", fwidth,
+ "Number of messages (allocated):",
+ (int)(oh->nmesgs), (int)(oh->alloc_nmesgs));
+ fprintf (stream, "%*s%-*s %d (%d)\n", indent, "", fwidth,
+ "Number of chunks (allocated):",
+ (int)(oh->nchunks), (int)(oh->alloc_nchunks));
+
+ /* debug each chunk */
+ for (i=chunk_total=0; i<oh->nchunks; i++) {
+ chunk_total += oh->chunk[i].size;
+ fprintf (stream, "%*sChunk %d...\n", indent, "", i);
+
+ fprintf (stream, "%*s%-*s %d\n", indent+3, "", MAX(0,fwidth-3),
+ "Dirty:",
+ (int)(oh->chunk[i].dirty));
+ fprintf (stream, "%*s%-*s %lu\n", indent+3, "", MAX(0,fwidth-3),
+ "Address:",
+ (unsigned long)(oh->chunk[i].addr));
+ if (0==i && oh->chunk[i].addr!=addr+H5O_SIZEOF_HDR(f)) {
+ fprintf (stream, "*** WRONG ADDRESS!\n");
+ }
+ fprintf (stream, "%*s%-*s %lu\n", indent+3, "", MAX(0,fwidth-3),
+ "Size in bytes:",
+ (unsigned long)(oh->chunk[i].size));
+ }
+
+ /* debug each message */
+ sequence = H5MM_xcalloc (NELMTS(message_type_g), sizeof(int));
+ for (i=mesg_total=0; i<oh->nmesgs; i++) {
+ mesg_total += 4 + oh->mesg[i].raw_size;
+ fprintf (stream, "%*sMessage %d...\n", indent, "", i);
+
+ /* check for bad message id */
+ if (oh->mesg[i].type->id<0 ||
+ oh->mesg[i].type->id>=NELMTS(message_type_g)) {
+ fprintf (stream, "*** BAD MESSAGE ID 0x%04x\n",
+ oh->mesg[i].type->id);
+ continue;
+ }
+
+ /* message name and size */
+ fprintf (stream, "%*s%-*s 0x%04x %s(%d)\n",
+ indent+3, "", MAX (0, fwidth-3),
+ "Message ID:",
+ (unsigned)(oh->mesg[i].type->id),
+ oh->mesg[i].type->name,
+ sequence[oh->mesg[i].type->id]++);
+ fprintf (stream, "%*s%-*s %lu\n", indent+3, "", MAX (0, fwidth-3),
+ "Raw size in bytes:",
+ (unsigned long)(oh->mesg[i].raw_size));
+
+ fprintf (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<0 || chunkno>=oh->nchunks) {
+ fprintf (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)) {
+ fprintf (stream, "*** BAD MESSAGE RAW ADDRESS\n");
+ }
+
+ /* decode the message */
+ if (NULL==oh->mesg[i].native && oh->mesg[i].type->decode) {
+ oh->mesg[i].native = (oh->mesg[i].type->decode)(f, oh->mesg[i].raw);
+ }
+
+ /* print the message */
+ if (oh->mesg[i].type->debug) {
+ (oh->mesg[i].type->debug)(f, oh->mesg[i].native, stream, indent+3,
+ MAX(0, fwidth-3));
+ } else {
+ fprintf (stream, "%*sNo info for this message.\n", indent+3, "");
+ }
+ }
+ sequence = H5MM_xfree (sequence);
+
+ if (mesg_total != chunk_total) {
+ fprintf (stream, "*** TOTAL SIZE DOES NOT MATCH ALLOCATED SIZE!\n");
+ }
+
+ FUNC_LEAVE (SUCCEED);
+}