From 1e07756ac265fad1171cd18efcdb2b0ba9bb903d Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Wed, 21 Feb 2007 14:58:48 -0500 Subject: [svn-r13367] Description: Allow "big" attributes to push attribute storage into "dense" form immediately, to accomodate storing the attribute. (This is only allowed in the "latest" version of the format). Tested on: Linux/32 2.6 (chicago) Linux/64 2.6 (chicago2) --- src/H5HF.c | 8 +- src/H5HFhuge.c | 75 ++++++++++++++ src/H5HFpkg.h | 2 + src/H5Oattribute.c | 44 ++++++--- src/H5SM.c | 154 +++++++++++++++++++++++------ src/H5SMpkg.h | 13 ++- src/H5SMprivate.h | 25 +++-- test/fheap.c | 17 +++- test/tattr.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 9 files changed, 552 insertions(+), 67 deletions(-) diff --git a/src/H5HF.c b/src/H5HF.c index 8651a8c..b617ec9 100644 --- a/src/H5HF.c +++ b/src/H5HF.c @@ -602,12 +602,12 @@ H5HF_write(H5HF_t *fh, hid_t dxpl_id, void *_id, hbool_t UNUSED *id_changed, /* Operate on object from managed heap blocks */ /* (ID can't change and modifying object is "easy" to manage) */ if(H5HF_man_write(fh->hdr, dxpl_id, id, obj) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "can't operate on object from fractal heap") + HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "can't write to 'managed' heap object") } /* end if */ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) { - /* Check for writing a 'huge' object */ - /* (which isn't supported yet - ID could change and lots of work to re-compress changed object) */ - HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "modifying 'huge' object not supported yet") + /* Operate on "huge" object */ + if(H5HF_huge_write(fh->hdr, dxpl_id, id, obj) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "can't write to 'huge' heap object") } /* end if */ else if((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) { /* Check for writing a 'tiny' object */ diff --git a/src/H5HFhuge.c b/src/H5HFhuge.c index 623210d..198ef62 100644 --- a/src/H5HFhuge.c +++ b/src/H5HFhuge.c @@ -708,6 +708,81 @@ done: /*------------------------------------------------------------------------- + * Function: H5HF_huge_write + * + * Purpose: Write a 'huge' object to the heap + * + * Note: This implementation somewhat limited: it doesn't handle + * heaps with filters, which would require re-compressing the + * huge object and probably changing the address of the object + * on disk (and possibly the heap ID for "direct" huge IDs). + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Feb 21 2007 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_huge_write(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, + const void *obj) +{ + haddr_t obj_addr; /* Object's address in the file */ + size_t obj_size; /* Object's size in the file */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HF_huge_write) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(id); + HDassert(obj); + + /* Check for filters on the heap */ + if(hdr->filter_len > 0) + HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "modifying 'huge' object with filters not supported yet") + + /* Skip over the flag byte */ + id++; + + /* Check for 'huge' object ID that encodes address & length directly */ + if(hdr->huge_ids_direct) { + /* Retrieve the object's address and length (common) */ + H5F_addr_decode(hdr->f, &id, &obj_addr); + H5F_DECODE_LENGTH(hdr->f, id, obj_size); + } /* end if */ + else { + H5HF_huge_bt2_indir_rec_t found_rec; /* Record found from tracking object */ + H5HF_huge_bt2_indir_rec_t search_rec; /* Record for searching for object */ + + /* Get ID for looking up 'huge' object in v2 B-tree */ + UINT64DECODE_VAR(id, search_rec.id, hdr->huge_id_size) + + /* Look up object in v2 B-tree */ + if(H5B2_find(hdr->f, dxpl_id, H5HF_BT2_INDIR, hdr->huge_bt2_addr, + &search_rec, H5HF_huge_bt2_indir_found, &found_rec) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "can't find object in B-tree") + + /* Retrieve the object's address & length */ + obj_addr = found_rec.addr; + H5_ASSIGN_OVERFLOW(/* To: */ obj_size, /* From: */ found_rec.len, /* From: */ hsize_t, /* To: */ size_t); + } /* end else */ + + /* Write the object's data to the file */ + /* (writes directly from application's buffer) */ + if(H5F_block_write(hdr->f, H5FD_MEM_FHEAP_HUGE_OBJ, obj_addr, obj_size, dxpl_id, obj) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "writing 'huge' object to file failed") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_huge_write() */ + + +/*------------------------------------------------------------------------- * Function: H5HF_huge_read * * Purpose: Read a 'huge' object from the heap diff --git a/src/H5HFpkg.h b/src/H5HFpkg.h index a1415a1..6dc1498 100644 --- a/src/H5HFpkg.h +++ b/src/H5HFpkg.h @@ -638,6 +638,8 @@ H5_DLL herr_t H5HF_huge_get_obj_len(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, size_t *obj_len_p); H5_DLL herr_t H5HF_huge_read(H5HF_hdr_t *fh, hid_t dxpl_id, const uint8_t *id, void *obj); +H5_DLL herr_t H5HF_huge_write(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, + const void *obj); H5_DLL herr_t H5HF_huge_op(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, H5HF_operator_t op, void *op_data); H5_DLL herr_t H5HF_huge_remove(H5HF_hdr_t *fh, hid_t dxpl_id, const uint8_t *id); diff --git a/src/H5Oattribute.c b/src/H5Oattribute.c index 3d3ae2c..9377bd0 100644 --- a/src/H5Oattribute.c +++ b/src/H5Oattribute.c @@ -221,24 +221,38 @@ H5O_attr_create(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr) if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) HGOTO_ERROR(H5E_ATTR, H5E_CANTLOAD, FAIL, "unable to load object header") - /* Check for switching to "dense" attribute storage */ - if(oh->version > H5O_VERSION_1 && oh->nattrs == oh->max_compact && - !H5F_addr_defined(oh->attr_fheap_addr)) { - H5O_iter_cvt_t udata; /* User data for callback */ - H5O_mesg_operator_t op; /* Wrapper for operator */ + /* Check if switching to "dense" attribute storage is possible */ + if(oh->version > H5O_VERSION_1 && !H5F_addr_defined(oh->attr_fheap_addr)) { + htri_t sharable; /* Whether the attribute will be shared */ + size_t raw_size = 0; /* Raw size of message */ + + /* Check for attribute being sharable */ + if((sharable = H5SM_can_share(loc->file, dxpl_id, NULL, NULL, H5O_ATTR_ID, attr)) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_BADMESG, FAIL, "can't determine attribute sharing status") + else if(sharable == FALSE) { + /* Compute the size needed to encode the attribute */ + raw_size = (H5O_MSG_ATTR->raw_size)(loc->file, FALSE, attr); + } /* end if */ - /* Create dense storage for attributes */ - if(H5A_dense_create(loc->file, dxpl_id, oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to create dense storage for attributes") + /* Check for condititions for switching to "dense" attribute storage are met */ + if(oh->nattrs == oh->max_compact || + (!sharable && raw_size >= H5O_MESG_MAX_SIZE)) { + H5O_iter_cvt_t udata; /* User data for callback */ + H5O_mesg_operator_t op; /* Wrapper for operator */ - /* Set up user data for callback */ - udata.f = loc->file; - udata.dxpl_id = dxpl_id; + /* Create dense storage for attributes */ + if(H5A_dense_create(loc->file, dxpl_id, oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to create dense storage for attributes") - /* Iterate over existing attributes, moving them to dense storage */ - op.lib_op = H5O_attr_to_dense_cb; - if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, TRUE, op, &udata, dxpl_id, &oh_flags) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTCONVERT, FAIL, "error converting attributes to dense storage") + /* Set up user data for callback */ + udata.f = loc->file; + udata.dxpl_id = dxpl_id; + + /* Iterate over existing attributes, moving them to dense storage */ + op.lib_op = H5O_attr_to_dense_cb; + if(H5O_msg_iterate_real(loc->file, oh, H5O_MSG_ATTR, TRUE, op, &udata, dxpl_id, &oh_flags) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTCONVERT, FAIL, "error converting attributes to dense storage") + } /* end if */ } /* end if */ /* Increment attribute count */ diff --git a/src/H5SM.c b/src/H5SM.c index 58a0730..3f2d9f7 100755 --- a/src/H5SM.c +++ b/src/H5SM.c @@ -761,6 +761,122 @@ done: /*------------------------------------------------------------------------- + * Function: H5SM_can_share_common + * + * Purpose: "trivial" checks for determining if a message can be shared. + * + * Note: These checks are common to the "can share" and "try share" + * routines and are the "fast" checks before we need to protect + * the SOHM master table. + * + * Return: TRUE if message could be a SOHM + * FALSE if this message couldn't be a SOHM + * Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, February 21, 2007 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5SM_can_share_common(const H5F_t *f, unsigned type_id, const void *mesg) +{ + htri_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5SM_can_share_common) + + /* Check whether this message ought to be shared or not */ + /* If sharing is disabled in this file, don't share the message */ + if(!H5F_addr_defined(f->shared->sohm_addr)) + HGOTO_DONE(FALSE) + + /* Type-specific check */ + if((ret_value = H5O_msg_can_share(type_id, mesg)) < 0) + HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "can_share callback returned error") + if(ret_value == FALSE) + HGOTO_DONE(FALSE) + + /* At this point, the message passes the "trivial" checks and is worth + * further checks. + */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5SM_can_share_common() */ + + +/*------------------------------------------------------------------------- + * Function: H5SM_can_share + * + * Purpose: Checks if an object header message would be shared or is + * already shared. + * + * If not, returns FALSE and does nothing. + * + * Return: TRUE if message will be a SOHM + * FALSE if this message won't be a SOHM + * Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, February 21, 2007 + * + *------------------------------------------------------------------------- + */ +htri_t +H5SM_can_share(H5F_t *f, hid_t dxpl_id, H5SM_master_table_t *table, + ssize_t *sohm_index_num, unsigned type_id, const void *mesg) +{ + size_t mesg_size; + H5SM_master_table_t *my_table = NULL; + ssize_t index_num; + htri_t tri_ret; + htri_t ret_value = TRUE; + + FUNC_ENTER_NOAPI(H5SM_can_share, FAIL) + + /* "trivial" sharing checks */ + if((tri_ret = H5SM_can_share_common(f, type_id, mesg)) < 0) + HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'trivial' sharing checks returned error") + if(tri_ret == FALSE) + HGOTO_DONE(FALSE) + + /* Look up the master SOHM table */ + /* (use incoming master SOHM table if possible) */ + if(table) + my_table = table; + else { + if(NULL == (my_table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, f->shared->sohm_addr, NULL, NULL, H5AC_READ))) + HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") + } /* end if */ + + /* Find the right index for this message type. If there is no such index + * then this type of message isn't shareable + */ + if((index_num = H5SM_get_index(my_table, type_id)) < 0) { + H5E_clear_stack(NULL); /*ignore error*/ + HGOTO_DONE(FALSE) + } /* end if */ + + /* If the message isn't big enough, don't bother sharing it */ + if(0 == (mesg_size = H5O_msg_raw_size(f, type_id, TRUE, mesg))) + HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "unable to get OH message size") + if(mesg_size < my_table->indexes[index_num].min_mesg_size) + HGOTO_DONE(FALSE) + + /* At this point, the message will be shared, set the index number if requested. */ + if(sohm_index_num) + *sohm_index_num = index_num; + +done: + /* Release the master SOHM table, if we protected it */ + if(my_table && my_table != table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, f->shared->sohm_addr, my_table, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_SOHM, H5E_CANTRELEASE, FAIL, "unable to close SOHM master table") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5SM_can_share() */ + + +/*------------------------------------------------------------------------- * Function: H5SM_try_share * * Purpose: Attempts to share an object header message. If the message @@ -784,46 +900,29 @@ done: htri_t H5SM_try_share(H5F_t *f, hid_t dxpl_id, unsigned type_id, void *mesg) { - size_t mesg_size; H5SM_master_table_t *table = NULL; unsigned cache_flags = H5AC__NO_FLAGS_SET; ssize_t index_num; htri_t tri_ret; - herr_t ret_value = TRUE; + htri_t ret_value = TRUE; FUNC_ENTER_NOAPI(H5SM_try_share, FAIL) - /* Check whether this message ought to be shared or not */ - /* If sharing is disabled in this file, don't share the message */ - if(f->shared->sohm_addr == HADDR_UNDEF) - HGOTO_DONE(FALSE); - - /* Type-specific check */ - if((tri_ret = H5O_msg_can_share(type_id, mesg)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "can_share callback returned error") + /* "trivial" sharing checks */ + if((tri_ret = H5SM_can_share_common(f, type_id, mesg)) < 0) + HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'trivial' sharing checks returned error") if(tri_ret == FALSE) - HGOTO_DONE(FALSE); + HGOTO_DONE(FALSE) /* Look up the master SOHM table */ if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, f->shared->sohm_addr, NULL, NULL, H5AC_WRITE))) HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") - /* Find the right index for this message type. If there is no such index - * then this type of message isn't shareable - */ - if((index_num = H5SM_get_index(table, type_id)) < 0) - { - H5E_clear_stack(NULL); /*ignore error*/ - HGOTO_DONE(FALSE); - } /* end if */ - - /* If the message isn't big enough, don't bother sharing it */ - if(0 == (mesg_size = H5O_msg_raw_size(f, type_id, TRUE, mesg))) - HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "unable to get OH message size") - if(mesg_size < table->indexes[index_num].min_mesg_size) - HGOTO_DONE(FALSE); - - /* At this point, the message will be shared. */ + /* "complex" sharing checks */ + if((tri_ret = H5SM_can_share(f, dxpl_id, table, &index_num, type_id, mesg)) < 0) + HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'complex' sharing checks returned error") + if(tri_ret == FALSE) + HGOTO_DONE(FALSE) /* If the index hasn't been allocated yet, create it */ if(table->indexes[index_num].index_addr == HADDR_UNDEF) @@ -1551,7 +1650,6 @@ H5SM_get_refcount(H5F_t *f, hid_t dxpl_id, unsigned type_id, H5SM_list_t *list = NULL; /* SOHM index list for message type (if in list form) */ H5SM_index_header_t *header=NULL; /* Index header for message type */ H5SM_mesg_key_t key; /* Key for looking up message */ - H5SM_fh_ud_gh_t udata; /* User data for fractal heap 'op' callback */ H5SM_sohm_t message; /* Shared message returned from callback */ size_t buf_size; /* Size of the encoded message */ void *encoding_buf = NULL; /* Buffer for encoded message */ diff --git a/src/H5SMpkg.h b/src/H5SMpkg.h index cf80959..aab7eb3 100755 --- a/src/H5SMpkg.h +++ b/src/H5SMpkg.h @@ -21,10 +21,17 @@ * the H5SM shared object header messages package. Source files * outside the H5SM package should include H5SMprivate.h instead. */ +#ifndef H5SM_PACKAGE +#error "Do not include this file outside the H5SM package!" +#endif + #ifndef _H5SMpkg_H #define _H5SMpkg_H -#include "H5SMprivate.h" +/* Get package's private header */ +#include "H5SMprivate.h" /* Shared Object Header Messages */ + +/* Other private headers needed by this file */ #include "H5B2private.h" /* B-trees */ #include "H5HFprivate.h" /* Fractal heaps */ @@ -141,13 +148,13 @@ typedef struct { /* Typedef for shared object header message master table */ -typedef struct { +struct H5SM_master_table_t { /* Information for H5AC cache functions, _must_ be first field in structure */ H5AC_info_t cache_info; uint8_t num_indexes; /* Number of indexes */ H5SM_index_header_t *indexes; /* Array of num_indexes indexes */ -} H5SM_master_table_t; +}; /* * Data exchange structure to pass through the fractal heap layer for the diff --git a/src/H5SMprivate.h b/src/H5SMprivate.h index 63c953c..49d0916 100755 --- a/src/H5SMprivate.h +++ b/src/H5SMprivate.h @@ -23,22 +23,30 @@ #ifndef _H5SMprivate_H #define _H5SMprivate_H -#include "H5Oprivate.h" -#include "H5Pprivate.h" +#include "H5Oprivate.h" /* Object headers */ +#include "H5Pprivate.h" /* Property lists */ /****************************/ /* Library Private Typedefs */ /****************************/ +/* Forward references of package typedefs */ +typedef struct H5SM_master_table_t H5SM_master_table_t; + + /******************************/ /* Library Private Prototypes */ /******************************/ + +/* Generally useful shared message routines */ H5_DLL herr_t H5SM_init(H5F_t *f, H5P_genplist_t *fc_plist, hid_t dxpl_id); +H5_DLL htri_t H5SM_can_share(H5F_t *f, hid_t dxpl_id, H5SM_master_table_t *table, + ssize_t *sohm_index_num, unsigned type_id, const void *mesg); H5_DLL htri_t H5SM_try_share(H5F_t *f, hid_t dxpl_id, unsigned type_id, - void *mesg); + void *mesg); H5_DLL herr_t H5SM_try_delete(H5F_t *f, hid_t dxpl_id, unsigned type_id, const H5O_shared_t *mesg); H5_DLL herr_t H5SM_get_info(H5F_t *f, unsigned *index_flags, unsigned *minsizes, - unsigned *list_max, unsigned *btree_min, hid_t dxpl_id); + unsigned *list_max, unsigned *btree_min, hid_t dxpl_id); H5_DLL htri_t H5SM_type_shared(H5F_t *f, unsigned type_id, hid_t dxpl_id); H5_DLL herr_t H5SM_get_fheap_addr(H5F_t *f, hid_t dxpl_id, unsigned type_id, haddr_t *fheap_addr); @@ -46,11 +54,12 @@ H5_DLL herr_t H5SM_reconstitute(H5O_shared_t *sh_mesg, H5O_fheap_id_t heap_id); H5_DLL herr_t H5SM_get_refcount(H5F_t *f, hid_t dxpl_id, unsigned type_id, const H5O_shared_t *sh_mesg, hsize_t *ref_count); +/* Debugging routines */ H5_DLL herr_t H5SM_table_debug(H5F_t *f, hid_t dxpl_id, haddr_t table_addr, - FILE *stream, int indent, int fwidth, - unsigned table_vers, unsigned num_indexes); + FILE *stream, int indent, int fwidth, unsigned table_vers, + unsigned num_indexes); H5_DLL herr_t H5SM_list_debug(H5F_t *f, hid_t dxpl_id, haddr_t list_addr, - FILE *stream, int indent, int fwidth, - unsigned list_vers, size_t num_messages); + FILE *stream, int indent, int fwidth, unsigned list_vers, size_t num_messages); + #endif /*_H5SMprivate_H*/ diff --git a/test/fheap.c b/test/fheap.c index bb96fda..f3dd7b3 100644 --- a/test/fheap.c +++ b/test/fheap.c @@ -15221,16 +15221,23 @@ test_write(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam) if(H5HF_insert(fh, dxpl, obj_size, shared_wobj_g, huge_heap_id) < 0) FAIL_STACK_ERROR - /* Verify that writing to 'tiny' and 'huge' objects return failure (for now) */ + /* Verify that writing to 'huge' objects works for un-filtered heaps */ H5E_BEGIN_TRY { - ret = H5HF_write(fh, dxpl, tiny_heap_id, &id_changed, shared_wobj_g); + ret = H5HF_write(fh, dxpl, huge_heap_id, &id_changed, shared_wobj_g); } H5E_END_TRY; HDassert(!id_changed); - if(ret >= 0) - TEST_ERROR + if(tparam->comp == FHEAP_TEST_COMPRESS) { + if(ret >= 0) + TEST_ERROR + } /* end if */ + else { + if(ret < 0) + FAIL_STACK_ERROR + } /* end else */ + /* Verify that writing to 'tiny' objects return failure (for now) */ H5E_BEGIN_TRY { - ret = H5HF_write(fh, dxpl, huge_heap_id, &id_changed, shared_wobj_g); + ret = H5HF_write(fh, dxpl, tiny_heap_id, &id_changed, shared_wobj_g); } H5E_END_TRY; HDassert(!id_changed); if(ret >= 0) diff --git a/test/tattr.c b/test/tattr.c index 1cd3a2f..e0d08e8 100644 --- a/test/tattr.c +++ b/test/tattr.c @@ -119,6 +119,11 @@ struct attr4_struct { #define ATTR5_RANK 0 float attr_data5=(float)-5.123; /* Test data for 5th attribute */ +#define ATTR6_RANK 3 +#define ATTR6_DIM1 100 +#define ATTR6_DIM2 100 +#define ATTR6_DIM3 100 + /* Attribute iteration struct */ typedef struct { H5_iter_order_t order; /* Direction of iteration */ @@ -2693,6 +2698,276 @@ test_attr_dense_limits(hid_t fcpl, hid_t fapl) /**************************************************************** ** +** test_attr_big(): Test basic H5A (attribute) code. +** Tests storing "big" attribute in dense storage immediately, if available +** +****************************************************************/ +static void +test_attr_big(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t big_sid; /* "Big" dataspace ID */ + hsize_t dims[ATTR6_RANK] = {ATTR6_DIM1, ATTR6_DIM2, ATTR6_DIM3}; /* Attribute dimensions */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ + unsigned nshared_indices; /* # of shared message indices */ + hbool_t latest_format; /* Whether we're using the latest version of the format or not */ + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + unsigned u; /* Local index variable */ + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Storing 'Big' Attributes in Dense Storage\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME); + if(empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create dataspace for dataset & "small" attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create "big" dataspace for "big" attributes */ + big_sid = H5Screate_simple(ATTR6_RANK, dims, NULL); + CHECK(big_sid, FAIL, "H5Screate_simple"); + + /* Query the group creation properties */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Retrieve # of shared message indices (ie. whether attributes are shared or not) */ + ret = H5Pget_shared_mesg_nindexes(fcpl, &nshared_indices); + CHECK(ret, FAIL, "H5Pget_shared_mesg_nindexes"); + + /* Retrieve the "use the latest version of the format" flag for creating objects in the file */ + ret = H5Pget_latest_format(fapl, &latest_format); + CHECK(ret, FAIL, "H5Pget_latest_format"); + + /* Create a dataset */ + dataset = H5Dcreate(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, dcpl); + CHECK(dataset, FAIL, "H5Dcreate"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + + /* Check on dataset's attribute storage status */ + is_empty = H5O_is_attr_empty_test(dataset); + VERIFY(is_empty, TRUE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); + + + /* Add first "small" attribute, which should be in compact storage */ + + /* Create attribute */ + u = 0; + sprintf(attrname, "attr %02u", u); + attr = H5Acreate(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check on dataset's attribute storage status */ + is_empty = H5O_is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); + + + /* Add second "small" attribute, which should stay in compact storage */ + + /* Create attribute */ + u = 1; + sprintf(attrname, "attr %02u", u); + attr = H5Acreate(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check on dataset's attribute storage status */ + is_empty = H5O_is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); + + + /* Add first "big" attribute, which should push storage into dense form */ + + /* Create attribute */ + u = 2; + sprintf(attrname, "attr %02u", u); + attr = H5Acreate(dataset, attrname, H5T_NATIVE_UINT, big_sid, H5P_DEFAULT); + if(latest_format) { + CHECK(attr, FAIL, "H5Acreate"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check on dataset's attribute storage status */ + /* (when attributes are shared, the "big" attribute goes into the shared + * message heap instead of forcing the attribute storage into the dense + * form - QAK) + */ + is_empty = H5O_is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, (nshared_indices ? FALSE : TRUE), "H5O_is_attr_dense_test"); + + + /* Add second "big" attribute, which should leave storage in dense form */ + + /* Create attribute */ + u = 3; + sprintf(attrname, "attr %02u", u); + attr = H5Acreate(dataset, attrname, H5T_NATIVE_UINT, big_sid, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check on dataset's attribute storage status */ + /* (when attributes are shared, the "big" attribute goes into the shared + * message heap instead of forcing the attribute storage into the dense + * form - QAK) + */ + is_empty = H5O_is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, (nshared_indices ? FALSE : TRUE), "H5O_is_attr_dense_test"); + + + /* Delete second "small" attribute, attributes should still be stored densely */ + + /* Delete attribute */ + u = 1; + sprintf(attrname, "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); + + /* Check on dataset's attribute storage status */ + is_empty = H5O_is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, (nshared_indices ? FALSE : TRUE), "H5O_is_attr_dense_test"); + + + /* Delete second "big" attribute, attributes should still be stored densely */ + + /* Delete attribute */ + u = 3; + sprintf(attrname, "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); + + /* Check on dataset's attribute storage status */ + is_empty = H5O_is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, (nshared_indices ? FALSE : TRUE), "H5O_is_attr_dense_test"); + + + /* Delete first "big" attribute, attributes should _not_ be stored densely */ + + /* Delete attribute */ + u = 2; + sprintf(attrname, "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); + + /* Check on dataset's attribute storage status */ + is_empty = H5O_is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); + + + /* Delete first "small" attribute, should be no attributes now */ + + /* Delete attribute */ + u = 0; + sprintf(attrname, "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); + + /* Check on dataset's attribute storage status */ + is_empty = H5O_is_attr_empty_test(dataset); + VERIFY(is_empty, TRUE, "H5O_is_attr_empty_test"); + } /* end if */ + else { + /* Shouldn't be able to create "big" attributes with older version of format */ + VERIFY(attr, FAIL, "H5Acreate"); + + /* Check on dataset's attribute storage status */ + /* (when attributes are shared, the "big" attribute goes into the shared + * message heap instead of forcing the attribute storage into the dense + * form - QAK) + */ + is_empty = H5O_is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); + } /* end else */ + + + /* Close dataspaces */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(big_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Unlink dataset */ + ret = H5Gunlink(fid, DSET1_NAME); + CHECK(ret, FAIL, "H5Gunlink"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Check size of file */ + filesize = h5_get_file_size(FILENAME); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); +} /* test_attr_dense_limits() */ + + +/**************************************************************** +** ** test_attr_corder_create_empty(): Test basic H5A (attribute) code. ** Tests basic code to create objects with attribute creation order info ** @@ -7461,13 +7736,10 @@ test_attr(void) test_attr_dense_rename(my_fcpl, my_fapl); /* Test renaming attributes in dense storage */ test_attr_dense_unlink(my_fcpl, my_fapl); /* Test unlinking object with attributes in dense storage */ test_attr_dense_limits(my_fcpl, my_fapl); /* Test dense attribute storage limits */ + test_attr_big(my_fcpl, my_fapl); /* Test storing big attribute */ /* Attribute creation order tests */ test_attr_corder_create_basic(my_fcpl, my_fapl);/* Test creating an object w/attribute creation order info */ -/* 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. - */ test_attr_corder_create_compact(my_fcpl, my_fapl); /* Test compact attribute storage on an object w/attribute creation order info */ test_attr_corder_create_dense(my_fcpl, my_fapl);/* Test dense attribute storage on an object w/attribute creation order info */ test_attr_corder_transition(my_fcpl, my_fapl); /* Test attribute storage transitions on an object w/attribute creation order info */ @@ -7496,6 +7768,7 @@ test_attr(void) test_attr_iterate2(new_format, fcpl, my_fapl); /* Test iterating over attributes by index */ test_attr_open_by_idx(new_format, fcpl, my_fapl); /* Test opening attributes by index */ test_attr_open(new_format, fcpl, my_fapl); /* Test opening attributes by name */ + test_attr_big(fcpl, my_fapl); /* Test storing big attribute */ } /* end else */ } /* end for */ -- cgit v0.12