summaryrefslogtreecommitdiffstats
path: root/src/H5Ocache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5Ocache.c')
-rw-r--r--src/H5Ocache.c1313
1 files changed, 869 insertions, 444 deletions
diff --git a/src/H5Ocache.c b/src/H5Ocache.c
index 780d5bb..95f3d3a 100644
--- a/src/H5Ocache.c
+++ b/src/H5Ocache.c
@@ -39,6 +39,7 @@
#include "H5FLprivate.h" /* Free lists */
#include "H5MFprivate.h" /* File memory management */
#include "H5Opkg.h" /* Object headers */
+#include "H5WBprivate.h" /* Wrapped Buffers */
/****************/
@@ -74,25 +75,31 @@ 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);
static herr_t H5O_size(const H5F_t *f, const H5O_t *oh, size_t *size_ptr);
+static H5O_chunk_proxy_t *H5O_cache_chk_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_udata1,
+ void *_udata2);
+static herr_t H5O_cache_chk_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5O_chunk_proxy_t *chk_proxy, unsigned UNUSED * flags_ptr);
+static herr_t H5O_cache_chk_dest(H5F_t *f, H5O_chunk_proxy_t *chk_proxy);
+static herr_t H5O_cache_chk_clear(H5F_t *f, H5O_chunk_proxy_t *chk_proxy, hbool_t destroy);
+static herr_t H5O_cache_chk_size(const H5F_t *f, const H5O_chunk_proxy_t *chk_proxy, size_t *size_ptr);
-/*********************/
-/* Package Variables */
-/*********************/
-
+/* Chunk proxy routines */
+static herr_t H5O_chunk_proxy_dest(H5O_chunk_proxy_t *chunk_proxy);
-/*****************************/
-/* Library Private Variables */
-/*****************************/
+/* Chunk routines */
+static herr_t H5O_chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len,
+ const uint8_t *image, H5O_common_cache_ud_t *udata, hbool_t *dirty);
+static herr_t H5O_chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno);
-/* Declare external the free list for H5O_unknown_t's */
-H5FL_EXTERN(H5O_unknown_t);
+/* Misc. routines */
+static herr_t H5O_add_cont_msg(H5O_cont_msgs_t *cont_msg_info,
+ const H5O_cont_t *cont);
-/*******************/
-/* Local Variables */
-/*******************/
+/*********************/
+/* Package Variables */
+/*********************/
-/* H5O inherits cache-like properties from H5AC */
+/* H5O object header prefix inherits cache-like properties from H5AC */
const H5AC_class_t H5AC_OHDR[1] = {{
H5AC_OHDR_ID,
(H5AC_load_func_t)H5O_load,
@@ -103,6 +110,37 @@ const H5AC_class_t H5AC_OHDR[1] = {{
(H5AC_size_func_t)H5O_size,
}};
+/* H5O object header chunk inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_OHDR_CHK[1] = {{
+ H5AC_OHDR_CHK_ID,
+ (H5AC_load_func_t)H5O_cache_chk_load,
+ (H5AC_flush_func_t)H5O_cache_chk_flush,
+ (H5AC_dest_func_t)H5O_cache_chk_dest,
+ (H5AC_clear_func_t)H5O_cache_chk_clear,
+ (H5AC_notify_func_t)NULL,
+ (H5AC_size_func_t)H5O_cache_chk_size,
+}};
+
+/* Declare external the free list for H5O_unknown_t's */
+H5FL_EXTERN(H5O_unknown_t);
+
+/* Declare extern the free list for H5O_chunk_proxy_t's */
+H5FL_EXTERN(H5O_chunk_proxy_t);
+
+/* Declare the free list for H5O_cont_t sequences */
+H5FL_SEQ_DEFINE(H5O_cont_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
/*-------------------------------------------------------------------------
* Function: H5O_load
@@ -121,18 +159,17 @@ const H5AC_class_t H5AC_OHDR[1] = {{
*/
static H5O_t *
H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
- void UNUSED * _udata2)
+ void *_udata2)
{
H5O_t *oh = NULL; /* Object header read in */
+ H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata2; /* User data for callback */
+ H5WB_t *wb = NULL; /* Wrapped buffer for prefix data */
uint8_t read_buf[H5O_SPEC_READ_SIZE]; /* Buffer for speculative read */
const uint8_t *p; /* Pointer into buffer to decode */
+ uint8_t *buf; /* Buffer to decode */
size_t spec_read_size; /* Size of buffer to speculatively read in */
size_t prefix_size; /* Size of object header prefix */
- unsigned nmesgs; /* Total # of messages in this object header */
- unsigned curmesg = 0; /* Current message being decoded in object header */
- unsigned merged_null_msgs = 0; /* Number of null messages merged together */
- haddr_t chunk_addr; /* Address of first chunk */
- size_t chunk_size; /* Size of first chunk */
+ size_t buf_size; /* Size of prefix+chunk #0 buffer */
haddr_t eoa; /* Relative end of file address */
H5O_t *ret_value; /* Return value */
@@ -142,7 +179,9 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
HDassert(f);
HDassert(H5F_addr_defined(addr));
HDassert(!_udata1);
- HDassert(!_udata2);
+ HDassert(udata);
+ HDassert(udata->common.f);
+ HDassert(udata->common.cont_msg_info);
/* Make certain we don't speculatively read off the end of the file */
if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_OHDR)))
@@ -161,8 +200,8 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
/* File-specific, non-stored information */
- oh->sizeof_size = H5F_SIZEOF_SIZE(f);
- oh->sizeof_addr = H5F_SIZEOF_ADDR(f);
+ oh->sizeof_size = H5F_SIZEOF_SIZE(udata->common.f);
+ oh->sizeof_addr = H5F_SIZEOF_ADDR(udata->common.f);
/* Check for presence of magic number */
/* (indicates version 2 or later) */
@@ -180,9 +219,6 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
if(oh->flags & ~H5O_HDR_ALL_FLAGS)
HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "unknown object header status flag(s)")
- /* Number of messages (to allocate initially) */
- nmesgs = 1;
-
/* Number of links to object (unless overridden by refcount message) */
oh->nlink = 1;
@@ -207,7 +243,7 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
UINT16DECODE(p, oh->max_compact);
UINT16DECODE(p, oh->min_dense);
if(oh->max_compact < oh->min_dense)
- HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header attribute phase change values")
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "bad object header attribute phase change values")
} /* end if */
else {
oh->max_compact = H5O_CRT_ATTR_MAX_COMPACT_DEF;
@@ -217,26 +253,26 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
/* First chunk size */
switch(oh->flags & H5O_HDR_CHUNK0_SIZE) {
case 0: /* 1 byte size */
- chunk_size = *p++;
+ oh->chunk0_size = *p++;
break;
case 1: /* 2 byte size */
- UINT16DECODE(p, chunk_size);
+ UINT16DECODE(p, oh->chunk0_size);
break;
case 2: /* 4 byte size */
- UINT32DECODE(p, chunk_size);
+ UINT32DECODE(p, oh->chunk0_size);
break;
case 3: /* 8 byte size */
- UINT64DECODE(p, chunk_size);
+ UINT64DECODE(p, oh->chunk0_size);
break;
default:
HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "bad size for chunk 0")
} /* end switch */
- if(chunk_size > 0 && chunk_size < H5O_SIZEOF_MSGHDR_OH(oh))
- HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header chunk size")
+ if(oh->chunk0_size > 0 && oh->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "bad object header chunk size")
} /* end if */
else {
/* Version */
@@ -251,7 +287,7 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
p++;
/* Number of messages */
- UINT16DECODE(p, nmesgs);
+ UINT16DECODE(p, udata->v1_pfx_nmesgs);
/* Link count */
UINT32DECODE(p, oh->nlink);
@@ -264,10 +300,10 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
oh->min_dense = 0;
/* First chunk size */
- UINT32DECODE(p, chunk_size);
- if((nmesgs > 0 && chunk_size < H5O_SIZEOF_MSGHDR_OH(oh)) ||
- (nmesgs == 0 && chunk_size > 0))
- HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header chunk size")
+ UINT32DECODE(p, oh->chunk0_size);
+ if((udata->v1_pfx_nmesgs > 0 && oh->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) ||
+ (udata->v1_pfx_nmesgs == 0 && oh->chunk0_size > 0))
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "bad object header chunk size")
/* Reserved, in version 1 (for 8-byte alignment padding) */
p += 4;
@@ -277,356 +313,44 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
prefix_size = (size_t)(p - (const uint8_t *)read_buf);
HDassert((size_t)prefix_size == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
- /* Compute first chunk address */
- chunk_addr = addr + (hsize_t)prefix_size;
+ /* Compute the size of the buffer used */
+ buf_size = oh->chunk0_size + (size_t)H5O_SIZEOF_HDR(oh);
- /* Allocate the message array */
- oh->alloc_nmesgs = (nmesgs > 0) ? nmesgs : 1;
- if(NULL == (oh->mesg = H5FL_SEQ_MALLOC(H5O_mesg_t, oh->alloc_nmesgs)))
- HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
-
- /* Read each chunk from disk */
- while(H5F_addr_defined(chunk_addr)) {
- unsigned chunkno; /* Current chunk's index */
-#ifndef NDEBUG
- unsigned nullcnt; /* Count of null messages (for sanity checking gaps in chunks) */
-#endif /* NDEBUG */
- uint8_t *eom_ptr; /* Pointer to end of messages for a chunk */
-
- /* Increase chunk array size, if necessary */
- if(oh->nchunks >= oh->alloc_nchunks) {
- unsigned na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */
- H5O_chunk_t *x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, (size_t)na);
-
- if(!x)
- HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
- oh->alloc_nchunks = na;
- oh->chunk = x;
- } /* end if */
-
- /* Init the chunk data info */
- chunkno = oh->nchunks++;
- oh->chunk[chunkno].dirty = FALSE;
- oh->chunk[chunkno].gap = 0;
- if(chunkno == 0) {
- /* First chunk's 'image' includes room for the object header prefix */
- oh->chunk[0].addr = addr;
- oh->chunk[0].size = chunk_size + H5O_SIZEOF_HDR(oh);
- } /* end if */
- else {
- oh->chunk[chunkno].addr = chunk_addr;
- oh->chunk[chunkno].size = chunk_size;
- } /* end else */
- if(NULL == (oh->chunk[chunkno].image = H5FL_BLK_MALLOC(chunk_image, oh->chunk[chunkno].size)))
- HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
-
- /* Handle chunk 0 as special case */
- if(chunkno == 0) {
- /* Check for speculative read of first chunk containing all the data needed */
- if(spec_read_size >= oh->chunk[0].size)
- HDmemcpy(oh->chunk[0].image, read_buf, oh->chunk[0].size);
- else {
- /* Copy the object header prefix into chunk 0's image */
- HDmemcpy(oh->chunk[0].image, read_buf, prefix_size);
-
- /* Read the chunk raw data */
- /* (probably re-reads some data we already retrieved, but since
- * we have to do the I/O operation anyway, we might as
- * well avoid memcpy()ing the data in our buffer already)
- */
- if(H5F_block_read(f, H5FD_MEM_OHDR, chunk_addr, (oh->chunk[0].size - prefix_size),
- dxpl_id, (oh->chunk[0].image + prefix_size)) < 0)
- HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header data")
- } /* end else */
-
- /* Point into chunk image to decode */
- p = oh->chunk[0].image + prefix_size;
- } /* end if */
- else {
- /* Read the chunk raw data */
- 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")
+ /* Check if the speculative read was large enough to parse the first chunk */
+ if(spec_read_size < buf_size) {
+ /* Wrap the local buffer for serialized header info */
+ if(NULL == (wb = H5WB_wrap(read_buf, sizeof(read_buf))))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't wrap buffer")
- /* Point into chunk image to decode */
- p = oh->chunk[chunkno].image;
- } /* end else */
+ /* Get a pointer to a buffer that's large enough for serialized header */
+ if(NULL == (buf = (uint8_t *)H5WB_actual(wb, buf_size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "can't get actual buffer")
- /* Check for magic # on chunks > 0 in later versions of the format */
- if(chunkno > 0 && oh->version > H5O_VERSION_1) {
- /* Magic number */
- if(HDmemcmp(p, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
- HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "wrong object header chunk signature")
- p += H5_SIZEOF_MAGIC;
- } /* end if */
+ /* Copy existing raw data into new buffer */
+ HDmemcpy(buf, read_buf, spec_read_size);
- /* Decode messages from this chunk */
- eom_ptr = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh));
-#ifndef NDEBUG
- nullcnt = 0;
-#endif /* NDEBUG */
- while(p < eom_ptr) {
- unsigned mesgno; /* Current message to operate on */
- size_t mesg_size; /* Size of message read in */
- unsigned id; /* ID (type) of current message */
- uint8_t flags; /* Flags for current message */
- H5O_msg_crt_idx_t crt_idx = 0; /* Creation index for current message */
-
- /* Decode message prefix info */
-
- /* Version # */
- if(oh->version == H5O_VERSION_1)
- UINT16DECODE(p, id)
- else
- id = *p++;
-
- /* Check for unknown message ID getting encoded in file */
- if(id == H5O_UNKNOWN_ID)
- HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "'unknown' message ID encoded in file?!?")
-
- /* Message size */
- UINT16DECODE(p, mesg_size);
- HDassert(mesg_size == H5O_ALIGN_OH(oh, mesg_size));
-
- /* Message flags */
- flags = *p++;
- if(flags & ~H5O_MSG_FLAG_BITS)
- HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unknown flag for message")
- if((flags & H5O_MSG_FLAG_SHARED) && (flags & H5O_MSG_FLAG_DONTSHARE))
- HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag combination for message")
- if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN))
- HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag combination for message")
- if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && !(flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN))
- HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag combination for message")
-
- /* Reserved bytes/creation index */
- if(oh->version == H5O_VERSION_1)
- p += 3; /*reserved*/
- else {
- /* Only decode creation index if they are being tracked */
- if(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED)
- UINT16DECODE(p, crt_idx);
- } /* end else */
-
- /* Try to detect invalidly formatted object header message that
- * extends past end of chunk.
- */
- if(p + mesg_size > eom_ptr)
- HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "corrupt object header")
-
-#ifndef NDEBUG
- /* Increment count of null messages */
- if(H5O_NULL_ID == id)
- nullcnt++;
-#endif /* NDEBUG */
-
- /* Check for combining two adjacent 'null' messages */
- if((H5F_INTENT(f) & H5F_ACC_RDWR) &&
- 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_OH(oh) + mesg_size;
- oh->mesg[mesgno].dirty = TRUE;
- merged_null_msgs++;
- } /* end if */
- else {
- /* Check if we need to extend message table to hold the new message */
- if(oh->nmesgs >= oh->alloc_nmesgs)
- if(H5O_alloc_msgs(oh, (size_t)1) < 0)
- HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "can't allocate more space for messages")
-
- /* Get index for message */
- mesgno = oh->nmesgs++;
-
- /* Initialize information about message */
- oh->mesg[mesgno].dirty = FALSE;
- oh->mesg[mesgno].flags = flags;
- oh->mesg[mesgno].crt_idx = crt_idx;
- oh->mesg[mesgno].native = NULL;
- oh->mesg[mesgno].raw = (uint8_t *)p; /* Casting away const OK - QAK */
- oh->mesg[mesgno].raw_size = mesg_size;
- oh->mesg[mesgno].chunkno = chunkno;
-
- /* Point unknown messages at 'unknown' message class */
- /* (Usually from future versions of the library) */
- if(id >= NELMTS(H5O_msg_class_g) || NULL == H5O_msg_class_g[id]) {
- H5O_unknown_t *unknown; /* Pointer to "unknown" message info */
-
- /* Allocate "unknown" message info */
- if(NULL == (unknown = H5FL_MALLOC(H5O_unknown_t)))
- HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
-
- /* Save the original message type ID */
- *unknown = id;
-
- /* Save 'native' form of unknown message */
- oh->mesg[mesgno].native = unknown;
-
- /* Set message to "unknown" class */
- oh->mesg[mesgno].type = H5O_msg_class_g[H5O_UNKNOWN_ID];
-
- /* Check for "fail if unknown" message flag */
- if(flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN)
- HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, NULL, "unknown message with 'fail if unknown' flag found")
- /* Check for "mark if unknown" message flag, etc. */
- else if((flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN) &&
- !(flags & H5O_MSG_FLAG_WAS_UNKNOWN) &&
- (H5F_INTENT(f) & H5F_ACC_RDWR)) {
-
- /* Mark the message as "unknown" */
- /* This is a bit aggressive, since the application may
- * never change anything about the object (metadata or
- * raw data), but we can sort out the finer details
- * when/if we start using the flag - QAK
- */
- /* Also, it's possible that this functionality may not
- * get invoked if the object header is brought into
- * the metadata cache in some other "weird" way, like
- * using H5Ocopy() - QAK
- */
- oh->mesg[mesgno].flags |= H5O_MSG_FLAG_WAS_UNKNOWN;
-
- /* Mark the message and object header as dirty */
- oh->mesg[mesgno].dirty = TRUE;
- oh->cache_info.is_dirty = TRUE;
- } /* end if */
- } /* end if */
- else
- /* Set message class for "known" messages */
- oh->mesg[mesgno].type = H5O_msg_class_g[id];
- } /* end else */
-
- /* Advance decode pointer past message */
- p += mesg_size;
-
- /* Check for 'gap' at end of chunk */
- if((eom_ptr - p) > 0 && (eom_ptr - p) < H5O_SIZEOF_MSGHDR_OH(oh)) {
- /* Gaps can only occur in later versions of the format */
- HDassert(oh->version > H5O_VERSION_1);
-
- /* Gaps should only occur in chunks with no null messages */
- HDassert(nullcnt == 0);
-
- /* Set gap information for chunk */
- oh->chunk[chunkno].gap = (size_t)(eom_ptr - p);
-
- /* Increment location in chunk */
- p += oh->chunk[chunkno].gap;
- } /* end if */
- } /* end while */
-
- /* Check for correct checksum on chunks, in later versions of the format */
- if(oh->version > H5O_VERSION_1) {
- uint32_t stored_chksum; /* Checksum from file */
- uint32_t computed_chksum; /* Checksum computed in memory */
-
- /* Metadata checksum */
- UINT32DECODE(p, stored_chksum);
-
- /* Compute checksum on chunk */
- computed_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0);
-
- /* Verify checksum */
- if(stored_chksum != computed_chksum)
- HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "incorrect metadata checksum for object header chunk")
- } /* end if */
-
- /* Sanity check */
- HDassert(p == oh->chunk[chunkno].image + oh->chunk[chunkno].size);
-
- /* Check for another chunk to read in & parse */
- for(chunk_addr = HADDR_UNDEF; !H5F_addr_defined(chunk_addr) && curmesg < oh->nmesgs; ++curmesg) {
- /* Check if next message to examine is a continuation message */
- if(H5O_CONT_ID == oh->mesg[curmesg].type->id) {
- H5O_cont_t *cont;
- unsigned ioflags = 0; /* Flags for decode routine */
-
- /* Decode continuation message */
- cont = (H5O_cont_t *)(H5O_MSG_CONT->decode)(f, dxpl_id, NULL, 0, &ioflags, oh->mesg[curmesg].raw);
- cont->chunkno = oh->nchunks; /*the next chunk to allocate */
-
- /* Save 'native' form of continuation message */
- oh->mesg[curmesg].native = cont;
-
- /* Set up to read in next chunk */
- chunk_addr = cont->addr;
- chunk_size = cont->size;
-
- /* Mark the object header as dirty if the message was changed by decoding */
- if((ioflags & H5O_DECODEIO_DIRTY) && (H5F_get_intent(f) & H5F_ACC_RDWR)) {
- oh->mesg[curmesg].dirty = TRUE;
- oh->cache_info.is_dirty = TRUE;
- }
- } /* end if */
- /* Check if next message to examine is a ref. count message */
- else if(H5O_REFCOUNT_ID == oh->mesg[curmesg].type->id) {
- H5O_refcount_t *refcount;
- unsigned ioflags = 0; /* Flags for decode routine */
-
- /* Decode ref. count message */
- HDassert(oh->version > H5O_VERSION_1);
- refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(f, dxpl_id, NULL, 0, &ioflags, oh->mesg[curmesg].raw);
-
- /* Save 'native' form of ref. count message */
- oh->mesg[curmesg].native = refcount;
-
- /* Set object header values */
- oh->has_refcount_msg = TRUE;
- oh->nlink = *refcount;
-
- /* Mark the object header as dirty if the message was changed by decoding */
- if((ioflags & H5O_DECODEIO_DIRTY) && (H5F_get_intent(f) & H5F_ACC_RDWR)) {
- oh->mesg[curmesg].dirty = TRUE;
- oh->cache_info.is_dirty = TRUE;
- }
- } /* end if */
- /* Check if next message to examine is a link message */
- else if(H5O_LINK_ID == oh->mesg[curmesg].type->id) {
- /* Increment the count of link messages */
- oh->link_msgs_seen++;
- } /* end if */
- /* Check if next message to examine is an attribute message */
- else if(H5O_ATTR_ID == oh->mesg[curmesg].type->id) {
- /* Increment the count of attribute messages */
- oh->attr_msgs_seen++;
- } /* end if */
- } /* end for */
- } /* end while */
-
- /* Mark the object header dirty if we've merged a message */
- if(merged_null_msgs)
- oh->cache_info.is_dirty = TRUE;
+ /* Read rest of the raw data */
+ if(H5F_block_read(f, H5FD_MEM_OHDR, (addr + spec_read_size), (buf_size - spec_read_size), dxpl_id, (buf + spec_read_size)) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header data")
+ } /* end if */
+ else
+ buf = read_buf;
-/* Don't check for the incorrect # of object header messages bug unless we've
- * enabled strict format checking. This allows for older files, created with
- * a version of the library that had a bug in tracking the correct # of header
- * messages to be read in without the library fussing about things. -QAK
- */
-#ifdef H5_STRICT_FORMAT_CHECKS
- /* Sanity check for the correct # of messages in object header */
- if(oh->version == H5O_VERSION_1)
- if((oh->nmesgs + merged_null_msgs) != nmesgs)
- HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - too few messages")
-#else /* H5_STRICT_FORMAT_CHECKS */
- /* Check for incorrect # of messages in object header and if we have write
- * access on the file, flag the object header as dirty, so it gets fixed.
- */
- if(oh->version == H5O_VERSION_1)
- if((oh->nmesgs + merged_null_msgs) != nmesgs &&
- (H5F_get_intent(f) & H5F_ACC_RDWR))
- oh->cache_info.is_dirty = TRUE;
-#endif /* H5_STRICT_FORMAT_CHECKS */
+ /* Parse the first chunk */
+ if(H5O_chunk_deserialize(oh, addr, oh->chunk0_size, buf, &(udata->common), &oh->cache_info.is_dirty) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize first object header chunk")
-#ifdef H5O_DEBUG
-H5O_assert(oh);
-#endif /* H5O_DEBUG */
+ /* Note that we've loaded the object header from the file */
+ udata->made_attempt = TRUE;
/* Set return value */
ret_value = oh;
done:
+ /* Release resources */
+ if(wb && H5WB_unwrap(wb) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CLOSEERROR, NULL, "can't close wrapped buffer")
+
/* Release the [possibly partially initialized] object header on errors */
if(!ret_value && oh)
if(H5O_free(oh) < 0)
@@ -664,7 +388,6 @@ H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t UNUSED addr, H5O_t *
/* flush */
if(oh->cache_info.is_dirty) {
uint8_t *p; /* Pointer to object header prefix buffer */
- unsigned u; /* Local index variable */
#ifdef H5O_DEBUG
H5O_assert(oh);
@@ -678,7 +401,10 @@ H5O_assert(oh);
* on the entire block of memory needs to be updated if anything is
* modified */
if(oh->version > H5O_VERSION_1) {
- uint64_t chunk0_size = oh->chunk[0].size - H5O_SIZEOF_HDR(oh); /* Size of chunk 0's data */
+ uint64_t chunk0_size; /* Size of chunk 0's data */
+
+ HDassert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh));
+ chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh);
/* Verify magic number */
HDassert(!HDmemcmp(p, H5O_HDR_MAGIC, H5_SIZEOF_MAGIC));
@@ -749,7 +475,7 @@ H5O_assert(oh);
UINT32ENCODE(p, oh->nlink);
/* First chunk size */
- UINT32ENCODE(p, (oh->chunk[0].size - H5O_SIZEOF_HDR(oh)));
+ UINT32ENCODE(p, (oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh)));
/* Zero to alignment */
HDmemset(p, 0, (size_t)(H5O_SIZEOF_HDR(oh) - 12));
@@ -757,57 +483,14 @@ H5O_assert(oh);
} /* end else */
HDassert((size_t)(p - oh->chunk[0].image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
- /* Mark chunk 0 as dirty, since the object header prefix has been updated */
- /* (this could be more sophisticated and track whether any prefix fields
- * have been changed, which could save I/O accesses if the
- * messages in chunk 0 haven't changed - QAK)
- */
- HDassert(H5F_addr_eq(addr, oh->chunk[0].addr));
- oh->chunk[0].dirty = TRUE;
-
- /* Encode any dirty messages */
- if(H5O_flush_msgs(f, oh) < 0)
- HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object header messages")
-
- /* Write each chunk to disk, if it's dirty */
- for(u = 0; u < oh->nchunks; u++) {
- /* Sanity checks */
- if(oh->version > H5O_VERSION_1)
- /* Make certain the magic # is present */
- HDassert(!HDmemcmp(oh->chunk[u].image, (u == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5_SIZEOF_MAGIC));
- else
- /* Gaps should never occur in version 1 of the format */
- HDassert(oh->chunk[u].gap == 0);
-
- /* Write out chunk, if it's dirty */
- if(oh->chunk[u].dirty) {
- /* Extra work, for later versions of the format */
- if(oh->version > H5O_VERSION_1) {
- uint32_t metadata_chksum; /* Computed metadata checksum value */
-
- /* Check for gap in chunk & zero it out */
- if(oh->chunk[u].gap)
- HDmemset((oh->chunk[u].image + oh->chunk[u].size) -
- (H5O_SIZEOF_CHKSUM + oh->chunk[u].gap), 0, oh->chunk[u].gap);
-
- /* Compute metadata checksum */
- metadata_chksum = H5_checksum_metadata(oh->chunk[u].image, (oh->chunk[u].size - H5O_SIZEOF_CHKSUM), 0);
-
- /* Metadata checksum */
- p = oh->chunk[u].image + (oh->chunk[u].size - H5O_SIZEOF_CHKSUM);
- UINT32ENCODE(p, metadata_chksum);
- } /* end if */
+ /* Serialize messages for this chunk */
+ if(H5O_chunk_serialize(f, oh, (unsigned)0) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize first object header chunk")
- /* Write the chunk out */
- HDassert(H5F_addr_defined(oh->chunk[u].addr));
- 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 chunk to disk")
-
- /* Mark chunk as clean now */
- oh->chunk[u].dirty = FALSE;
- } /* end if */
- } /* end for */
+ /* Write the chunk out */
+ HDassert(H5F_addr_defined(oh->chunk[0].addr));
+ if(H5F_block_write(f, H5FD_MEM_OHDR, oh->chunk[0].addr, oh->chunk[0].size, dxpl_id, oh->chunk[0].image) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header chunk to disk")
/* Mark object header as clean now */
oh->cache_info.is_dirty = FALSE;
@@ -845,6 +528,7 @@ H5O_dest(H5F_t *f, H5O_t *oh)
/* check args */
HDassert(oh);
+ HDassert(oh->rc == 0);
/* Verify that node is clean */
HDassert(!oh->cache_info.is_dirty);
@@ -893,17 +577,13 @@ H5O_clear(H5F_t *f, H5O_t *oh, hbool_t destroy)
/* check args */
HDassert(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;
#ifndef NDEBUG
- /* Reset the number of messages dirtied by decoding */
- oh->ndecode_dirtied = 0;
+ /* Reset the number of messages dirtied by decoding */
+ oh->ndecode_dirtied = 0;
#endif /* NDEBUG */
/* Mark whole header as clean */
@@ -935,22 +615,767 @@ done:
static herr_t
H5O_size(const H5F_t UNUSED *f, const H5O_t *oh, size_t *size_ptr)
{
- size_t size; /* Running sum of the object header's size */
- unsigned u; /* Local index variable */
-
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_size)
/* check args */
HDassert(oh);
HDassert(size_ptr);
- /* Add sizes of all the chunks */
- /* (includes size of prefix, in chunk 0) */
- for(u = 0, size = 0; u < oh->nchunks; u++)
- size += oh->chunk[u].size;
-
- *size_ptr = size;
+ /* Report the object header's prefix+first chunk length */
+ *size_ptr = (size_t)H5O_SIZEOF_HDR(oh) + oh->chunk0_size;
FUNC_LEAVE_NOAPI(SUCCEED)
} /* H5O_size() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cache_chk_load
+ *
+ * Purpose: Loads an object header continuation chunk from disk.
+ *
+ * Return: Success: Pointer to the new object header chunk proxy.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5O_chunk_proxy_t *
+H5O_cache_chk_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
+ void *_udata2)
+{
+ H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk proxy object */
+ H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata2; /* User data for callback */
+ H5WB_t *wb = NULL; /* Wrapped buffer for prefix data */
+ uint8_t chunk_buf[H5O_SPEC_READ_SIZE]; /* Buffer for speculative read */
+ uint8_t *buf; /* Buffer to decode */
+ H5O_chunk_proxy_t *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_cache_chk_load)
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(H5F_addr_defined(addr));
+ HDassert(udata);
+ HDassert(udata->oh);
+
+ /* Allocate space for the object header data structure */
+ if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
+
+ /* Wrap the local buffer for serialized header info */
+ if(NULL == (wb = H5WB_wrap(chunk_buf, sizeof(chunk_buf))))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't wrap buffer")
+
+ /* Get a pointer to a buffer that's large enough for serialized header */
+ if(NULL == (buf = (uint8_t *)H5WB_actual(wb, udata->chunk_size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "can't get actual buffer")
+
+ /* Read rest of the raw data */
+ if(H5F_block_read(f, H5FD_MEM_OHDR, addr, udata->chunk_size, dxpl_id, buf) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header continuation chunk")
+
+ /* Check if we are still decoding the object header */
+ /* (as opposed to bringing a piece of it back from the file) */
+ if(udata->decoding) {
+ /* Sanity check */
+ HDassert(udata->common.f);
+ HDassert(udata->common.cont_msg_info);
+
+ /* Parse the chunk */
+ if(H5O_chunk_deserialize(udata->oh, addr, udata->chunk_size, buf, &(udata->common), &chk_proxy->cache_info.is_dirty) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize object header chunk")
+
+ /* Set the fields for the chunk proxy */
+ chk_proxy->oh = udata->oh;
+ chk_proxy->chunkno = udata->oh->nchunks - 1;
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(udata->chunkno < udata->oh->nchunks);
+
+ /* Set the fields for the chunk proxy */
+ chk_proxy->oh = udata->oh;
+ chk_proxy->chunkno = udata->chunkno;
+
+ /* Sanity check that the chunk representation we have in memory is the same
+ * as the one being brought in from disk.
+ */
+ HDassert(0 == HDmemcmp(buf, chk_proxy->oh->chunk[chk_proxy->chunkno].image, chk_proxy->oh->chunk[chk_proxy->chunkno].size));
+ } /* end else */
+
+ /* Increment reference count of object header */
+ if(H5O_inc_rc(udata->oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "can't increment reference count on object header")
+
+ /* Set return value */
+ ret_value = chk_proxy;
+
+done:
+ /* Release resources */
+ if(wb && H5WB_unwrap(wb) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CLOSEERROR, NULL, "can't close wrapped buffer")
+
+ /* Release the [possibly partially initialized] object header on errors */
+ if(!ret_value && chk_proxy)
+ if(H5O_chunk_proxy_dest(chk_proxy) < 0)
+ HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header chunk proxy")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_cache_chk_load() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cache_chk_flush
+ *
+ * Purpose: Flushes (and destroys) an object header continuation chunk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Jul 12 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_cache_chk_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr,
+ H5O_chunk_proxy_t *chk_proxy, unsigned UNUSED * flags_ptr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_cache_chk_flush)
+
+ /* flush */
+ if(chk_proxy->cache_info.is_dirty) {
+ /* Serialize messages for this chunk */
+ if(H5O_chunk_serialize(f, chk_proxy->oh, chk_proxy->chunkno) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize object header continuation chunk")
+
+ /* Write the chunk out */
+ HDassert(H5F_addr_defined(chk_proxy->oh->chunk[chk_proxy->chunkno].addr));
+ HDassert(H5F_addr_eq(addr, chk_proxy->oh->chunk[chk_proxy->chunkno].addr));
+ if(H5F_block_write(f, H5FD_MEM_OHDR, addr, chk_proxy->oh->chunk[chk_proxy->chunkno].size, dxpl_id, chk_proxy->oh->chunk[chk_proxy->chunkno].image) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header continuation chunk to disk")
+
+ /* Mark object header as clean now */
+ chk_proxy->cache_info.is_dirty = FALSE;
+ } /* end if */
+
+ /* Destroy the object header, if requested */
+ if(destroy)
+ if(H5O_cache_chk_dest(f, chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header continuation chunk data")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_cache_chk_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cache_chk_dest
+ *
+ * Purpose: Destroys an object header continuation chunk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 12, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_cache_chk_dest(H5F_t *f, H5O_chunk_proxy_t *chk_proxy)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_cache_chk_dest)
+
+ /* Check arguments */
+ HDassert(chk_proxy);
+ HDassert(chk_proxy->chunkno > 0);
+
+ /* Verify that node is clean */
+ HDassert(chk_proxy->cache_info.is_dirty == FALSE);
+
+ /* If we're going to free the space on disk, the address must be valid */
+ HDassert(!chk_proxy->cache_info.free_file_space_on_destroy || H5F_addr_defined(chk_proxy->cache_info.addr));
+
+ /* Check for releasing file space for object header */
+ if(chk_proxy->cache_info.free_file_space_on_destroy) {
+ /* Release the space on disk */
+ /* (XXX: Nasty usage of internal DXPL value! -QAK) */
+ if(H5MF_xfree(f, H5FD_MEM_OHDR, H5AC_dxpl_id, chk_proxy->oh->chunk[chk_proxy->chunkno].addr, (hsize_t)chk_proxy->oh->chunk[chk_proxy->chunkno].size) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free object header continuation chunk")
+ } /* end if */
+
+ /* Destroy object header chunk proxy */
+ if(H5O_chunk_proxy_dest(chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header chunk proxy")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_cache_chk_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cache_chk_clear
+ *
+ * Purpose: Mark a object header continuation chunk in memory as non-dirty.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 12, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_cache_chk_clear(H5F_t *f, H5O_chunk_proxy_t *chk_proxy, hbool_t destroy)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_cache_chk_clear)
+
+ /* check args */
+ HDassert(chk_proxy);
+
+ /* Mark messages in chunk as clean */
+ for(u = 0; u < chk_proxy->oh->nmesgs; u++)
+ if(chk_proxy->oh->mesg[u].chunkno == chk_proxy->chunkno)
+ chk_proxy->oh->mesg[u].dirty = FALSE;
+
+ /* Mark as clean */
+ chk_proxy->cache_info.is_dirty = FALSE;
+
+ if(destroy)
+ if(H5O_cache_chk_dest(f, chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header continuation chunk data")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_cache_chk_clear() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_cache_chk_size
+ *
+ * Purpose: Compute the size in bytes of the specified instance of
+ * an object header continuation chunk on disk, and return it in
+ * *len_ptr. On failure, the value of *len_ptr is undefined.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 12, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_cache_chk_size(const H5F_t UNUSED *f, const H5O_chunk_proxy_t *chk_proxy, size_t *size_ptr)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_cache_chk_size)
+
+ /* check args */
+ HDassert(chk_proxy);
+ HDassert(size_ptr);
+
+ /* Report the object header continuation chunk's length */
+ *size_ptr = chk_proxy->oh->chunk[chk_proxy->chunkno].size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5O_cache_chk_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_add_cont_msg
+ *
+ * Purpose: Add information from a continuation message to the list of
+ * continuation messages in the object header
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 12, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_add_cont_msg(H5O_cont_msgs_t *cont_msg_info, const H5O_cont_t *cont)
+{
+ unsigned contno; /* Continuation message index */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_add_cont_msg)
+
+ /* Check arguments */
+ HDassert(cont_msg_info);
+ HDassert(cont);
+
+ /* Increase chunk array size, if necessary */
+ if(cont_msg_info->nmsgs >= cont_msg_info->alloc_nmsgs) {
+ unsigned na = MAX(H5O_NCHUNKS, cont_msg_info->alloc_nmsgs * 2); /* Double # of messages allocated */
+ H5O_cont_t *x = H5FL_SEQ_REALLOC(H5O_cont_t, cont_msg_info->msgs, (size_t)na);
+
+ if(!x)
+ HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "memory allocation failed")
+ cont_msg_info->alloc_nmsgs = na;
+ cont_msg_info->msgs = x;
+ } /* end if */
+
+ /* Init the continuation message info */
+ contno = cont_msg_info->nmsgs++;
+ cont_msg_info->msgs[contno].addr = cont->addr;
+ cont_msg_info->msgs[contno].size = cont->size;
+ cont_msg_info->msgs[contno].chunkno = cont->chunkno;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_add_cont_msg() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_chunk_deserialize
+ *
+ * Purpose: Deserialize a chunk for an object header
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 12, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image,
+ H5O_common_cache_ud_t *udata, hbool_t *dirty)
+{
+ const uint8_t *p; /* Pointer into buffer to decode */
+ uint8_t *eom_ptr; /* Pointer to end of messages for a chunk */
+ unsigned curmesg; /* Current message being decoded in object header */
+ unsigned merged_null_msgs = 0; /* Number of null messages merged together */
+ unsigned chunkno; /* Current chunk's index */
+#ifndef NDEBUG
+ unsigned nullcnt; /* Count of null messages (for sanity checking gaps in chunks) */
+#endif /* NDEBUG */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_chunk_deserialize)
+
+ /* Check arguments */
+ HDassert(oh);
+ HDassert(image);
+ HDassert(udata->f);
+ HDassert(udata->cont_msg_info);
+
+ /* Increase chunk array size, if necessary */
+ if(oh->nchunks >= oh->alloc_nchunks) {
+ unsigned na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */
+ H5O_chunk_t *x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, (size_t)na);
+
+ if(!x)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ oh->alloc_nchunks = na;
+ oh->chunk = x;
+ } /* end if */
+
+ /* Init the chunk data info */
+ chunkno = oh->nchunks++;
+ oh->chunk[chunkno].gap = 0;
+ if(chunkno == 0) {
+ /* First chunk's 'image' includes room for the object header prefix */
+ oh->chunk[0].addr = addr;
+ oh->chunk[0].size = len + (size_t)H5O_SIZEOF_HDR(oh);
+ } /* end if */
+ else {
+ oh->chunk[chunkno].addr = addr;
+ oh->chunk[chunkno].size = len;
+ } /* end else */
+ if(NULL == (oh->chunk[chunkno].image = H5FL_BLK_MALLOC(chunk_image, oh->chunk[chunkno].size)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ /* Copy disk image into chunk's image */
+ HDmemcpy(oh->chunk[chunkno].image, image, oh->chunk[chunkno].size);
+
+ /* Point into chunk image to decode */
+ p = oh->chunk[chunkno].image;
+
+ /* Handle chunk 0 as special case */
+ if(chunkno == 0)
+ /* Skip over [already decoded] prefix */
+ p += (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh));
+ /* Check for magic # on chunks > 0 in later versions of the format */
+ else if(chunkno > 0 && oh->version > H5O_VERSION_1) {
+ /* Magic number */
+ if(HDmemcmp(p, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "wrong object header chunk signature")
+ p += H5_SIZEOF_MAGIC;
+ } /* end if */
+
+ /* Save # of messages already inspected */
+ curmesg = oh->nmesgs;
+
+ /* Decode messages from this chunk */
+ eom_ptr = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh));
+#ifndef NDEBUG
+ nullcnt = 0;
+#endif /* NDEBUG */
+ while(p < eom_ptr) {
+ unsigned mesgno; /* Current message to operate on */
+ size_t mesg_size; /* Size of message read in */
+ unsigned id; /* ID (type) of current message */
+ uint8_t flags; /* Flags for current message */
+ H5O_msg_crt_idx_t crt_idx = 0; /* Creation index for current message */
+
+ /* Decode message prefix info */
+
+ /* Version # */
+ if(oh->version == H5O_VERSION_1)
+ UINT16DECODE(p, id)
+ else
+ id = *p++;
+
+ /* Check for unknown message ID getting encoded in file */
+ if(id == H5O_UNKNOWN_ID)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "'unknown' message ID encoded in file?!?")
+
+ /* Message size */
+ UINT16DECODE(p, mesg_size);
+ HDassert(mesg_size == H5O_ALIGN_OH(oh, mesg_size));
+
+ /* Message flags */
+ flags = *p++;
+ if(flags & ~H5O_MSG_FLAG_BITS)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unknown flag for message")
+ if((flags & H5O_MSG_FLAG_SHARED) && (flags & H5O_MSG_FLAG_DONTSHARE))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
+ if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
+ if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && !(flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
+
+ /* Reserved bytes/creation index */
+ if(oh->version == H5O_VERSION_1)
+ p += 3; /*reserved*/
+ else {
+ /* Only decode creation index if they are being tracked */
+ if(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED)
+ UINT16DECODE(p, crt_idx);
+ } /* end else */
+
+ /* Try to detect invalidly formatted object header message that
+ * extends past end of chunk.
+ */
+ if(p + mesg_size > eom_ptr)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "corrupt object header")
+
+#ifndef NDEBUG
+ /* Increment count of null messages */
+ if(H5O_NULL_ID == id)
+ nullcnt++;
+#endif /* NDEBUG */
+
+ /* Check for combining two adjacent 'null' messages */
+ if((udata->file_intent & H5F_ACC_RDWR) &&
+ 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_OH(oh) + mesg_size;
+ oh->mesg[mesgno].dirty = TRUE;
+ merged_null_msgs++;
+ udata->merged_null_msgs++;
+ } /* end if */
+ else {
+ /* Check if we need to extend message table to hold the new message */
+ if(oh->nmesgs >= oh->alloc_nmesgs)
+ if(H5O_alloc_msgs(oh, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate more space for messages")
+
+ /* Get index for message */
+ mesgno = oh->nmesgs++;
+
+ /* Initialize information about message */
+ oh->mesg[mesgno].dirty = FALSE;
+ oh->mesg[mesgno].flags = flags;
+ oh->mesg[mesgno].crt_idx = crt_idx;
+ oh->mesg[mesgno].native = NULL;
+ oh->mesg[mesgno].raw = (uint8_t *)p; /* Casting away const OK - QAK */
+ oh->mesg[mesgno].raw_size = mesg_size;
+ oh->mesg[mesgno].chunkno = chunkno;
+
+ /* Point unknown messages at 'unknown' message class */
+ /* (Usually from future versions of the library) */
+ if(id >= NELMTS(H5O_msg_class_g) || NULL == H5O_msg_class_g[id]) {
+ H5O_unknown_t *unknown; /* Pointer to "unknown" message info */
+
+ /* Allocate "unknown" message info */
+ if(NULL == (unknown = H5FL_MALLOC(H5O_unknown_t)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
+
+ /* Save the original message type ID */
+ *unknown = id;
+
+ /* Save 'native' form of unknown message */
+ oh->mesg[mesgno].native = unknown;
+
+ /* Set message to "unknown" class */
+ oh->mesg[mesgno].type = H5O_msg_class_g[H5O_UNKNOWN_ID];
+
+ /* Check for "fail if unknown" message flag */
+ if(flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "unknown message with 'fail if unknown' flag found")
+ /* Check for "mark if unknown" message flag, etc. */
+ else if((flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN) &&
+ !(flags & H5O_MSG_FLAG_WAS_UNKNOWN) &&
+ (udata->file_intent & H5F_ACC_RDWR)) {
+
+ /* Mark the message as "unknown" */
+ /* This is a bit aggressive, since the application may
+ * never change anything about the object (metadata or
+ * raw data), but we can sort out the finer details
+ * when/if we start using the flag - QAK
+ */
+ /* Also, it's possible that this functionality may not
+ * get invoked if the object header is brought into
+ * the metadata cache in some other "weird" way, like
+ * using H5Ocopy() - QAK
+ */
+ oh->mesg[mesgno].flags |= H5O_MSG_FLAG_WAS_UNKNOWN;
+
+ /* Mark the message and chunk as dirty */
+ oh->mesg[mesgno].dirty = TRUE;
+ udata->mesgs_modified = TRUE;
+ *dirty = TRUE;
+ } /* end if */
+ } /* end if */
+ else
+ /* Set message class for "known" messages */
+ oh->mesg[mesgno].type = H5O_msg_class_g[id];
+ } /* end else */
+
+ /* Advance decode pointer past message */
+ p += mesg_size;
+
+ /* Check for 'gap' at end of chunk */
+ if((eom_ptr - p) > 0 && (eom_ptr - p) < H5O_SIZEOF_MSGHDR_OH(oh)) {
+ /* Gaps can only occur in later versions of the format */
+ HDassert(oh->version > H5O_VERSION_1);
+
+ /* Gaps should only occur in chunks with no null messages */
+ HDassert(nullcnt == 0);
+
+ /* Set gap information for chunk */
+ oh->chunk[chunkno].gap = (size_t)(eom_ptr - p);
+
+ /* Increment location in chunk */
+ p += oh->chunk[chunkno].gap;
+ } /* end if */
+ } /* end while */
+
+ /* Check for correct checksum on chunks, in later versions of the format */
+ if(oh->version > H5O_VERSION_1) {
+ uint32_t stored_chksum; /* Checksum from file */
+ uint32_t computed_chksum; /* Checksum computed in memory */
+
+ /* Metadata checksum */
+ UINT32DECODE(p, stored_chksum);
+
+ /* Compute checksum on chunk */
+ computed_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0);
+
+ /* Verify checksum */
+ if(stored_chksum != computed_chksum)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "incorrect metadata checksum for object header chunk")
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(p == oh->chunk[chunkno].image + oh->chunk[chunkno].size);
+
+ /* Do some inspection/interpretation of new messages from this chunk */
+ /* (detect continuation messages, ref. count messages, etc.) */
+ while(curmesg < oh->nmesgs) {
+ /* Check if next message to examine is a continuation message */
+ if(H5O_CONT_ID == oh->mesg[curmesg].type->id) {
+ H5O_cont_t *cont;
+ unsigned ioflags = 0; /* Flags for decode routine */
+
+ /* Decode continuation message */
+ cont = (H5O_cont_t *)(H5O_MSG_CONT->decode)(udata->f, udata->dxpl_id, NULL, 0, &ioflags, oh->mesg[curmesg].raw);
+ cont->chunkno = udata->cont_msg_info->nmsgs + 1; /*the next continuation message/chunk */
+
+ /* Save 'native' form of continuation message */
+ oh->mesg[curmesg].native = cont;
+
+ /* Add to continuation messages left to interpret */
+ if(H5O_add_cont_msg(udata->cont_msg_info, cont) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add continuation message")
+
+ /* Mark the message & chunk as dirty if the message was changed by decoding */
+ if((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) {
+ oh->mesg[curmesg].dirty = TRUE;
+ udata->mesgs_modified = TRUE;
+ *dirty = TRUE;
+ } /* end if */
+ } /* end if */
+ /* Check if next message to examine is a ref. count message */
+ else if(H5O_REFCOUNT_ID == oh->mesg[curmesg].type->id) {
+ H5O_refcount_t *refcount;
+ unsigned ioflags = 0; /* Flags for decode routine */
+
+ /* Decode ref. count message */
+ HDassert(oh->version > H5O_VERSION_1);
+ refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(udata->f, udata->dxpl_id, NULL, 0, &ioflags, oh->mesg[curmesg].raw);
+
+ /* Save 'native' form of ref. count message */
+ oh->mesg[curmesg].native = refcount;
+
+ /* Set object header values */
+ oh->has_refcount_msg = TRUE;
+ oh->nlink = *refcount;
+
+ /* Mark the message & chunk as dirty if the message was changed by decoding */
+ if((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) {
+ oh->mesg[curmesg].dirty = TRUE;
+ udata->mesgs_modified = TRUE;
+ *dirty = TRUE;
+ } /* end if */
+ } /* end if */
+ /* Check if next message to examine is a link message */
+ else if(H5O_LINK_ID == oh->mesg[curmesg].type->id) {
+ /* Increment the count of link messages */
+ oh->link_msgs_seen++;
+ } /* end if */
+ /* Check if next message to examine is an attribute message */
+ else if(H5O_ATTR_ID == oh->mesg[curmesg].type->id) {
+ /* Increment the count of attribute messages */
+ oh->attr_msgs_seen++;
+ } /* end if */
+
+ /* Advance to next message */
+ curmesg++;
+ } /* end while */
+
+ /* Mark the chunk dirty if we've merged null messages */
+ if(merged_null_msgs) {
+ udata->mesgs_modified = TRUE;
+ *dirty = TRUE;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_chunk_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_chunk_serialize
+ *
+ * Purpose: Serialize a chunk for an object header
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 12, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno)
+{
+ H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_chunk_serialize)
+
+ /* Check arguments */
+ HDassert(f);
+ HDassert(oh);
+
+ /* Encode any dirty messages in this chunk */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++)
+ if(curr_msg->dirty && curr_msg->chunkno == chunkno)
+ /* Casting away const OK -QAK */
+ if(H5O_msg_flush((H5F_t *)f, oh, curr_msg) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message")
+
+ /* Sanity checks */
+ if(oh->version > H5O_VERSION_1)
+ /* Make certain the magic # is present */
+ HDassert(!HDmemcmp(oh->chunk[chunkno].image, (chunkno == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5_SIZEOF_MAGIC));
+ else
+ /* Gaps should never occur in version 1 of the format */
+ HDassert(oh->chunk[chunkno].gap == 0);
+
+ /* Extra work, for later versions of the format */
+ if(oh->version > H5O_VERSION_1) {
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ uint8_t *p; /* Pointer into object header chunk */
+
+ /* Check for gap in chunk & zero it out */
+ if(oh->chunk[chunkno].gap)
+ HDmemset((oh->chunk[chunkno].image + oh->chunk[chunkno].size) -
+ (H5O_SIZEOF_CHKSUM + oh->chunk[chunkno].gap), 0, oh->chunk[chunkno].gap);
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0);
+
+ /* Metadata checksum */
+ p = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM);
+ UINT32ENCODE(p, metadata_chksum);
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_chunk_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_chunk_proxy_dest
+ *
+ * Purpose: Destroy a chunk proxy object
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * July 13, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_chunk_proxy_dest(H5O_chunk_proxy_t *chk_proxy)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_chunk_proxy_dest)
+
+ /* Check arguments */
+ HDassert(chk_proxy);
+
+ /* Decrement reference count of object header */
+ if(H5O_dec_rc(chk_proxy->oh) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "can't decrement reference count on object header")
+
+ /* Release the chunk proxy object */
+ chk_proxy = H5FL_FREE(H5O_chunk_proxy_t, chk_proxy);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5O_chunk_proxy_dest() */
+