summaryrefslogtreecommitdiffstats
path: root/src/H5Ocache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5Ocache.c')
-rw-r--r--src/H5Ocache.c161
1 files changed, 113 insertions, 48 deletions
diff --git a/src/H5Ocache.c b/src/H5Ocache.c
index 75f9d69..d574fe8 100644
--- a/src/H5Ocache.c
+++ b/src/H5Ocache.c
@@ -30,6 +30,7 @@
#define H5O_PACKAGE /*suppress error about including H5Opkg */
+
/***********/
/* Headers */
/***********/
@@ -38,6 +39,7 @@
#include "H5FLprivate.h" /* Free lists */
#include "H5Opkg.h" /* Object headers */
+
/****************/
/* Local Macros */
/****************/
@@ -80,6 +82,9 @@ static herr_t H5O_size(const H5F_t *f, const H5O_t *oh, size_t *size_ptr);
/* Library Private Variables */
/*****************************/
+/* Declare external the free list for H5O_unknown_t's */
+H5FL_EXTERN(H5O_unknown_t);
+
/*******************/
/* Local Variables */
@@ -126,15 +131,22 @@ H5O_flush_msgs(H5F_t *f, H5O_t *oh)
for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
if(curr_msg->dirty) {
uint8_t *p; /* Temporary pointer to encode with */
+ unsigned msg_id; /* ID for message */
/* Point into message's chunk's image */
p = curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh);
+ /* Retrieve actual message ID, for unknown messages */
+ if(curr_msg->type == H5O_MSG_UNKNOWN)
+ msg_id = *(H5O_unknown_t *)(curr_msg->native);
+ else
+ msg_id = (uint8_t)curr_msg->type->id;
+
/* Encode the message prefix */
if(oh->version == H5O_VERSION_1)
- UINT16ENCODE(p, curr_msg->type->id)
+ UINT16ENCODE(p, msg_id)
else
- *p++ = (uint8_t)curr_msg->type->id;
+ *p++ = (uint8_t)msg_id;
HDassert(curr_msg->raw_size < H5O_MESG_MAX_SIZE);
UINT16ENCODE(p, curr_msg->raw_size);
*p++ = curr_msg->flags;
@@ -155,12 +167,16 @@ H5O_flush_msgs(H5F_t *f, H5O_t *oh)
#ifndef NDEBUG
/* Make certain that null messages aren't in chunks w/gaps */
- if(H5O_NULL_ID == curr_msg->type->id)
+ if(H5O_NULL_ID == msg_id)
HDassert(oh->chunk[curr_msg->chunkno].gap == 0);
+
+ /* Unknown messages should always have a native pointer */
+ if(curr_msg->type == H5O_MSG_UNKNOWN)
+ HDassert(curr_msg->native);
#endif /* NDEBUG */
- /* Encode the message itself */
- if(curr_msg->native) {
+ /* Encode the message itself, if it's not an "unknown" message */
+ if(curr_msg->native && curr_msg->type != H5O_MSG_UNKNOWN) {
/*
* Encode the message. If the message is shared then we
* encode a Shared Object message instead of the object
@@ -226,7 +242,6 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
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 skipped_msgs = 0; /* Number of unknown messages skipped */
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 */
@@ -474,12 +489,24 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
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)
@@ -496,51 +523,89 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
if(p + mesg_size > eom_ptr)
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(H5O_msg_class_g) || NULL == H5O_msg_class_g[id]) {
- /* Increment the size of the message skipped over (for later sanity checking) */
- oh->skipped_mesg_size += H5O_SIZEOF_MSGHDR_OH(oh) + mesg_size;
-
- /* Increment skipped messages counter */
- skipped_msgs++;
- } /* end if */
- else {
#ifndef NDEBUG
- /* Increment count of null messages */
- if(H5O_NULL_ID == id)
- nullcnt++;
+ /* Increment count of null messages */
+ if(H5O_NULL_ID == id)
+ nullcnt++;
#endif /* NDEBUG */
- /* Check for combining two adjacent 'null' messages */
- if((H5F_get_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++;
+ /* Check for combining two adjacent 'null' messages */
+ if((H5F_get_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_RESOURCE, H5E_NOSPACE, 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_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Save the original message type ID */
+ *unknown = id;
+
+ /* Save 'native' form of continuation 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_get_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 {
- /* 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_RESOURCE, H5E_NOSPACE, NULL, "can't allocate more space for messages")
-
- /* Record information about message */
- mesgno = oh->nmesgs++;
+ else
+ /* Set message class for "known" messages */
oh->mesg[mesgno].type = H5O_msg_class_g[id];
- 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;
- } /* end else */
} /* end else */
/* Advance decode pointer past message */
@@ -632,7 +697,7 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
/* Sanity check for the correct # of messages in object header */
if(oh->version == H5O_VERSION_1)
- if((oh->nmesgs + skipped_msgs + merged_null_msgs) != nmesgs)
+ if((oh->nmesgs + merged_null_msgs) != nmesgs)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - too few messages")
#ifdef H5O_DEBUG
@@ -645,7 +710,7 @@ H5O_assert(oh);
done:
/* Release the [possibly partially initialized] object header on errors */
if(!ret_value && oh)
- if(H5O_dest(f,oh) < 0)
+ if(H5O_dest(f, oh) < 0)
HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, NULL, "unable to destroy object header data")
FUNC_LEAVE_NOAPI(ret_value)