summaryrefslogtreecommitdiffstats
path: root/src/H5Ocache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5Ocache.c')
-rw-r--r--src/H5Ocache.c554
1 files changed, 554 insertions, 0 deletions
diff --git a/src/H5Ocache.c b/src/H5Ocache.c
new file mode 100644
index 0000000..e5e20e4
--- /dev/null
+++ b/src/H5Ocache.c
@@ -0,0 +1,554 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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: H5Ocache.c
+ * Sep 28 2005
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Object header metadata cache virtual functions.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5O_PACKAGE /*suppress error about including H5Opkg */
+
+/* Interface initialization */
+#define H5_INTERFACE_INIT_FUNC H5O_cache_init_interface
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Opkg.h" /* Object headers */
+
+/* Private typedefs */
+
+/* PRIVATE PROTOTYPES */
+
+/* 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_clear(H5F_t *f, H5O_t *oh, hbool_t destroy);
+static herr_t H5O_compute_size(const H5F_t *f, const H5O_t *oh, size_t *size_ptr);
+
+/* H5O inherits cache-like properties from H5AC */
+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,
+ (H5AC_size_func_t)H5O_compute_size,
+}};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cache_init_interface
+ *
+ * Purpose: Initialize the H5O interface. (Just calls
+ * H5O_init_iterface currently).
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, September 28, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_cache_init_interface(void)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_cache_init_interface)
+
+ FUNC_LEAVE_NOAPI(H5O_init())
+} /* end H5O_cache_init_interface() */
+
+
+/*-------------------------------------------------------------------------
+ * 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
+ *
+ *-------------------------------------------------------------------------
+ */
+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;
+ unsigned skipped_msgs = 0; /* Number of unknown messages skipped */
+ unsigned merged_null_msgs = 0; /* Number of null messages merged together */
+ haddr_t chunk_addr;
+ size_t chunk_size;
+ uint8_t flags;
+
+ FUNC_ENTER_NOAPI(H5O_load, NULL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(!_udata1);
+ HDassert(!_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_SEQ_CALLOC(H5O_mesg_t,(size_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_SEQ_REALLOC (H5O_chunk_t, oh->chunk, (size_t)na);
+
+ if(!x)
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
+ oh->alloc_nchunks = na;
+ oh->chunk = x;
+ } /* end if */
+
+ /* 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);
+ HDassert(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]) {
+ skipped_msgs++;
+ continue;
+ } /* end if */
+
+ 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;
+ merged_null_msgs++;
+ } else {
+ /* new message */
+ if (oh->nmesgs >= nmesgs)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - too many messages");
+ 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;
+ } /* end else */
+ } /* end for */
+
+ HDassert(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);
+ oh->mesg[curmesg].native = cont;
+ chunk_addr = cont->addr;
+ chunk_size = cont->size;
+ cont->chunkno = oh->nchunks; /*the next chunk to allocate */
+ } /* end if */
+ } /* end for */
+ } /* end while */
+
+ /* Sanity check for the correct # of messages in object header */
+ if((oh->nmesgs + skipped_msgs + merged_null_msgs) != nmesgs)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - too few messages")
+
+ /* 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")
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_load() */
+
+
+/*-------------------------------------------------------------------------
+ * 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
+ *
+ *-------------------------------------------------------------------------
+ */
+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;
+ H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
+ herr_t (*encode)(H5F_t*, uint8_t*, const void*) = NULL;
+ unsigned combine = 0; /* Whether to combine the object header prefix & the first chunk */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5O_flush, FAIL)
+
+ /* check args */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(oh);
+
+ /* flush */
+ if(oh->cache_info.is_dirty) {
+ /* Encode any dirty 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);
+ HDassert(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) {
+ HDassert(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))
+ /* We now allocate disk space on insertion, instead
+ * of on flush from the cache, so this case is now an
+ * error. -- JRM
+ */
+ HGOTO_ERROR(H5E_OHDR, H5E_SYSTEM, FAIL, "File space for message not allocated!?!")
+
+ /*
+ * Encode the message. If the message is shared then we
+ * encode a Shared Object message instead of the object
+ * which is being shared.
+ */
+ HDassert(curr_msg->raw >= oh->chunk[curr_msg->chunkno].image);
+ HDassert(curr_msg->raw_size == H5O_ALIGN (curr_msg->raw_size));
+ HDassert(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")
+ } /* end if */
+ curr_msg->dirty = FALSE;
+ oh->chunk[curr_msg->chunkno].dirty = TRUE;
+ } /* end if */
+ } /* end for */
+
+ /* Sanity check for the correct # of messages in object header */
+ if(oh->nmesgs != u)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "corrupt object header - too few messages")
+
+ /* Encode header prefix */
+ 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, (size_t)(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, (size_t)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 */
+
+ /* write each chunk to disk */
+ for(u = 0; u < oh->nchunks; u++) {
+ if(oh->chunk[u].dirty) {
+ HDassert(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, (size_t)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.is_dirty = FALSE;
+ } /* end if */
+
+ if (destroy) {
+ if(H5O_dest(f,oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * 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
+ *
+ *-------------------------------------------------------------------------
+ */
+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.is_dirty==FALSE);
+
+ /* 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);
+ }
+ if(oh->chunk)
+ oh->chunk = H5FL_SEQ_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);
+
+ H5O_free_mesg(&oh->mesg[i]);
+ }
+ if(oh->mesg)
+ oh->mesg = H5FL_SEQ_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
+ *
+ *-------------------------------------------------------------------------
+ */
+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.is_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_compute_size
+ *
+ * Purpose: Compute the size in bytes of the specified instance of
+ * H5O_t on disk, and return it in *len_ptr. On failure,
+ * the value of *len_ptr is undefined.
+ *
+ * The value returned will probably be low unless the object
+ * has just been flushed, as we simply total up the size of
+ * the header with the sizes of the chunks. Thus any message
+ * that has been added since the last flush will not be
+ * reflected in the total.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 5/13/04
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_compute_size(const H5F_t *f, const H5O_t *oh, size_t *size_ptr)
+{
+ unsigned u;
+ size_t size;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_compute_size);
+
+ /* check args */
+ HDassert(f);
+ HDassert(oh);
+ HDassert(size_ptr);
+
+ size = H5O_SIZEOF_HDR(f);
+
+ for (u = 0; u < oh->nchunks; u++)
+ size += oh->chunk[u].size;
+
+ HDassert(size >= H5O_SIZEOF_HDR(f));
+
+ *size_ptr = size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED);
+} /* H5O_compute_size() */
+