From 44f312b183305cf37295595bfd3f5df40fc637be Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sat, 3 Mar 2007 23:28:09 -0500 Subject: [svn-r13449] Description: Add object creation property (H5P[s|g]et_obj_track_times) to disable storing timestamps on objects, which makes the object's header size smaller. Also, added object header status flags to H5O_info_t struct (for H5Oget_info/H5Oget_info_by_idx) and cleaned up other field names in the struct as well. Tested on: FreeBSD/32 6.2 (duty) Mac OS X/32 10.4.8 (amazon) --- src/H5Gdeprec.c | 4 +- src/H5O.c | 128 +++++++++++++++++-------------- src/H5Oattribute.c | 36 ++++++--- src/H5Ocache.c | 34 ++++++--- src/H5Opkg.h | 19 +++-- src/H5Oprivate.h | 2 - src/H5Opublic.h | 24 ++++-- src/H5Pocpl.c | 126 +++++++++++++++++++++++++++--- src/H5Ppublic.h | 2 + test/links.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++------- 10 files changed, 463 insertions(+), 133 deletions(-) diff --git a/src/H5Gdeprec.c b/src/H5Gdeprec.c index 5f7942e..5dbb1d2 100644 --- a/src/H5Gdeprec.c +++ b/src/H5Gdeprec.c @@ -905,8 +905,8 @@ H5G_get_objinfo_cb(H5G_loc_t *grp_loc/*in*/, const char UNUSED *name, const H5O_ statbuf->mtime = oinfo.ctime; /* Retrieve the object header information */ - statbuf->ohdr.size = oinfo.hdr.hdr_size; - statbuf->ohdr.free = oinfo.hdr.free_space; + statbuf->ohdr.size = oinfo.hdr.space.total; + statbuf->ohdr.free = oinfo.hdr.space.free; statbuf->ohdr.nmesgs = oinfo.hdr.nmesgs; statbuf->ohdr.nchunks = oinfo.hdr.nchunks; } /* end if */ diff --git a/src/H5O.c b/src/H5O.c index 7b0584f..874b4c8 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -676,9 +676,6 @@ H5O_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, hid_t ocpl_id, if(oh->version > H5O_VERSION_1) { H5P_genplist_t *oc_plist; /* Object creation property list */ - /* Initialize all time fields with current time */ - oh->atime = oh->mtime = oh->ctime = oh->btime = H5_now(); - /* Get the property list */ if(NULL == (oc_plist = H5I_object(ocpl_id))) HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a property list") @@ -695,12 +692,21 @@ H5O_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, hid_t ocpl_id, if(H5P_get(oc_plist, H5O_CRT_OHDR_FLAGS_NAME, &oh->flags) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags") + /* Initialize all time fields with current time */ + if(oh->flags & H5O_HDR_STORE_TIMES) + oh->atime = oh->mtime = oh->ctime = oh->btime = H5_now(); + else + oh->atime = oh->mtime = oh->ctime = oh->btime = 0; + /* Set starting values for attribute info */ oh->attr_fheap_addr = HADDR_UNDEF; oh->name_bt2_addr = HADDR_UNDEF; oh->corder_bt2_addr = HADDR_UNDEF; } /* end if */ else { + /* Flags */ + oh->flags = H5O_CRT_OHDR_FLAGS_DEF; + /* Reset unused time fields */ oh->atime = oh->mtime = oh->ctime = oh->btime = 0; @@ -1109,55 +1115,58 @@ H5O_touch_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hbool_t force) HDassert(f); HDassert(oh); - /* Get current time */ - now = H5_now(); + /* Check if this object header is tracking times */ + if(oh->flags & H5O_HDR_STORE_TIMES) { + /* Get current time */ + now = H5_now(); - /* Check version, to determine how to store time information */ - if(oh->version == H5O_VERSION_1) { - unsigned idx; /* Index of modification time message to update */ + /* Check version, to determine how to store time information */ + if(oh->version == H5O_VERSION_1) { + unsigned idx; /* Index of modification time message to update */ - /* Look for existing message */ - for(idx = 0; idx < oh->nmesgs; idx++) - if(H5O_MSG_MTIME == oh->mesg[idx].type || H5O_MSG_MTIME_NEW == oh->mesg[idx].type) - break; + /* Look for existing message */ + for(idx = 0; idx < oh->nmesgs; idx++) + if(H5O_MSG_MTIME == oh->mesg[idx].type || H5O_MSG_MTIME_NEW == oh->mesg[idx].type) + break; - /* Create a new message, if necessary */ - if(idx == oh->nmesgs) { - unsigned mesg_flags = 0; /* Flags for message in object header */ + /* Create a new message, if necessary */ + if(idx == oh->nmesgs) { + unsigned mesg_flags = 0; /* Flags for message in object header */ - /* If we would have to create a new message, but we aren't 'forcing' it, get out now */ - if(!force) - HGOTO_DONE(SUCCEED); /*nothing to do*/ + /* If we would have to create a new message, but we aren't 'forcing' it, get out now */ + if(!force) + HGOTO_DONE(SUCCEED); /*nothing to do*/ - /* Allocate space for the modification time message */ - if((idx = H5O_msg_alloc(f, dxpl_id, oh, H5O_MSG_MTIME_NEW, &mesg_flags, &now)) == UFAIL) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for modification time message") + /* Allocate space for the modification time message */ + if((idx = H5O_msg_alloc(f, dxpl_id, oh, H5O_MSG_MTIME_NEW, &mesg_flags, &now)) == UFAIL) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for modification time message") - /* Set the message's flags if appropriate */ - oh->mesg[idx].flags = mesg_flags; - } /* end if */ + /* Set the message's flags if appropriate */ + oh->mesg[idx].flags = mesg_flags; + } /* end if */ - /* Allocate 'native' space, if necessary */ - if(NULL == oh->mesg[idx].native) { - if(NULL == (oh->mesg[idx].native = H5FL_MALLOC(time_t))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "memory allocation failed for modification time message") - } /* end if */ + /* Allocate 'native' space, if necessary */ + if(NULL == oh->mesg[idx].native) { + if(NULL == (oh->mesg[idx].native = H5FL_MALLOC(time_t))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "memory allocation failed for modification time message") + } /* end if */ - /* Update the message */ - *((time_t *)(oh->mesg[idx].native)) = now; + /* Update the message */ + *((time_t *)(oh->mesg[idx].native)) = now; - /* Mark the message as dirty */ - oh->mesg[idx].dirty = TRUE; - } /* end if */ - else { - /* XXX: For now, update access time & change fields in the object header */ - /* (will need to add some code to update modification time appropriately) */ - oh->atime = oh->ctime = now; - } /* end else */ + /* Mark the message as dirty */ + oh->mesg[idx].dirty = TRUE; + } /* end if */ + else { + /* XXX: For now, update access time & change fields in the object header */ + /* (will need to add some code to update modification time appropriately) */ + oh->atime = oh->ctime = now; + } /* end else */ - /* Mark object header as dirty in cache */ - if(H5AC_mark_pinned_or_protected_entry_dirty(f, oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty") + /* Mark object header as dirty in cache */ + if(H5AC_mark_pinned_or_protected_entry_dirty(f, oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty") + } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) @@ -1857,13 +1866,16 @@ H5O_get_info(H5O_loc_t *oloc, H5O_info_t *oinfo, hid_t dxpl_id) oinfo->hdr.nmesgs = oh->nmesgs; oinfo->hdr.nchunks = oh->nchunks; + /* Set the status flags */ + oinfo->hdr.flags = oh->flags; + /* Iterate over all the messages, accumulating message size & type information */ oinfo->num_attrs = 0; - oinfo->hdr.meta_space = H5O_SIZEOF_HDR(oh) + (H5O_SIZEOF_CHKHDR_OH(oh) * (oh->nchunks - 1)); - oinfo->hdr.mesg_space = 0; - oinfo->hdr.free_space = 0; - oinfo->hdr.msg_present = 0; - oinfo->hdr.msg_shared = 0; + oinfo->hdr.space.meta = H5O_SIZEOF_HDR(oh) + (H5O_SIZEOF_CHKHDR_OH(oh) * (oh->nchunks - 1)); + oinfo->hdr.space.mesg = 0; + oinfo->hdr.space.free = 0; + oinfo->hdr.mesg.present = 0; + oinfo->hdr.mesg.shared = 0; for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { uint64_t type_flag; /* Flag for message type */ @@ -1873,21 +1885,21 @@ H5O_get_info(H5O_loc_t *oloc, H5O_info_t *oinfo, hid_t dxpl_id) /* Accumulate information, based on the type of message */ if(H5O_NULL_ID == curr_msg->type->id) - oinfo->hdr.free_space += H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size; + oinfo->hdr.space.free += H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size; else if(H5O_CONT_ID == curr_msg->type->id) - oinfo->hdr.meta_space += H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size; + oinfo->hdr.space.meta += H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size; else { - oinfo->hdr.meta_space += H5O_SIZEOF_MSGHDR_OH(oh); - oinfo->hdr.mesg_space += curr_msg->raw_size; + oinfo->hdr.space.meta += H5O_SIZEOF_MSGHDR_OH(oh); + oinfo->hdr.space.mesg += curr_msg->raw_size; } /* end else */ - /* Set flag to indicate present of message type */ + /* Set flag to indicate presence of message type */ type_flag = ((uint64_t)1) << curr_msg->type->id; - oinfo->hdr.msg_present |= type_flag; + oinfo->hdr.mesg.present |= type_flag; /* Set flag if the message is shared in some way */ if(curr_msg->flags & H5O_MSG_FLAG_SHARED) \ - oinfo->hdr.msg_shared |= type_flag; + oinfo->hdr.mesg.shared |= type_flag; } /* end for */ /* Sanity checking, etc. for # of attributes */ @@ -1901,17 +1913,17 @@ H5O_get_info(H5O_loc_t *oloc, H5O_info_t *oinfo, hid_t dxpl_id) } /* end if */ /* Iterate over all the chunks, adding any gaps to the free space */ - oinfo->hdr.hdr_size = 0; + oinfo->hdr.space.total = 0; for(u = 0, curr_chunk = &oh->chunk[0]; u < oh->nchunks; u++, curr_chunk++) { /* Accumulate the size of the header on header */ - oinfo->hdr.hdr_size += curr_chunk->size; + oinfo->hdr.space.total += curr_chunk->size; /* If the chunk has a gap, add it to the free space */ - oinfo->hdr.free_space += curr_chunk->gap; + oinfo->hdr.space.free += curr_chunk->gap; } /* end for */ /* Sanity check that all the bytes are accounted for */ - HDassert(oinfo->hdr.hdr_size == (oinfo->hdr.free_space + oinfo->hdr.meta_space + oinfo->hdr.mesg_space + oh->skipped_mesg_size)); + HDassert(oinfo->hdr.space.total == (oinfo->hdr.space.free + oinfo->hdr.space.meta + oinfo->hdr.space.mesg + oh->skipped_mesg_size)); done: if(oh && H5AC_unprotect(oloc->file, dxpl_id, H5AC_OHDR, oloc->addr, oh, H5AC__NO_FLAGS_SET) < 0) diff --git a/src/H5Oattribute.c b/src/H5Oattribute.c index 92c0887..ac76f78 100644 --- a/src/H5Oattribute.c +++ b/src/H5Oattribute.c @@ -671,6 +671,7 @@ herr_t H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr) { H5O_t *oh = NULL; /* Pointer to actual object header */ + unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_write) @@ -714,8 +715,11 @@ H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr) if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") + /* Indicate that the object header was modified */ + oh_flags |= H5AC__DIRTIED_FLAG; + done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) HDONE_ERROR(H5E_ATTR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -948,15 +952,15 @@ H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id, const char *old_name, /* Check that we found the attribute to rename */ if(!udata.found) HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute with old name") - - /* Indicate that the object header was modified */ - oh_flags |= H5AC__DIRTIED_FLAG; } /* end else */ /* Update the modification time, if any */ if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") + /* Indicate that the object header was modified */ + oh_flags |= H5AC__DIRTIED_FLAG; + done: if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) HDONE_ERROR(H5E_ATTR, H5E_PROTECT, FAIL, "unable to release object header") @@ -1175,10 +1179,6 @@ H5O_attr_remove_update(const H5O_loc_t *loc, H5O_t *oh, hid_t dxpl_id) /* Remove the dense storage */ if(H5A_dense_delete(loc->file, dxpl_id, oh) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete dense attribute storage") - - /* Update the modification time, if any */ - if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") } /* end if */ /* Free attribute table information */ @@ -1264,6 +1264,7 @@ herr_t H5O_attr_remove(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) { H5O_t *oh = NULL; /* Pointer to actual object header */ + unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_remove) @@ -1310,8 +1311,15 @@ H5O_attr_remove(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) if(H5O_attr_remove_update(loc, oh, dxpl_id) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info") + /* Update the modification time, if any */ + if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") + + /* Indicate that the object header was modified */ + oh_flags |= H5AC__DIRTIED_FLAG; + done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) HDONE_ERROR(H5E_ATTR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -1336,6 +1344,7 @@ H5O_attr_remove_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t dxpl_id) { H5O_t *oh = NULL; /* Pointer to actual object header */ + unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */ H5A_attr_table_t atable = {0, NULL}; /* Table of attributes */ herr_t ret_value = SUCCEED; /* Return value */ @@ -1390,8 +1399,15 @@ H5O_attr_remove_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, if(H5O_attr_remove_update(loc, oh, dxpl_id) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info") + /* Update the modification time, if any */ + if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") + + /* Indicate that the object header was modified */ + oh_flags |= H5AC__DIRTIED_FLAG; + done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) HDONE_ERROR(H5E_ATTR, H5E_PROTECT, FAIL, "unable to release object header") if(atable.attrs && H5A_attr_release_table(&atable) < 0) HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table") diff --git a/src/H5Ocache.c b/src/H5Ocache.c index 194ebf4..48e3a6d 100644 --- a/src/H5Ocache.c +++ b/src/H5Ocache.c @@ -43,7 +43,9 @@ /****************/ /* Set the object header size to speculatively read in */ -/* (needs to be more than the default dataset header size) */ +/* (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) */ #define H5O_SPEC_READ_SIZE 512 @@ -281,6 +283,9 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, 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++; } /* end else */ @@ -294,10 +299,14 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, /* Version-specific fields */ if(oh->version > H5O_VERSION_1) { /* Time fields */ - UINT32DECODE(p, oh->atime); - UINT32DECODE(p, oh->mtime); - UINT32DECODE(p, oh->ctime); - UINT32DECODE(p, oh->btime); + if(oh->flags & H5O_HDR_STORE_TIMES) { + UINT32DECODE(p, oh->atime); + UINT32DECODE(p, oh->mtime); + UINT32DECODE(p, oh->ctime); + UINT32DECODE(p, oh->btime); + } /* end if */ + else + oh->atime = oh->mtime = oh->ctime = oh->btime = 0; /* Attribute fields */ UINT16DECODE(p, oh->max_compact); @@ -331,6 +340,7 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, /* Determine object header prefix length */ prefix_size = (size_t)(p - 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; @@ -385,6 +395,10 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, 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") @@ -634,10 +648,12 @@ H5O_assert(oh); UINT32ENCODE(p, oh->nlink); /* Time fields */ - UINT32ENCODE(p, oh->atime); - UINT32ENCODE(p, oh->mtime); - UINT32ENCODE(p, oh->ctime); - UINT32ENCODE(p, oh->btime); + if(oh->flags & H5O_HDR_STORE_TIMES) { + UINT32ENCODE(p, oh->atime); + UINT32ENCODE(p, oh->mtime); + UINT32ENCODE(p, oh->ctime); + UINT32ENCODE(p, oh->btime); + } /* end if */ /* Attribute fields */ UINT16ENCODE(p, oh->max_compact); diff --git a/src/H5Opkg.h b/src/H5Opkg.h index 6ed310e..6825210 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -40,7 +40,7 @@ #define H5O_VERSION_1 1 /* Revised version - leaves out reserved bytes and alignment padding, and adds - * magic number as prefix and checksum + * magic number as prefix and checksum as suffix for all chunks. */ #define H5O_VERSION_2 2 @@ -78,6 +78,9 @@ /* Size of checksum (on disk) */ #define H5O_SIZEOF_CHKSUM 4 +/* Default value for object header status flags */ +#define H5O_CRT_OHDR_FLAGS_DEF H5O_HDR_STORE_TIMES + /* * Size of object header prefix. */ @@ -95,10 +98,12 @@ 1 + /*flags */ \ 2 + /*number of messages */ \ 4 + /*reference count */ \ - 4 + /*access time */ \ - 4 + /*modification time */ \ - 4 + /*change time */ \ - 4 + /*birth time */ \ + (((O)->flags & H5O_HDR_STORE_TIMES) ? ( \ + 4 + /*access time */ \ + 4 + /*modification time */ \ + 4 + /*change time */ \ + 4 /*birth time */ \ + ) : 0) + \ 2 + /*max compact attributes */ \ 2 + /*min dense attributes */ \ (O)->sizeof_size + /*# of attributes */ \ @@ -231,9 +236,9 @@ struct H5O_t { size_t sizeof_addr; /* Size of file addresses */ /* Object information (stored) */ - unsigned version; /*version number */ unsigned nlink; /*link count */ - unsigned flags; /*flags */ + uint8_t version; /*version number */ + uint8_t flags; /*flags */ /* Time information (stored, for versions > 1) */ time_t atime; /*access time */ diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 0438101..c08b97d 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -414,8 +414,6 @@ typedef herr_t (*H5O_operator_t)(const void *mesg/*in*/, unsigned idx, /* Forward declarations for prototype arguments */ struct H5P_genplist_t; -struct H5SL_t; -struct H5O_t; /* Object header routines */ H5_DLL herr_t H5O_init(void); diff --git a/src/H5Opublic.h b/src/H5Opublic.h index 6395eec..0e64a93 100644 --- a/src/H5Opublic.h +++ b/src/H5Opublic.h @@ -48,7 +48,7 @@ /* Flags for shared message indexes. * Pass these flags in using the mesg_type_flags parameter in * H5P_set_shared_mesg_index. - * (Developers: These flags correspond to object header message type_ids, + * (Developers: These flags correspond to object header message type IDs, * but we need to assign each kind of message to a different bit so that * one index can hold multiple types.) */ @@ -60,6 +60,11 @@ #define H5O_MESG_ATTR_FLAG 0x0010 /* Attribute Message. */ #define H5O_MESG_ALL_FLAG (H5O_MESG_SDSPACE_FLAG | H5O_MESG_DTYPE_FLAG | H5O_MESG_FILL_FLAG | H5O_MESG_PLINE_FLAG | H5O_MESG_ATTR_FLAG) +/* Object header status flag definitions */ +#define H5O_HDR_ATTR_CRT_ORDER_TRACKED 0x01 /* Attribute creation order is tracked */ +#define H5O_HDR_ATTR_CRT_ORDER_INDEXED 0x02 /* Attribute creation order has index */ +#define H5O_HDR_STORE_TIMES 0x04 /* Store access, modification, change & birth times for object */ + /* Maximum shared message values. Number of indexes is 8 to allow room to add * new types of messages. */ @@ -100,12 +105,17 @@ typedef struct H5O_info_t { unsigned version; /* Version number of header format in file */ unsigned nmesgs; /* Number of object header messages */ unsigned nchunks; /* Number of object header chunks */ - hsize_t hdr_size; /* Total size of object header in file */ - hsize_t meta_space; /* Space within header for object header metadata information */ - hsize_t mesg_space; /* Space within header for actual message information */ - hsize_t free_space; /* Free space within object header */ - uint64_t msg_present; /* Flags to indicate presence of message type in header */ - uint64_t msg_shared; /* Flags to indicate message type is shared in header */ + unsigned flags; /* Object header status flags */ + struct { + hsize_t total; /* Total space for storing object header in file */ + hsize_t meta; /* Space within header for object header metadata information */ + hsize_t mesg; /* Space within header for actual message information */ + hsize_t free; /* Free space within object header */ + } space; + struct { + uint64_t present; /* Flags to indicate presence of message type in header */ + uint64_t shared; /* Flags to indicate message type is shared in header */ + } mesg; } hdr; hsize_t meta_size; /* Size of additional metadata for an object */ /* (B-tree & heap for groups, B-tree for chunked dataset, etc.) */ diff --git a/src/H5Pocpl.c b/src/H5Pocpl.c index b454d08..974a6a0 100755 --- a/src/H5Pocpl.c +++ b/src/H5Pocpl.c @@ -27,6 +27,7 @@ /****************/ /* Module Setup */ /****************/ +#define H5O_PACKAGE /*suppress error about including H5Opkg */ #define H5P_PACKAGE /*suppress error about including H5Ppkg */ @@ -36,6 +37,7 @@ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Iprivate.h" /* IDs */ +#include "H5Opkg.h" /* Object headers */ #include "H5Ppkg.h" /* Property lists */ @@ -50,9 +52,8 @@ /* Definitions for the min. # of attributes to store densely */ #define H5O_CRT_ATTR_MIN_DENSE_SIZE sizeof(unsigned) #define H5O_CRT_ATTR_MIN_DENSE_DEF 6 -/* Definitions for the min. # of attributes to store densely */ -#define H5O_CRT_OHDR_FLAGS_SIZE sizeof(unsigned) -#define H5O_CRT_OHDR_FLAGS_DEF 0 +/* Definitions for object header flags */ +#define H5O_CRT_OHDR_FLAGS_SIZE sizeof(uint8_t) /******************/ @@ -114,6 +115,7 @@ const H5P_libclass_t H5P_CLS_OCRT[1] = {{ * * Programmer: Quincey Koziol * November 28, 2006 + * *------------------------------------------------------------------------- */ static herr_t @@ -121,7 +123,7 @@ H5P_ocrt_reg_prop(H5P_genclass_t *pclass) { unsigned attr_max_compact = H5O_CRT_ATTR_MAX_COMPACT_DEF; /* Default max. compact attribute storage settings */ unsigned attr_min_dense = H5O_CRT_ATTR_MIN_DENSE_DEF; /* Default min. dense attribute storage settings */ - unsigned ohdr_flags = H5O_CRT_OHDR_FLAGS_DEF; /* Default object header flag settings */ + uint8_t ohdr_flags = H5O_CRT_OHDR_FLAGS_DEF; /* Default object header flag settings */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5P_ocrt_reg_prop) @@ -249,13 +251,14 @@ done: * * Programmer: Quincey Koziol * February 6, 2007 + * *------------------------------------------------------------------------- */ herr_t H5Pset_attr_creation_order(hid_t plist_id, unsigned crt_order_flags) { H5P_genplist_t *plist; /* Property list pointer */ - unsigned ohdr_flags; /* Object header flags */ + uint8_t ohdr_flags; /* Object header flags */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(H5Pset_attr_creation_order, FAIL) @@ -274,11 +277,11 @@ H5Pset_attr_creation_order(hid_t plist_id, unsigned crt_order_flags) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags") /* Mask off previous attribute creation order flag settings */ - ohdr_flags &= ~(H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED); + ohdr_flags &= ~(H5O_HDR_ATTR_CRT_ORDER_TRACKED | H5O_HDR_ATTR_CRT_ORDER_INDEXED); /* Update with new attribute creation order flags */ - ohdr_flags |= (crt_order_flags & H5P_CRT_ORDER_TRACKED); - ohdr_flags |= (crt_order_flags & H5P_CRT_ORDER_INDEXED); + ohdr_flags |= (crt_order_flags & H5P_CRT_ORDER_TRACKED) ? H5O_HDR_ATTR_CRT_ORDER_TRACKED : 0; + ohdr_flags |= (crt_order_flags & H5P_CRT_ORDER_INDEXED) ? H5O_HDR_ATTR_CRT_ORDER_INDEXED : 0; /* Set object header flags */ if(H5P_set(plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0) @@ -298,7 +301,8 @@ done: * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * Ferbruary 6, 2007 + * February 6, 2007 + * *------------------------------------------------------------------------- */ herr_t @@ -312,7 +316,7 @@ H5Pget_attr_creation_order(hid_t plist_id, unsigned *crt_order_flags) /* Get values */ if(crt_order_flags) { H5P_genplist_t *plist; /* Property list pointer */ - unsigned ohdr_flags; /* Object header flags */ + uint8_t ohdr_flags; /* Object header flags */ /* Reset the value to return */ *crt_order_flags = 0; @@ -326,10 +330,110 @@ H5Pget_attr_creation_order(hid_t plist_id, unsigned *crt_order_flags) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags") /* Set creation order flags to return */ - *crt_order_flags = ohdr_flags & (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED); + *crt_order_flags |= (ohdr_flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) ? H5P_CRT_ORDER_TRACKED : 0; + *crt_order_flags |= (ohdr_flags & H5O_HDR_ATTR_CRT_ORDER_INDEXED) ? H5P_CRT_ORDER_INDEXED : 0; } /* end if */ done: FUNC_LEAVE_API(ret_value) } /* end H5Pget_attr_creation_order() */ + +/*------------------------------------------------------------------------- + * Function: H5Pset_obj_track_times + * + * Purpose: Set whether the birth, access, modification & change times for + * an object are stored. + * + * Birth time is the time the object was created. Access time is + * the last time that metadata or raw data was read from this + * object. Modification time is the last time the data for + * this object was changed (either writing raw data to a dataset + * or inserting/modifying/deleting a link in a group). Change + * time is the last time the metadata for this object was written + * (adding/modifying/deleting an attribute on an object, extending + * the size of a dataset, etc). + * + * If these times are not tracked, they will be reported as + * 12:00 AM UDT, Jan. 1, 1970 (i.e. 0 seconds past the UNIX + * epoch) when queried. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * March 1, 2007 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_obj_track_times(hid_t plist_id, hbool_t track_times) +{ + H5P_genplist_t *plist; /* Property list pointer */ + uint8_t ohdr_flags; /* Object header flags */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(H5Pset_obj_track_times, FAIL) + + /* Get the plist structure */ + if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Get object header flags */ + if(H5P_get(plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags") + + /* Mask off previous time tracking flag settings */ + ohdr_flags &= ~H5O_HDR_STORE_TIMES; + + /* Update with new time tracking flag */ + ohdr_flags |= track_times ? H5O_HDR_STORE_TIMES : 0; + + /* Set object header flags */ + if(H5P_set(plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set object header flags") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pset_obj_track_times() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pget_obj_track_times + * + * Purpose: Returns whether times are tracked for an object. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * March 1, 2007 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pget_obj_track_times(hid_t plist_id, hbool_t *track_times) +{ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(H5Pget_obj_track_times, FAIL) + + /* Get values */ + if(track_times) { + H5P_genplist_t *plist; /* Property list pointer */ + uint8_t ohdr_flags; /* Object header flags */ + + /* Get the plist structure */ + if(NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Get object header flags */ + if(H5P_get(plist, H5O_CRT_OHDR_FLAGS_NAME, &ohdr_flags) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object header flags") + + /* Set track times flag to return */ + *track_times = (ohdr_flags & H5O_HDR_STORE_TIMES) ? TRUE : FALSE; + } /* end if */ + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pget_obj_track_times() */ + diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index 5475fa0..637528d 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -224,6 +224,8 @@ H5_DLL herr_t H5Pset_attr_phase_change(hid_t plist_id, unsigned max_compact, uns H5_DLL herr_t H5Pget_attr_phase_change(hid_t plist_id, unsigned *max_compact, unsigned *min_dense); H5_DLL herr_t H5Pset_attr_creation_order(hid_t plist_id, unsigned crt_order_flags); H5_DLL herr_t H5Pget_attr_creation_order(hid_t plist_id, unsigned *crt_order_flags); +H5_DLL herr_t H5Pset_obj_track_times(hid_t plist_id, hbool_t track_times); +H5_DLL herr_t H5Pget_obj_track_times(hid_t plist_id, hbool_t *track_times); /* File creation property list (FCPL) routines */ H5_DLL herr_t H5Pget_version(hid_t plist_id, unsigned *boot/*out*/, diff --git a/test/links.c b/test/links.c index b23bbca..6b7e5b2 100644 --- a/test/links.c +++ b/test/links.c @@ -80,6 +80,10 @@ const char *FILENAME[] = { #define CORDER_ITER_STOP 3 #define CORDER_EST_ENTRY_LEN 9 +/* Timestamp macros */ +#define TIMESTAMP_GROUP_1 "timestamp1" +#define TIMESTAMP_GROUP_2 "timestamp2" + /* Link iteration struct */ typedef struct { H5_iter_order_t order; /* Direction of iteration */ @@ -9310,6 +9314,171 @@ error: /*------------------------------------------------------------------------- + * Function: timestamps + * + * Purpose: Verify that disabling tracking timestamps for an object + * works correctly + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * Saturday, March 3, 2007 + * + *------------------------------------------------------------------------- + */ +static int +timestamps(hid_t fapl) +{ + hid_t file_id = (-1); /* File ID */ + hid_t group_id = (-1); /* Group ID */ + hid_t group_id2 = (-1); /* Group ID */ + hid_t gcpl_id = (-1); /* Group creation property list ID */ + hid_t gcpl_id2 = (-1); /* Group creation property list ID */ + H5O_info_t oinfo, oinfo2; /* Object info for groups created */ + char filename[NAME_BUF_SIZE];/* File name */ + hbool_t track_times; /* The object timestamp setting */ + + /* Print test message */ + TESTING("timestamps on objects") + + /* Create group creation property list */ + if((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) TEST_ERROR + + /* Query the object timestamp setting */ + if(H5Pget_obj_track_times(gcpl_id, &track_times) < 0) TEST_ERROR + + /* Check default timestamp information */ + if(track_times != TRUE) TEST_ERROR + + /* Set a non-default object timestamp setting */ + if(H5Pset_obj_track_times(gcpl_id, FALSE) < 0) TEST_ERROR + + /* Query the object timestamp setting */ + if(H5Pget_obj_track_times(gcpl_id, &track_times) < 0) TEST_ERROR + + /* Check default timestamp information */ + if(track_times != FALSE) TEST_ERROR + + + /* Create file */ + h5_fixname(FILENAME[0], fapl, filename, sizeof filename); + if((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR + + /* Create group with non-default object timestamp setting */ + if((group_id = H5Gcreate_expand(file_id, gcpl_id, H5P_DEFAULT)) < 0) TEST_ERROR + if(H5Llink(file_id, TIMESTAMP_GROUP_1, group_id, H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR + + /* Close the group creation property list */ + if(H5Pclose(gcpl_id) < 0) TEST_ERROR + + /* Create group with default object timestamp setting */ + if((group_id2 = H5Gcreate_expand(file_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR + if(H5Llink(file_id, TIMESTAMP_GROUP_2, group_id2, H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR + + /* Retrieve the new groups' creation properties */ + if((gcpl_id = H5Gget_create_plist(group_id)) < 0) TEST_ERROR + if((gcpl_id2 = H5Gget_create_plist(group_id2)) < 0) TEST_ERROR + + /* Query & verify the object timestamp settings */ + if(H5Pget_obj_track_times(gcpl_id, &track_times) < 0) TEST_ERROR + if(track_times != FALSE) TEST_ERROR + if(H5Pget_obj_track_times(gcpl_id2, &track_times) < 0) TEST_ERROR + if(track_times != TRUE) TEST_ERROR + + /* Query the object information for each group */ + if(H5Oget_info(group_id, ".", &oinfo, H5P_DEFAULT) < 0) TEST_ERROR + if(H5Oget_info(group_id2, ".", &oinfo2, H5P_DEFAULT) < 0) TEST_ERROR + + /* Sanity check object information for each group */ + if(oinfo.atime != 0) TEST_ERROR + if(oinfo.mtime != 0) TEST_ERROR + if(oinfo.ctime != 0) TEST_ERROR + if(oinfo.btime != 0) TEST_ERROR + if(oinfo.atime == oinfo2.atime) TEST_ERROR + if(oinfo.mtime == oinfo2.mtime) TEST_ERROR + if(oinfo.ctime == oinfo2.ctime) TEST_ERROR + if(oinfo.btime == oinfo2.btime) TEST_ERROR + if((oinfo.hdr.flags & H5O_HDR_STORE_TIMES) != 0) TEST_ERROR + if((oinfo2.hdr.flags & H5O_HDR_STORE_TIMES) == 0) TEST_ERROR + if(oinfo.hdr.space.total >= oinfo2.hdr.space.total) TEST_ERROR + if(oinfo.hdr.space.meta >= oinfo2.hdr.space.meta) TEST_ERROR + + /* Close the property lists */ + if(H5Pclose(gcpl_id) < 0) TEST_ERROR + if(H5Pclose(gcpl_id2) < 0) TEST_ERROR + + /* Close the groups */ + if(H5Gclose(group_id) < 0) TEST_ERROR + if(H5Gclose(group_id2) < 0) TEST_ERROR + + /* Close the file */ + if(H5Fclose(file_id) < 0) TEST_ERROR + + + /* Re-open the file */ + if((file_id = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) TEST_ERROR + + /* Open groups */ + if((group_id = H5Gopen(file_id, TIMESTAMP_GROUP_1)) < 0) TEST_ERROR + if((group_id2 = H5Gopen(file_id, TIMESTAMP_GROUP_2)) < 0) TEST_ERROR + + /* Retrieve the groups' creation properties */ + if((gcpl_id = H5Gget_create_plist(group_id)) < 0) TEST_ERROR + if((gcpl_id2 = H5Gget_create_plist(group_id2)) < 0) TEST_ERROR + + /* Query & verify the object timestamp settings */ + if(H5Pget_obj_track_times(gcpl_id, &track_times) < 0) TEST_ERROR + if(track_times != FALSE) TEST_ERROR + if(H5Pget_obj_track_times(gcpl_id2, &track_times) < 0) TEST_ERROR + if(track_times != TRUE) TEST_ERROR + + /* Query the object information for each group */ + if(H5Oget_info(group_id, ".", &oinfo, H5P_DEFAULT) < 0) TEST_ERROR + if(H5Oget_info(group_id2, ".", &oinfo2, H5P_DEFAULT) < 0) TEST_ERROR + + /* Sanity check object information for each group */ + if(oinfo.atime != 0) TEST_ERROR + if(oinfo.mtime != 0) TEST_ERROR + if(oinfo.ctime != 0) TEST_ERROR + if(oinfo.btime != 0) TEST_ERROR + if(oinfo.atime == oinfo2.atime) TEST_ERROR + if(oinfo.mtime == oinfo2.mtime) TEST_ERROR + if(oinfo.ctime == oinfo2.ctime) TEST_ERROR + if(oinfo.btime == oinfo2.btime) TEST_ERROR + if((oinfo.hdr.flags & H5O_HDR_STORE_TIMES) != 0) TEST_ERROR + if((oinfo2.hdr.flags & H5O_HDR_STORE_TIMES) == 0) TEST_ERROR + if(oinfo.hdr.space.total >= oinfo2.hdr.space.total) TEST_ERROR + if(oinfo.hdr.space.meta >= oinfo2.hdr.space.meta) TEST_ERROR + + /* Close the property lists */ + if(H5Pclose(gcpl_id) < 0) TEST_ERROR + if(H5Pclose(gcpl_id2) < 0) TEST_ERROR + + /* Close the groups */ + if(H5Gclose(group_id) < 0) TEST_ERROR + if(H5Gclose(group_id2) < 0) TEST_ERROR + + /* Close the file */ + if(H5Fclose(file_id) < 0) TEST_ERROR + + PASSED(); + + return 0; + +error: + /* Free resources */ + H5E_BEGIN_TRY { + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Fclose(file_id); + } H5E_END_TRY; + + return -1; +} /* end timestamps() */ + + +/*------------------------------------------------------------------------- * Function: main * * Purpose: Test links @@ -9399,35 +9568,33 @@ main(void) nerrors += linkinfo((new_format ? fapl2 : fapl), new_format) < 0 ? 1 : 0; nerrors += check_all_closed((new_format ? fapl2 : fapl), new_format) < 0 ? 1 : 0; + } /* end for */ - /* New group revision feature tests */ - if(new_format == TRUE) { - nerrors += corder_create_empty(fapl2) < 0 ? 1 : 0; + /* New group revision feature tests */ + nerrors += corder_create_empty(fapl2) < 0 ? 1 : 0; /* XXX: when creation order indexing is fully working, go back and add checks - * to these tests to make certain that the creation order values are - * correct. - */ - nerrors += corder_create_compact(fapl2) < 0 ? 1 : 0; - nerrors += corder_create_dense(fapl2) < 0 ? 1 : 0; - nerrors += corder_transition(fapl2) < 0 ? 1 : 0; - nerrors += corder_delete(fapl2) < 0 ? 1 : 0; - nerrors += link_info_by_idx(fapl2) < 0 ? 1 : 0; - nerrors += delete_by_idx(fapl2) < 0 ? 1 : 0; - nerrors += link_iterate(fapl2) < 0 ? 1 : 0; - nerrors += open_by_idx(fapl2) < 0 ? 1 : 0; - nerrors += object_info(fapl2) < 0 ? 1 : 0; - nerrors += group_info(fapl2) < 0 ? 1 : 0; - } /* end if */ - else { - /* Test new API calls on old-style groups */ - nerrors += link_info_by_idx_old(fapl) < 0 ? 1 : 0; - nerrors += delete_by_idx_old(fapl) < 0 ? 1 : 0; - nerrors += link_iterate_old(fapl) < 0 ? 1 : 0; - nerrors += open_by_idx_old(fapl) < 0 ? 1 : 0; - nerrors += object_info_old(fapl) < 0 ? 1 : 0; - nerrors += group_info_old(fapl) < 0 ? 1 : 0; - } - } /* end for */ +* to these tests to make certain that the creation order values are +* correct. +*/ + nerrors += corder_create_compact(fapl2) < 0 ? 1 : 0; + nerrors += corder_create_dense(fapl2) < 0 ? 1 : 0; + nerrors += corder_transition(fapl2) < 0 ? 1 : 0; + nerrors += corder_delete(fapl2) < 0 ? 1 : 0; + nerrors += link_info_by_idx(fapl2) < 0 ? 1 : 0; + nerrors += delete_by_idx(fapl2) < 0 ? 1 : 0; + nerrors += link_iterate(fapl2) < 0 ? 1 : 0; + nerrors += open_by_idx(fapl2) < 0 ? 1 : 0; + nerrors += object_info(fapl2) < 0 ? 1 : 0; + nerrors += group_info(fapl2) < 0 ? 1 : 0; + nerrors += timestamps(fapl2) < 0 ? 1 : 0; + + /* Test new API calls on old-style groups */ + nerrors += link_info_by_idx_old(fapl) < 0 ? 1 : 0; + nerrors += delete_by_idx_old(fapl) < 0 ? 1 : 0; + nerrors += link_iterate_old(fapl) < 0 ? 1 : 0; + nerrors += open_by_idx_old(fapl) < 0 ? 1 : 0; + nerrors += object_info_old(fapl) < 0 ? 1 : 0; + nerrors += group_info_old(fapl) < 0 ? 1 : 0; /* Close 2nd FAPL */ H5Pclose(fapl2); -- cgit v0.12