diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/H5O.c | 34 | ||||
-rw-r--r-- | src/H5Oalloc.c | 209 | ||||
-rw-r--r-- | src/H5Ocache.c | 61 | ||||
-rw-r--r-- | src/H5Ocopy.c | 68 | ||||
-rw-r--r-- | src/H5Opkg.h | 9 | ||||
-rw-r--r-- | src/H5Oprivate.h | 8 | ||||
-rw-r--r-- | src/H5Orefcount.c | 324 | ||||
-rwxr-xr-x | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/Makefile.in | 5 |
9 files changed, 614 insertions, 107 deletions
@@ -103,6 +103,7 @@ const H5O_msg_class_t *const H5O_msg_class_g[] = { H5O_MSG_BTREEK, /*0x0013 Non-default v1 B-tree 'K' values */ H5O_MSG_DRVINFO, /*0x0014 Driver info settings */ H5O_MSG_AINFO, /*0x0015 Attribute information */ + H5O_MSG_REFCOUNT, /*0x0016 Object's ref. count */ }; /* Header object ID to class mapping */ @@ -989,8 +990,7 @@ H5O_link(const H5O_loc_t *loc, int adjust, hid_t dxpl_id) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file") /* get header */ - if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, - NULL, NULL, H5AC_WRITE))) + if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* adjust link count */ @@ -1033,6 +1033,36 @@ H5O_link(const H5O_loc_t *loc, int adjust, hid_t dxpl_id) oh_flags |= H5AC__DIRTIED_FLAG; } /* end if */ + /* Check for operations on refcount message */ + if(oh->version > H5O_VERSION_1) { + /* Check if the object has a refcount message already */ + if(oh->has_refcount_msg) { + /* Check for removing refcount message */ + if(oh->nlink <= 1) { + if(H5O_msg_remove_real(loc->file, oh, H5O_MSG_REFCOUNT, H5O_ALL, NULL, NULL, TRUE, dxpl_id) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete refcount message") + oh->has_refcount_msg = FALSE; + } /* end if */ + /* Update refcount message with new link count */ + else { + H5O_refcount_t refcount = oh->nlink; + + if(H5O_msg_write_real(loc->file, dxpl_id, oh, H5O_MSG_REFCOUNT, H5O_MSG_FLAG_DONTSHARE, 0, &refcount) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update refcount message") + } /* end else */ + } /* end if */ + else { + /* Check for adding refcount message to object */ + if(oh->nlink > 1) { + H5O_refcount_t refcount = oh->nlink; + + if(H5O_msg_append_real(loc->file, dxpl_id, oh, H5O_MSG_REFCOUNT, H5O_MSG_FLAG_DONTSHARE, 0, &refcount) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new refcount message") + oh->has_refcount_msg = TRUE; + } /* end if */ + } /* end else */ + } /* end if */ + /* Set return value */ ret_value = oh->nlink; diff --git a/src/H5Oalloc.c b/src/H5Oalloc.c index b03a774..ce20a27 100644 --- a/src/H5Oalloc.c +++ b/src/H5Oalloc.c @@ -632,6 +632,15 @@ done: * * SIZE need not be aligned. * + * Note: The algorithm for finding a message to replace with a + * continuation message is still fairly limited. It's possible + * that two (or more) messages smaller than a continuation message + * might occupy a chunk and need to be moved in order to make + * room for the continuation message. + * + * Also, we aren't checking for NULL messages in front of another + * message right now... + * * 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 @@ -651,11 +660,20 @@ H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size) { + /* Struct for storing information about "best" messages to allocate from */ + typedef struct { + int msgno; /* Index in message array */ + size_t gap_size; /* Size of any "gap" in the chunk immediately after message */ + size_t null_size; /* Size of any null message in the chunk immediately after message */ + size_t total_size; /* Total size of "available" space around message */ + unsigned null_msgno; /* Message index of null message immediately after message */ + } alloc_info; + + H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ size_t cont_size; /*continuation message size */ - int found_null = (-1); /*best fit null message */ - int found_attr = (-1); /*best fit attribute message */ - int found_link = (-1); /*best fit link message */ - int found_other = (-1); /*best fit other message */ + int found_null = (-1); /* Best fit null message */ + alloc_info found_attr = {-1, 0, 0, 0, 0}; /* Best fit attribute message */ + alloc_info found_other = {-1, 0, 0, 0, 0}; /* Best fit other message */ unsigned idx; /*message number */ uint8_t *p = NULL; /*ptr into new chunk */ H5O_cont_t *cont = NULL; /*native continuation message */ @@ -677,81 +695,114 @@ H5O_alloc_new_chunk(H5F_t *f, * that could be moved to make room for the continuation message. * * Don't ever move continuation message from one chunk to another. - * Prioritize link messages moving to later chunks, instead of - * more "important" messages. + * * Avoid moving attributes when possible to preserve their * ordering (although ordering is *not* guaranteed!). * */ cont_size = H5O_ALIGN_OH(oh, H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f)); - for(u = 0; u < oh->nmesgs; u++) { - int msg_id = oh->mesg[u].type->id; /* Temp. copy of message type ID */ + for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { + if(curr_msg->type->id == H5O_NULL_ID) { + if(cont_size == curr_msg->raw_size) { + found_null = u; + break; + } /* end if */ + else if(curr_msg->raw_size > cont_size && + (found_null < 0 || curr_msg->raw_size < oh->mesg[found_null].raw_size)) + found_null = u; + } /* end if */ + else if(curr_msg->type->id == H5O_CONT_ID) { + /* Don't consider continuation messages (for now) */ + } /* end if */ + else { + unsigned msg_chunkno = curr_msg->chunkno; /* Chunk that the message is in */ + uint8_t *end_chunk_data = (oh->chunk[msg_chunkno].image + oh->chunk[msg_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[msg_chunkno].gap); /* End of message data in chunk */ + uint8_t *end_msg = curr_msg->raw + curr_msg->raw_size; /* End of current message */ + size_t gap_size = 0; /* Size of gap after current message */ + size_t null_size = 0; /* Size of NULL message after current message */ + unsigned null_msgno; /* Index of NULL message after current message */ + size_t total_size; /* Total size of available space "around" current message */ + + /* Check if the message is the last one in the chunk */ + if(end_msg == end_chunk_data) + gap_size = oh->chunk[msg_chunkno].gap; + else { + H5O_mesg_t *tmp_msg; /* Temp. pointer to message to operate on */ + unsigned v; /* Local index variable */ + + /* Check for null message after this message, in same chunk */ + for(v = 0, tmp_msg = &oh->mesg[0]; v < oh->nmesgs; v++, tmp_msg++) { + if(tmp_msg->type->id == H5O_NULL_ID && (tmp_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == end_msg) { + null_msgno = v; + null_size = H5O_SIZEOF_MSGHDR_OH(oh) + tmp_msg->raw_size; + break; + } /* end if */ - if(H5O_NULL_ID == msg_id) { - if(cont_size == oh->mesg[u].raw_size) { - found_null = u; - break; - } else if(oh->mesg[u].raw_size >= cont_size && - (found_null < 0 || - oh->mesg[u].raw_size < oh->mesg[found_null].raw_size)) { - found_null = u; - } - } else if(H5O_CONT_ID == msg_id) { - /*don't consider continuation messages */ - } else if(H5O_ATTR_ID == msg_id) { - if(oh->mesg[u].raw_size >= cont_size && - (found_attr < 0 || - oh->mesg[u].raw_size < oh->mesg[found_attr].raw_size)) - found_attr = u; - } else if(H5O_LINK_ID == msg_id) { - if(oh->mesg[u].raw_size >= cont_size && - (found_link < 0 || - oh->mesg[u].raw_size < oh->mesg[found_link].raw_size)) - found_link = u; - } else { - if(oh->mesg[u].raw_size >= cont_size && - (found_other < 0 || - oh->mesg[u].raw_size < oh->mesg[found_other].raw_size)) - found_other = u; - } /* end else */ + /* XXX: Should also check for NULL message in front of current message... */ + + } /* end for */ + } /* end else */ + + /* Add up current message's total available space */ + total_size = curr_msg->raw_size + gap_size + null_size; + + /* Check if message is large enough to hold continuation info */ + if(total_size >= cont_size) { + if(curr_msg->type->id == H5O_ATTR_ID) { + if(found_attr.msgno < 0 || total_size < found_attr.total_size) { + found_attr.msgno = u; + found_attr.gap_size = gap_size; + found_attr.null_size = null_size; + found_attr.total_size = total_size; + found_attr.null_msgno = null_msgno; + } /* end if */ + } /* end if */ + else { + if(found_other.msgno < 0 || total_size < found_other.total_size) { + found_other.msgno = u; + found_other.gap_size = gap_size; + found_other.null_size = null_size; + found_other.total_size = total_size; + found_other.null_msgno = null_msgno; + } /* end if */ + } /* end else */ + } /* end if */ + } /* end else */ } /* end for */ - HDassert(found_null >= 0 || found_attr >= 0 || found_link >= 0 || found_other >= 0); + if(found_null < 0 && found_attr.msgno < 0 && found_other.msgno < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to locate message to move") /* * 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. * - * Move link messages first, then other messages, and attributes - * only as a last resort. + * Move other messages first, and attributes only as a last resort. * */ if(found_null < 0) { - if(found_link >= 0) - found_other = found_link; - - if(found_other < 0) + if(found_other.msgno < 0) found_other = found_attr; - HDassert(found_other >= 0); - size += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; + HDassert(found_other.msgno >= 0); + size += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size; } /* end if */ /* + * The total chunk size must include the requested space plus enough + * for the message header. This must be at least some minimum and + * aligned propertly. + */ + size = MAX(H5O_MIN_SIZE, size + H5O_SIZEOF_MSGHDR_OH(oh)); + HDassert(size == H5O_ALIGN_OH(oh, size)); + + /* * The total chunk size must include enough space for the checksum * on the chunk and the continuation chunk magic #. (which are only present * in later versions of the object header) */ size += H5O_SIZEOF_CHKHDR_OH(oh); - /* - * The total chunk size must include the requested space plus enough - * for the message header. This must be at least some minimum and a - * multiple of the alignment size. - */ - size = MAX(H5O_MIN_SIZE, size + H5O_SIZEOF_MSGHDR_OH(oh)); - HDassert(size == H5O_ALIGN_OH(oh, size)); - /* allocate space in file to hold the new chunk */ new_chunk_addr = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)size); if(HADDR_UNDEF == new_chunk_addr) @@ -806,22 +857,51 @@ H5O_alloc_new_chunk(H5F_t *f, null_msg->type = H5O_MSG_NULL; null_msg->dirty = TRUE; null_msg->native = NULL; - null_msg->raw = oh->mesg[found_other].raw; - null_msg->raw_size = oh->mesg[found_other].raw_size; - null_msg->chunkno = oh->mesg[found_other].chunkno; + null_msg->raw = oh->mesg[found_other.msgno].raw; + null_msg->raw_size = oh->mesg[found_other.msgno].raw_size; + null_msg->chunkno = oh->mesg[found_other.msgno].chunkno; - /* Copy the message to move to its new location */ + /* Copy the message to move (& its prefix) to its new location */ /* (Chunk is already dirty, no need to mark it) */ - HDmemcpy(p, oh->mesg[found_other].raw - H5O_SIZEOF_MSGHDR_OH(oh), - oh->mesg[found_other].raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); + HDmemcpy(p, oh->mesg[found_other.msgno].raw - H5O_SIZEOF_MSGHDR_OH(oh), + oh->mesg[found_other.msgno].raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); - /* Switch message to point to new location */ - oh->mesg[found_other].raw = p + H5O_SIZEOF_MSGHDR_OH(oh); - oh->mesg[found_other].chunkno = chunkno; + /* Switch moved message to point to new location */ + oh->mesg[found_other.msgno].raw = p + H5O_SIZEOF_MSGHDR_OH(oh); + oh->mesg[found_other.msgno].chunkno = chunkno; /* Account for copied message in new chunk */ - p += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; - size -= H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; + p += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size; + size -= H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size; + + /* Add any available space after the message to move to the new null message */ + if(found_other.gap_size > 0) { + /* Absorb a gap after the moved message */ + HDassert(oh->chunk[null_msg->chunkno].gap == found_other.gap_size); + null_msg->raw_size += found_other.gap_size; + oh->chunk[null_msg->chunkno].gap = 0; + } /* end if */ + else if(found_other.null_size > 0) { + H5O_mesg_t *old_null_msg = &oh->mesg[found_other.null_msgno]; /* Pointer to NULL message to eliminate */ + + /* Absorb a null message after the moved message */ + HDassert((null_msg->raw + null_msg->raw_size) == (old_null_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh))); + null_msg->raw_size += found_other.null_size; + + /* Release any information/memory for message */ + H5O_msg_free_mesg(old_null_msg); + + /* Remove null message from list of messages */ + if(found_other.null_msgno < (oh->nmesgs - 1)) + HDmemmove(old_null_msg, old_null_msg + 1, ((oh->nmesgs - 1) - found_other.null_msgno) * sizeof(H5O_mesg_t)); + + /* Decrement # of messages */ + /* (Don't bother reducing size of message array for now -QAK) */ + oh->nmesgs--; + + /* Adjust message index for new NULL message */ + found_null--; + } /* end if */ } /* end if */ HDassert(found_null >= 0); @@ -832,8 +912,7 @@ H5O_alloc_new_chunk(H5F_t *f, oh->mesg[idx].dirty = TRUE; oh->mesg[idx].native = NULL; oh->mesg[idx].raw = p + H5O_SIZEOF_MSGHDR_OH(oh); - oh->mesg[idx].raw_size = size - - (H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh)); + oh->mesg[idx].raw_size = size - (H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh)); oh->mesg[idx].chunkno = chunkno; /* Initialize the continuation information */ diff --git a/src/H5Ocache.c b/src/H5Ocache.c index 142d23f..2a76526 100644 --- a/src/H5Ocache.c +++ b/src/H5Ocache.c @@ -44,8 +44,8 @@ /* Set the object header size to speculatively read in */ /* (needs to be more than the object header prefix size to work at all and - * should be larger than the default dataset object header to save the - * extra I/O operations) */ + * should be larger than the largest object type's default object header + * size to save the extra I/O operations) */ #define H5O_SPEC_READ_SIZE 512 @@ -283,28 +283,10 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, /* Number of messages (to allocate initially) */ nmesgs = 1; - } /* end if */ - else { - /* Version */ - oh->version = *p++; - if(H5O_VERSION_1 != oh->version) - HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header version number") - - /* Flags */ - oh->flags = H5O_CRT_OHDR_FLAGS_DEF; - - /* Reserved */ - p++; - - /* Number of messages */ - UINT16DECODE(p, nmesgs); - } /* end else */ - /* Link count */ - UINT32DECODE(p, oh->nlink); + /* Number of links to object (unless overridden by refcount message) */ + oh->nlink = 1; - /* Version-specific fields */ - if(oh->version > H5O_VERSION_1) { /* Time fields */ if(oh->flags & H5O_HDR_STORE_TIMES) { UINT32DECODE(p, oh->atime); @@ -348,6 +330,23 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, } /* end switch */ } /* end if */ else { + /* Version */ + oh->version = *p++; + if(H5O_VERSION_1 != oh->version) + HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header version number") + + /* Flags */ + oh->flags = H5O_CRT_OHDR_FLAGS_DEF; + + /* Reserved */ + p++; + + /* Number of messages */ + UINT16DECODE(p, nmesgs); + + /* Link count */ + UINT32DECODE(p, oh->nlink); + /* Reset unused time fields */ oh->atime = oh->mtime = oh->ctime = oh->btime = 0; @@ -592,6 +591,21 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, chunk_addr = cont->addr; chunk_size = cont->size; } /* 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; + + /* Decode ref. count message */ + HDassert(oh->version > H5O_VERSION_1); + refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(f, dxpl_id, 0, 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; + } /* end if */ } /* end for */ } /* end while */ @@ -681,9 +695,6 @@ H5O_assert(oh); /* Flags */ *p++ = oh->flags; - /* Link count */ - UINT32ENCODE(p, oh->nlink); - /* Time fields */ if(oh->flags & H5O_HDR_STORE_TIMES) { UINT32ENCODE(p, oh->atime); diff --git a/src/H5Ocopy.c b/src/H5Ocopy.c index ee2a63e..ec51f00 100644 --- a/src/H5Ocopy.c +++ b/src/H5Ocopy.c @@ -295,12 +295,15 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, haddr_t addr_new = HADDR_UNDEF; hbool_t *deleted = NULL; /* Array of flags indicating whether messages should be copied */ size_t null_msgs; /* Number of NULL messages found in each loop */ + size_t orig_dst_msgs; /* Original # of messages in dest. object */ H5O_mesg_t *mesg_src; /* Message in source object header */ H5O_mesg_t *mesg_dst; /* Message in source object header */ const H5O_msg_class_t *copy_type; /* Type of message to use for copying */ const H5O_obj_class_t *obj_class = NULL; /* Type of object we are copying */ void *udata = NULL; /* User data for passing to message callbacks */ size_t dst_oh_size; /* Total size of the destination OH */ + size_t dst_oh_null; /* Size of the null message to add to destination OH */ + unsigned dst_oh_gap; /* Size of the gap in chunk #0 of destination OH */ uint8_t *current_pos; /* Current position in destination image */ size_t msghdr_size; hbool_t shared; /* Whether copy_file callback created a shared message */ @@ -535,6 +538,27 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, oh_dst->flags |= H5O_HDR_CHUNK0_2; } /* end if */ + /* Check if the chunk's data portion is too small */ + dst_oh_gap = dst_oh_null = 0; + if(dst_oh_size < H5O_MIN_SIZE) { + size_t delta = (H5O_MIN_SIZE - dst_oh_size); /* Delta in chunk size needed */ + + /* Sanity check */ + HDassert((oh_dst->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_1); + + /* Determine whether to create gap or NULL message */ + if(delta < H5O_SIZEOF_MSGHDR_OH(oh_dst)) + dst_oh_gap = delta; + else + dst_oh_null = delta; + + /* Increase destination object header size */ + dst_oh_size += delta; + + /* Sanity check */ + HDassert(dst_oh_size <= 255); + } /* end if */ + /* Add in destination's object header size now */ dst_oh_size += H5O_SIZEOF_HDR(oh_dst); @@ -550,7 +574,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, /* Set dest. chunk information */ oh_dst->chunk[0].dirty = TRUE; oh_dst->chunk[0].size = dst_oh_size; - oh_dst->chunk[0].gap = 0; + oh_dst->chunk[0].gap = dst_oh_gap; /* Set up raw pointers and copy messages that didn't need special * treatment. This has to happen after the destination header has been @@ -568,7 +592,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, HDmemcpy(current_pos, H5O_HDR_MAGIC, (size_t)H5O_SIZEOF_MAGIC); current_pos += H5O_SIZEOF_HDR(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst); - /* Copy each message that wasn't dirtied above */ + /* Loop through destination messages, updating their "raw" info */ null_msgs = 0; for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { /* Skip any deleted or NULL messages in the source unless the @@ -585,17 +609,43 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, mesg_src = &(oh_src->mesg[mesgno + null_msgs]); mesg_dst = &(oh_dst->mesg[mesgno]); - if(!mesg_dst->dirty) { + /* Copy each message that wasn't dirtied above */ + if(!mesg_dst->dirty) /* Copy the message header plus the message's raw data. */ - HDmemcpy(current_pos, mesg_src->raw - msghdr_size, - msghdr_size + mesg_src->raw_size); - } /* end if */ + HDmemcpy(current_pos, mesg_src->raw - msghdr_size, msghdr_size + mesg_src->raw_size); + + /* Set message's raw pointer to destination chunk's new "image" */ mesg_dst->raw = current_pos + msghdr_size; + + /* Move to location where next message should go */ current_pos += mesg_dst->raw_size + msghdr_size; } /* end for */ + /* Save this in case more messages are added during NULL message checking */ + orig_dst_msgs = oh_dst->nmesgs; + + /* Check if we need to add a NULL message to this header */ + if(dst_oh_null > 0) { + unsigned null_idx; /* Index of new NULL message */ + + /* Make sure we have enough space for new NULL message */ + if(oh_dst->nmesgs + 1 > oh_dst->alloc_nmesgs) + if(H5O_alloc_msgs(oh_dst, (size_t)1) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") + + /* Create null message for [rest of] space in new chunk */ + /* (account for chunk's magic # & checksum) */ + null_idx = oh_dst->nmesgs++; + oh_dst->mesg[null_idx].type = H5O_MSG_NULL; + oh_dst->mesg[null_idx].dirty = TRUE; + oh_dst->mesg[null_idx].native = NULL; + oh_dst->mesg[null_idx].raw = current_pos + msghdr_size; + oh_dst->mesg[null_idx].raw_size = dst_oh_null - msghdr_size; + oh_dst->mesg[null_idx].chunkno = 0; + } /* end if */ + /* Make sure we filled the chunk, except for room at the end for a checksum */ - HDassert(current_pos + H5O_SIZEOF_CHKSUM_OH(oh_dst) == dst_oh_size + oh_dst->chunk[0].image); + HDassert(current_pos + dst_oh_gap + dst_oh_null + H5O_SIZEOF_CHKSUM_OH(oh_dst) == dst_oh_size + oh_dst->chunk[0].image); /* Set the dest. object location to the first chunk address */ HDassert(H5F_addr_defined(addr_new)); @@ -620,7 +670,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, * object header for destination object */ null_msgs = 0; - for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { + for(mesgno = 0; mesgno < orig_dst_msgs; mesgno++) { /* Skip any deleted or NULL messages in the source unless the * preserve_null flag is set */ @@ -657,7 +707,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, /* Indicate that the destination address will no longer be locked */ addr_map->is_locked = FALSE; - /* Increment object header's reference count, if any descendents have created links to link to this object */ + /* Increment object header's reference count, if any descendents have created links to this object */ if(addr_map->inc_ref_count) { H5_CHECK_OVERFLOW(addr_map->inc_ref_count, hsize_t, unsigned); oh_dst->nlink += (unsigned)addr_map->inc_ref_count; diff --git a/src/H5Opkg.h b/src/H5Opkg.h index 0eed076..68a286d 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -29,8 +29,8 @@ /* Object header macros */ #define H5O_NMESGS 8 /*initial number of messages */ #define H5O_NCHUNKS 2 /*initial number of chunks */ -#define H5O_MIN_SIZE 32 /*min obj header data size */ -#define H5O_MSG_TYPES 22 /* # of types of messages */ +#define H5O_MIN_SIZE 22 /* Min. obj header data size (must be big enough for a message prefix and a continuation message) */ +#define H5O_MSG_TYPES 23 /* # of types of messages */ #define H5O_MAX_CRT_ORDER_IDX 65535 /* Max. creation order index value */ /* Versions of object header structure */ @@ -109,7 +109,6 @@ (H5O_SIZEOF_MAGIC + /*magic number */ \ 1 + /*version number */ \ 1 + /*flags */ \ - 4 + /*reference count */ \ (((O)->flags & H5O_HDR_STORE_TIMES) ? ( \ 4 + /*access time */ \ 4 + /*modification time */ \ @@ -247,6 +246,7 @@ struct H5O_t { size_t sizeof_addr; /* Size of file addresses */ /* Object information (stored) */ + hbool_t has_refcount_msg; /* Whether the object has a ref. count message */ unsigned nlink; /*link count */ uint8_t version; /*version number */ uint8_t flags; /*flags */ @@ -434,6 +434,9 @@ H5_DLLVAR const H5O_msg_class_t H5O_MSG_DRVINFO[1]; /* Attribute Information Message. (0x0015) */ H5_DLLVAR const H5O_msg_class_t H5O_MSG_AINFO[1]; +/* Reference Count Message. (0x0016) */ +H5_DLLVAR const H5O_msg_class_t H5O_MSG_REFCOUNT[1]; + /* * Object header "object" types diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index eca29e2..60d7a1d 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -135,6 +135,7 @@ typedef struct H5O_copy_t { #define H5O_BTREEK_ID 0x0013 /* v1 B-tree 'K' values message. */ #define H5O_DRVINFO_ID 0x0014 /* Driver info message. */ #define H5O_AINFO_ID 0x0015 /* Attribute info message. */ +#define H5O_REFCOUNT_ID 0x0016 /* Reference count message. */ /* Shared object message flags. @@ -429,6 +430,13 @@ typedef struct H5O_ainfo_t { haddr_t name_bt2_addr; /* Address of v2 B-tree for indexing names of "dense" attributes */ } H5O_ainfo_t; +/* + * Reference Count Message. + * (Contains # of links to object, if >1) + * (Data structure in memory) + */ +typedef uint32_t H5O_refcount_t; + /* Typedef for iteration operations */ typedef herr_t (*H5O_operator_t)(const void *mesg/*in*/, unsigned idx, diff --git a/src/H5Orefcount.c b/src/H5Orefcount.c new file mode 100644 index 0000000..8f49b8c --- /dev/null +++ b/src/H5Orefcount.c @@ -0,0 +1,324 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * 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://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Orefcount.c + * Mar 10 2007 + * Quincey Koziol <koziol@hdfgroup.org> + * + * Purpose: Object ref. count messages. + * + *------------------------------------------------------------------------- + */ + +#define H5O_PACKAGE /*suppress error about including H5Opkg */ + +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free lists */ +#include "H5Opkg.h" /* Object headers */ + + +/* PRIVATE PROTOTYPES */ +static void *H5O_refcount_decode(H5F_t *f, hid_t dxpl_id, unsigned mesg_flags, const uint8_t *p); +static herr_t H5O_refcount_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg); +static void *H5O_refcount_copy(const void *_mesg, void *_dest); +static size_t H5O_refcount_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg); +static herr_t H5O_refcount_free(void *_mesg); +static herr_t H5O_refcount_pre_copy_file(H5F_t *file_src, const void *mesg_src, + hbool_t *deleted, const H5O_copy_t *cpy_info, void *udata); +static herr_t H5O_refcount_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, + FILE * stream, int indent, int fwidth); + +/* This message derives from H5O message class */ +const H5O_msg_class_t H5O_MSG_REFCOUNT[1] = {{ + H5O_REFCOUNT_ID, /*message id number */ + "refcount", /*message name for debugging */ + sizeof(H5O_refcount_t), /*native message size */ + FALSE, /* messages are sharable? */ + H5O_refcount_decode, /*decode message */ + H5O_refcount_encode, /*encode message */ + H5O_refcount_copy, /*copy the native value */ + H5O_refcount_size, /*size of symbol table entry */ + NULL, /*default reset method */ + H5O_refcount_free, /* free method */ + NULL, /* file delete method */ + NULL, /* link method */ + NULL, /*set share method */ + NULL, /*can share method */ + H5O_refcount_pre_copy_file, /* pre copy native value to file */ + NULL, /* copy native value to file */ + NULL, /* post copy native value to file */ + NULL, /* get creation index */ + NULL, /* set creation index */ + H5O_refcount_debug /*debug the message */ +}}; + +/* Current version of ref. count information */ +#define H5O_REFCOUNT_VERSION 0 + +/* Declare a free list to manage the H5O_refcount_t struct */ +H5FL_DEFINE_STATIC(H5O_refcount_t); + + +/*------------------------------------------------------------------------- + * Function: H5O_refcount_decode + * + * Purpose: Decode a message and return a pointer to a newly allocated one. + * + * Return: Success: Ptr to new message in native form. + * Failure: NULL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 10 2007 + * + *------------------------------------------------------------------------- + */ +static void * +H5O_refcount_decode(H5F_t *f, hid_t UNUSED dxpl_id, unsigned UNUSED mesg_flags, + const uint8_t *p) +{ + H5O_refcount_t *refcount = NULL; /* Reference count */ + void *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_refcount_decode) + + /* check args */ + HDassert(f); + HDassert(p); + + /* Version of message */ + if(*p++ != H5O_REFCOUNT_VERSION) + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message") + + /* Allocate space for message */ + if(NULL == (refcount = H5FL_MALLOC(H5O_refcount_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Get ref. count for object */ + UINT32DECODE(p, *refcount) + + /* Set return value */ + ret_value = refcount; + +done: + if(ret_value == NULL && refcount != NULL) + H5FL_FREE(H5O_refcount_t, refcount); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_refcount_decode() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_refcount_encode + * + * Purpose: Encodes a message. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 10 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_refcount_encode(H5F_t *f, hbool_t UNUSED disable_shared, uint8_t *p, const void *_mesg) +{ + const H5O_refcount_t *refcount = (const H5O_refcount_t *)_mesg; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_refcount_encode) + + /* check args */ + HDassert(f); + HDassert(p); + HDassert(refcount); + + /* Message version */ + *p++ = H5O_REFCOUNT_VERSION; + + /* Object's ref. count */ + UINT32ENCODE(p, *refcount); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O_refcount_encode() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_refcount_copy + * + * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if + * necessary. + * + * Return: Success: Ptr to _DEST + * Failure: NULL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 10 2007 + * + *------------------------------------------------------------------------- + */ +static void * +H5O_refcount_copy(const void *_mesg, void *_dest) +{ + const H5O_refcount_t *refcount = (const H5O_refcount_t *)_mesg; + H5O_refcount_t *dest = (H5O_refcount_t *) _dest; + void *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_refcount_copy) + + /* check args */ + HDassert(refcount); + if(!dest && NULL == (dest = H5FL_MALLOC(H5O_refcount_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* copy */ + *dest = *refcount; + + /* Set return value */ + ret_value = dest; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_refcount_copy() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_refcount_size + * + * Purpose: Returns the size of the raw message in bytes not counting + * the message type or size fields, but only the data fields. + * This function doesn't take into account alignment. + * + * Return: Success: Message data size in bytes without alignment. + * Failure: zero + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 10 2007 + * + *------------------------------------------------------------------------- + */ +static size_t +H5O_refcount_size(const H5F_t *f, hbool_t UNUSED disable_shared, const void *_mesg) +{ + const H5O_refcount_t *refcount = (const H5O_refcount_t *)_mesg; + size_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_refcount_size) + + /* Set return value */ + ret_value = 1 /* Version */ + + 4; /* Ref. count */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_refcount_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_refcount_free + * + * Purpose: Free's the message + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, March 10, 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_refcount_free(void *mesg) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_refcount_free) + + HDassert(mesg); + + H5FL_FREE(H5O_refcount_t, mesg); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O_refcount_free() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_refcount_pre_copy_file + * + * Purpose: Perform any necessary actions before copying message between + * files. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Saturday, March 10, 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_refcount_pre_copy_file(H5F_t UNUSED *file_src, const void UNUSED *native_src, + hbool_t *deleted, const H5O_copy_t *cpy_info, void UNUSED *udata) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_refcount_pre_copy_file) + + /* check args */ + HDassert(deleted); + HDassert(cpy_info); + + /* Always delete this message when copying objects between files. Let + * the copy routine set the correct ref. count. + */ + *deleted = TRUE; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O_refcount_pre_copy_file() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_refcount_debug + * + * Purpose: Prints debugging info for a message. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 6 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_refcount_debug(H5F_t UNUSED *f, hid_t UNUSED dxpl_id, const void *_mesg, FILE * stream, + int indent, int fwidth) +{ + const H5O_refcount_t *refcount = (const H5O_refcount_t *) _mesg; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_refcount_debug) + + /* check args */ + HDassert(f); + HDassert(refcount); + HDassert(stream); + HDassert(indent >= 0); + HDassert(fwidth >= 0); + + HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, + "Number of links:", (unsigned)*refcount); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O_refcount_debug() */ + diff --git a/src/Makefile.am b/src/Makefile.am index 8375f3a1..ced4713 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,7 +67,8 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5Ofill.c H5Oginfo.c \ H5Olayout.c \ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \ - H5Oname.c H5Onull.c H5Opline.c H5Osdspace.c H5Oshared.c H5Ostab.c \ + H5Oname.c H5Onull.c H5Opline.c H5Orefcount.c \ + H5Osdspace.c H5Oshared.c H5Ostab.c \ H5Oshmesg.c H5Otest.c \ H5P.c H5Pacpl.c H5Pdcpl.c H5Pdxpl.c H5Pfapl.c H5Pfcpl.c H5Pfmpl.c \ H5Pgcpl.c \ diff --git a/src/Makefile.in b/src/Makefile.in index bc614d6..1c1bb6e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -105,7 +105,7 @@ am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \ H5Obtreek.lo H5Ocache.lo H5Ocont.lo H5Ocopy.lo H5Odbg.lo \ H5Odrvinfo.lo H5Odtype.lo H5Oefl.lo H5Ofill.lo H5Oginfo.lo \ H5Olayout.lo H5Olinfo.lo H5Olink.lo H5Omessage.lo H5Omtime.lo \ - H5Oname.lo H5Onull.lo H5Opline.lo H5Osdspace.lo H5Oshared.lo \ + H5Oname.lo H5Onull.lo H5Opline.lo H5Orefcount.lo H5Osdspace.lo H5Oshared.lo \ H5Ostab.lo H5Oshmesg.lo H5Otest.lo H5P.lo H5Pacpl.lo \ H5Pdcpl.lo H5Pdxpl.lo H5Pfapl.lo H5Pfcpl.lo H5Pfmpl.lo \ H5Pgcpl.lo H5Plapl.lo H5Plcpl.lo H5Pocpl.lo H5Pocpypl.lo \ @@ -426,7 +426,7 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5Ofill.c H5Oginfo.c \ H5Olayout.c \ H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \ - H5Oname.c H5Onull.c H5Opline.c H5Osdspace.c H5Oshared.c H5Ostab.c \ + H5Oname.c H5Onull.c H5Opline.c H5Orefcount.c H5Osdspace.c H5Oshared.c H5Ostab.c \ H5Oshmesg.c H5Otest.c \ H5P.c H5Pacpl.c H5Pdcpl.c H5Pdxpl.c H5Pfapl.c H5Pfcpl.c H5Pfmpl.c \ H5Pgcpl.c \ @@ -694,6 +694,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oname.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Onull.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Opline.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Orefcount.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Osdspace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oshared.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oshmesg.Plo@am__quote@ |