From d1a1f2421d9653b13ecf491e642129fa7f9fab6b Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Mon, 19 Feb 2007 21:28:41 -0500 Subject: [svn-r13341] Description: Checkpoint "delete by index" code, which is partially finished. Tested on: FreeBSD/32 6.2 (duty) --- src/H5A.c | 145 +++++++++++++++--- src/H5Adense.c | 235 ++++++++++++++++++++++++++++- src/H5Apkg.h | 35 +++-- src/H5Apublic.h | 5 +- src/H5Gdense.c | 2 +- src/H5Oattribute.c | 242 ++++++++++++++++++++++-------- src/H5Opkg.h | 21 +-- test/tattr.c | 423 +++++++++++++++++++++++++++++++++++++++++++---------- 8 files changed, 910 insertions(+), 198 deletions(-) diff --git a/src/H5A.c b/src/H5A.c index 4fd4a87..635893b 100644 --- a/src/H5A.c +++ b/src/H5A.c @@ -71,8 +71,8 @@ static hid_t H5A_create(const H5G_loc_t *loc, const char *name, static herr_t H5A_open_common(const H5G_loc_t *loc, H5A_t *attr); static H5A_t *H5A_open_by_idx(const H5G_loc_t *loc, const char *obj_name, H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t lapl_id, hid_t dxpl_id); -static H5A_t *H5A_open_by_name(const H5G_loc_t *loc, const char *name, - hid_t dxpl_id); +static H5A_t *H5A_open_by_name(const H5G_loc_t *loc, const char *obj_name, + const char *attr_name, hid_t lapl_id, hid_t dxpl_id); static herr_t H5A_write(H5A_t *attr, const H5T_t *mem_type, const void *buf, hid_t dxpl_id); static herr_t H5A_read(const H5A_t *attr, const H5T_t *mem_type, void *buf, hid_t dxpl_id); static hsize_t H5A_get_storage_size(const H5A_t *attr); @@ -456,7 +456,7 @@ H5Aopen_name(hid_t loc_id, const char *name) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") /* Open the attribute on the object header */ - if(NULL == (attr = H5A_open_by_name(&loc, name, H5AC_ind_dxpl_id))) + if(NULL == (attr = H5A_open_by_name(&loc, ".", name, H5P_LINK_ACCESS_DEFAULT, H5AC_ind_dxpl_id))) HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "can't open attribute") /* Register the attribute and get an ID for it */ @@ -604,8 +604,8 @@ H5A_open_by_idx(const H5G_loc_t *loc, const char *obj_name, H5_index_t idx_type, H5G_name_t obj_path; /* Opened object group hier. path */ H5O_loc_t obj_oloc; /* Opened object object location */ hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */ - H5A_t *attr = NULL; - H5A_t *ret_value; /* Return value */ + H5A_t *attr = NULL; /* Attribute from object header */ + H5A_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5A_open_by_idx) @@ -652,16 +652,9 @@ done: /*------------------------------------------------------------------------- * Function: H5A_open_by_name * - * Purpose: - * Open an attribute in an object header, according to it's name + * Purpose: Open an attribute in an object header, according to it's name * - * Usage: - * herr_t H5A_open(loc, name, dxpl_id) - * const H5G_loc_t *loc; IN: Pointer to group location for object - * const char *name; IN: Name of attribute to open - * hid_t dxpl_id; IN: DXPL for operation - * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * December 11, 2006 @@ -669,19 +662,35 @@ done: *------------------------------------------------------------------------- */ static H5A_t * -H5A_open_by_name(const H5G_loc_t *loc, const char *name, hid_t dxpl_id) +H5A_open_by_name(const H5G_loc_t *loc, const char *obj_name, const char *attr_name, + hid_t lapl_id, hid_t dxpl_id) { - H5A_t *attr = NULL; /* Attribute from object header */ - H5A_t *ret_value; /* Return value */ + H5G_loc_t obj_loc; /* Location used to open group */ + H5G_name_t obj_path; /* Opened object group hier. path */ + H5O_loc_t obj_oloc; /* Opened object object location */ + hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */ + H5A_t *attr = NULL; /* Attribute from object header */ + H5A_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5A_open_by_name) /* check args */ HDassert(loc); - HDassert(name); + HDassert(obj_name); + HDassert(attr_name); + + /* Set up opened group location to fill in */ + obj_loc.oloc = &obj_oloc; + obj_loc.path = &obj_path; + H5G_loc_reset(&obj_loc); + + /* Find the object's location */ + if(H5G_loc_find(loc, obj_name, &obj_loc/*out*/, lapl_id, dxpl_id) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "object not found") + loc_found = TRUE; /* Read in attribute from object header */ - if(NULL == (attr = H5O_attr_open_by_name(loc->oloc, name, dxpl_id))) + if(NULL == (attr = H5O_attr_open_by_name(obj_loc.oloc, attr_name, dxpl_id))) HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, NULL, "unable to load attribute info from object header") attr->initialized = TRUE; @@ -693,6 +702,10 @@ H5A_open_by_name(const H5G_loc_t *loc, const char *name, hid_t dxpl_id) ret_value = attr; done: + /* Release resources */ + if(loc_found && H5G_loc_free(&obj_loc) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, NULL, "can't free location") + /* Cleanup on failure */ if(ret_value == NULL) if(attr && H5A_close(attr) < 0) @@ -1374,7 +1387,8 @@ H5A_get_storage_size(const H5A_t *attr) *------------------------------------------------------------------------- */ herr_t -H5Aget_info(hid_t loc_id, const char *name, H5A_info_t *ainfo) +H5Aget_info(hid_t loc_id, const char *obj_name, const char *attr_name, + H5A_info_t *ainfo, hid_t lapl_id) { H5G_loc_t loc; /* Object location */ H5A_t *attr = NULL; /* Attribute object for name */ @@ -1387,13 +1401,20 @@ H5Aget_info(hid_t loc_id, const char *name, H5A_info_t *ainfo) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute") if(H5G_loc(loc_id, &loc) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") - if(!name || !*name) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") + if(!obj_name || !*obj_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name") + if(!attr_name || !*attr_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no attribute name") if(NULL == ainfo) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid info pointer") + if(H5P_DEFAULT == lapl_id) + lapl_id = H5P_LINK_ACCESS_DEFAULT; + else + if(TRUE != H5P_isa_class(lapl_id, H5P_LINK_ACCESS)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link access property list ID") /* Open the attribute on the object header */ - if(NULL == (attr = H5A_open_by_name(&loc, name, H5AC_ind_dxpl_id))) + if(NULL == (attr = H5A_open_by_name(&loc, obj_name, attr_name, lapl_id, H5AC_ind_dxpl_id))) HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "can't open attribute") /* Get the attribute information */ @@ -1630,7 +1651,6 @@ done: const char *name; IN: Name of attribute to delete RETURNS Non-negative on success/Negative on failure - DESCRIPTION This function removes the named attribute from a dataset or group. This function should not be used when attribute IDs are open on 'loc_id' @@ -1665,6 +1685,83 @@ done: /*-------------------------------------------------------------------------- NAME + H5Adelete_by_idx + PURPOSE + Deletes an attribute from a location, according to the order within an index + USAGE + herr_t H5Adelete_by_idx(loc_id, obj_name, idx_type, order, n, lapl_id) + hid_t loc_id; IN: Base location for object + const char *obj_name; IN: Name of object relative to location + H5_index_t idx_type; IN: Type of index to use + H5_iter_order_t order; IN: Order to iterate over index + hsize_t n; IN: Offset within index + hid_t lapl_id; IN: Link access property list + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + This function removes an attribute from an object, using the IDX_TYPE + index to delete the N'th attribute in ORDER direction in the index. The + object is specified relative to the LOC_ID with the OBJ_NAME path. To + remove an attribute on the object specified by LOC_ID, pass in "." for + OBJ_NAME. The link access property list, LAPL_ID, controls aspects of + the group hierarchy traversal when using the OBJ_NAME to locate the final + object to operate on. +--------------------------------------------------------------------------*/ +herr_t +H5Adelete_by_idx(hid_t loc_id, const char *obj_name, H5_index_t idx_type, + H5_iter_order_t order, hsize_t n, hid_t lapl_id) +{ + H5G_loc_t loc; /* Object location */ + H5G_loc_t obj_loc; /* Location used to open group */ + H5G_name_t obj_path; /* Opened object group hier. path */ + H5O_loc_t obj_oloc; /* Opened object object location */ + hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(H5Adelete_by_idx, FAIL) + + /* check arguments */ + if(H5I_ATTR == H5I_get_type(loc_id)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute") + if(H5G_loc(loc_id, &loc) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + if(!obj_name || !*obj_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name") + if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified") + if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified") + if(H5P_DEFAULT == lapl_id) + lapl_id = H5P_LINK_ACCESS_DEFAULT; + else + if(TRUE != H5P_isa_class(lapl_id, H5P_LINK_ACCESS)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link access property list ID") + + /* Set up opened group location to fill in */ + obj_loc.oloc = &obj_oloc; + obj_loc.path = &obj_path; + H5G_loc_reset(&obj_loc); + + /* Find the object's location */ + if(H5G_loc_find(&loc, obj_name, &obj_loc/*out*/, lapl_id, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "object not found") + loc_found = TRUE; + + /* Delete the attribute from the location */ + if(H5O_attr_remove_by_idx(obj_loc.oloc, idx_type, order, n, H5AC_dxpl_id) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute") + +done: + /* Release resources */ + if(loc_found && H5G_loc_free(&obj_loc) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't free location") + + FUNC_LEAVE_API(ret_value) +} /* H5Adelete_by_idx() */ + + +/*-------------------------------------------------------------------------- + NAME H5Aclose PURPOSE Close an attribute ID diff --git a/src/H5Adense.c b/src/H5Adense.c index 78cdcc8..0d4f02d 100644 --- a/src/H5Adense.c +++ b/src/H5Adense.c @@ -116,6 +116,30 @@ typedef struct { H5A_t *attr; /* Copy of attribute */ } H5A_fh_ud_cp_t; +/* + * Data exchange structure for dense attribute storage. This structure is + * passed through the v2 B-tree layer when removing attributes. + */ +typedef struct H5A_bt2_ud_rm_t { + /* downward */ + H5A_bt2_ud_common_t common; /* Common info for B-tree user data (must be first) */ + haddr_t corder_bt2_addr; /* v2 B-tree address of creation order index */ +} H5A_bt2_ud_rm_t; + +/* + * Data exchange structure for dense attribute storage. This structure is + * passed through the v2 B-tree layer when removing attributes by index. + */ +typedef struct H5A_bt2_ud_rmbi_t { + /* downward */ + H5F_t *f; /* Pointer to file that fractal heap is in */ + hid_t dxpl_id; /* DXPL for operation */ + H5HF_t *fheap; /* Fractal heap handle */ + H5HF_t *shared_fheap; /* Fractal heap handle for shared messages */ + H5_index_t idx_type; /* Index type for operation */ + haddr_t other_bt2_addr; /* v2 B-tree address of "other" index */ +} H5A_bt2_ud_rmbi_t; + /********************/ /* Package Typedefs */ @@ -1130,8 +1154,7 @@ H5A_dense_remove_bt2_cb(const void *_record, void *_udata) udata->common.corder = attr->crt_idx; /* Remove the record from the name index v2 B-tree */ - if(H5B2_remove(udata->common.f, udata->common.dxpl_id, H5A_BT2_CORDER, udata->corder_bt2_addr, - udata, NULL, NULL) < 0) + if(H5B2_remove(udata->common.f, udata->common.dxpl_id, H5A_BT2_CORDER, udata->corder_bt2_addr, udata, NULL, NULL) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove attribute from creation order index v2 B-tree") } /* end if */ @@ -1225,6 +1248,214 @@ done: /*------------------------------------------------------------------------- + * Function: H5A_dense_remove_by_idx_bt2_cb + * + * Purpose: v2 B-tree callback for dense attribute storage record removal by index + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Feb 14 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5A_dense_remove_by_idx_bt2_cb(const void *_record, void *_bt2_udata) +{ + const H5A_dense_bt2_name_rec_t *record = (const H5A_dense_bt2_name_rec_t *)_record; /* v2 B-tree record */ + H5A_bt2_ud_rmbi_t *bt2_udata = (H5A_bt2_ud_rmbi_t *)_bt2_udata; /* User data for callback */ + H5A_fh_ud_cp_t fh_udata; /* User data for fractal heap 'op' callback */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5A_dense_remove_by_idx_bt2_cb) + + /* Set up the user data for fractal heap 'op' callback */ + fh_udata.f = bt2_udata->f; + fh_udata.dxpl_id = bt2_udata->dxpl_id; + fh_udata.record = record; + fh_udata.attr = NULL; + + /* Call fractal heap 'op' routine, to make copy of attribute to remove */ + if(H5HF_op(bt2_udata->fheap, bt2_udata->dxpl_id, &record->id, H5A_dense_copy_fh_cb, &fh_udata) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTOPERATE, FAIL, "attribute removal callback failed") + HDassert(fh_udata.attr); + + /* Check for removing shared attribute */ + if(record->flags & H5O_MSG_FLAG_SHARED) { + /* Decrement the reference count on the shared attribute message */ + if(H5SM_try_delete(bt2_udata->f, bt2_udata->dxpl_id, H5O_ATTR_ID, &(fh_udata.attr->sh_loc)) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to delete shared attribute") + } /* end if */ + else { + /* Perform the deletion action on the attribute */ + /* (takes care of shared & committed datatype/dataspace components) */ + if(H5O_attr_delete(bt2_udata->f, bt2_udata->dxpl_id, &fh_udata.attr) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute") + + /* Remove record from fractal heap */ + if(H5HF_remove(bt2_udata->fheap, bt2_udata->dxpl_id, &record->id) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from fractal heap") + } /* end else */ + + /* Check for removing the link from the "other" index (creation order, when name used and vice versa) */ + if(H5F_addr_defined(bt2_udata->other_bt2_addr)) { + H5A_bt2_ud_common_t other_bt2_udata; /* Info for B-tree callbacks */ + const H5B2_class_t *other_bt2_class; /* Class of "other" v2 B-tree */ + + /* Determine the index being used */ + if(bt2_udata->idx_type == H5_INDEX_NAME) { + /* Set the class of the "other" index */ + other_bt2_class = H5A_BT2_CORDER; + + /* Set up the user data for the v2 B-tree 'record remove' callback */ + other_bt2_udata.corder = fh_udata.attr->crt_idx; + } /* end if */ + else { + HDassert(bt2_udata->idx_type == H5_INDEX_CRT_ORDER); + + /* Set the class of the "other" index */ + other_bt2_class = H5A_BT2_NAME; + + /* Set up the user data for the v2 B-tree 'record remove' callback */ + other_bt2_udata.f = bt2_udata->f; + other_bt2_udata.dxpl_id = bt2_udata->dxpl_id; + other_bt2_udata.fheap = bt2_udata->fheap; + other_bt2_udata.name = fh_udata.attr->name; + other_bt2_udata.name_hash = H5_checksum_lookup3(fh_udata.attr->name, HDstrlen(fh_udata.attr->name), 0); + other_bt2_udata.found_op = NULL; + other_bt2_udata.found_op_data = NULL; + } /* end else */ + + /* Set the common information for the v2 B-tree remove operation */ + + /* Remove the record from the "other" index v2 B-tree */ + if(H5B2_remove(bt2_udata->f, bt2_udata->dxpl_id, other_bt2_class, bt2_udata->other_bt2_addr, &other_bt2_udata, NULL, NULL) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove record from 'other' index v2 B-tree") + } /* end if */ + +done: + /* Release resources */ + if(fh_udata.attr) + H5O_msg_free(H5O_ATTR_ID, fh_udata.attr); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5A_dense_remove_by_idx_bt2_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5A_dense_remove_by_idx + * + * Purpose: Remove an attribute from the dense storage of an object, + * according to the order within an index + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Feb 14 2007 + * + *------------------------------------------------------------------------- + */ +herr_t +H5A_dense_remove_by_idx(H5F_t *f, hid_t dxpl_id, const H5O_t *oh, + H5_index_t idx_type, H5_iter_order_t order, hsize_t n) +{ + H5HF_t *fheap = NULL; /* Fractal heap handle */ + H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */ + const H5B2_class_t *bt2_class = NULL; /* Class of v2 B-tree */ + haddr_t bt2_addr; /* Address of v2 B-tree to use for operation */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5A_dense_remove_by_idx, FAIL) + + /* + * Check arguments. + */ + HDassert(f); + HDassert(oh); + + /* Determine the address of the index to use */ + if(idx_type == H5_INDEX_NAME) { + /* Check if "native" order is OK - since names are hashed, getting them + * in strictly increasing or decreasing order requires building a + * table and sorting it. + */ + if(order == H5_ITER_NATIVE) { + bt2_addr = oh->name_bt2_addr; + bt2_class = H5A_BT2_NAME; + HDassert(H5F_addr_defined(bt2_addr)); + } /* end if */ + else + bt2_addr = HADDR_UNDEF; + } /* end if */ + else { + HDassert(idx_type == H5_INDEX_CRT_ORDER); + + /* This address may not be defined if creation order is tracked, but + * there's no index on it. If there's no v2 B-tree that indexes + * the links, a table will be built. + */ + bt2_addr = oh->corder_bt2_addr; + bt2_class = H5A_BT2_CORDER; + } /* end else */ + + /* If there is an index defined for the field, use it */ + if(H5F_addr_defined(bt2_addr)) { + H5A_bt2_ud_rmbi_t udata; /* User data for v2 B-tree record removal */ + htri_t attr_sharable; /* Flag indicating attributes are sharable */ + + /* Open the fractal heap */ + if(NULL == (fheap = H5HF_open(f, dxpl_id, oh->attr_fheap_addr))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap") + + /* Check if attributes are shared in this file */ + if((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID, dxpl_id)) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared") + + /* Get handle for shared message heap, if attributes are sharable */ + if(attr_sharable) { + haddr_t shared_fheap_addr; /* Address of fractal heap to use */ + + /* Retrieve the address of the shared message's fractal heap */ + if(H5SM_get_fheap_addr(f, dxpl_id, H5O_ATTR_ID, &shared_fheap_addr) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address") + + /* Check if there are any shared messages currently */ + if(H5F_addr_defined(shared_fheap_addr)) { + /* Open the fractal heap for shared header messages */ + if(NULL == (shared_fheap = H5HF_open(f, dxpl_id, shared_fheap_addr))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap") + } /* end if */ + } /* end if */ + + /* Set up the user data for the v2 B-tree 'record remove' callback */ + udata.f = f; + udata.dxpl_id = dxpl_id; + udata.fheap = fheap; + udata.shared_fheap = shared_fheap; + udata.idx_type = idx_type; + udata.other_bt2_addr = idx_type == H5_INDEX_NAME ? oh->corder_bt2_addr : oh->name_bt2_addr; + + /* Remove the record from the name index v2 B-tree */ + if(H5B2_remove_by_idx(f, dxpl_id, bt2_class, bt2_addr, order, n, H5A_dense_remove_by_idx_bt2_cb, &udata) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from v2 B-tree index") + } /* end if */ + else { + } /* end else */ + +done: + /* Release resources */ + if(shared_fheap && H5HF_close(shared_fheap, dxpl_id) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap") + if(fheap && H5HF_close(fheap, dxpl_id) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5A_dense_remove_by_idx() */ + + +/*------------------------------------------------------------------------- * Function: H5A_dense_exists * * Purpose: Check if an attribute exists in dense storage structures for diff --git a/src/H5Apkg.h b/src/H5Apkg.h index fda8a02..c8d1938 100644 --- a/src/H5Apkg.h +++ b/src/H5Apkg.h @@ -124,16 +124,6 @@ typedef struct H5A_bt2_ud_ins_t { H5O_fheap_id_t id; /* Heap ID of attribute to insert */ } H5A_bt2_ud_ins_t; -/* - * Data exchange structure for dense attribute storage. This structure is - * passed through the v2 B-tree layer when removing attributes. - */ -typedef struct H5A_bt2_ud_rm_t { - /* downward */ - H5A_bt2_ud_common_t common; /* Common info for B-tree user data (must be first) */ - haddr_t corder_bt2_addr; /* v2 B-tree address of creation order index */ -} H5A_bt2_ud_rm_t; - /* Data structure to hold table of attributes for an object */ typedef struct { size_t nattrs; /* # of attributes in table */ @@ -199,6 +189,8 @@ H5_DLL herr_t H5A_dense_iterate(H5F_t *f, hid_t dxpl_id, hid_t loc_id, hsize_t *last_attr, const H5A_attr_iter_op_t *attr_op, void *op_data); H5_DLL herr_t H5A_dense_remove(H5F_t *f, hid_t dxpl_id, const H5O_t *oh, const char *name); +H5_DLL herr_t H5A_dense_remove_by_idx(H5F_t *f, hid_t dxpl_id, const H5O_t *oh, + H5_index_t idx_type, H5_iter_order_t order, hsize_t n); H5_DLL htri_t H5A_dense_exists(H5F_t *f, hid_t dxpl_id, const H5O_t *oh, const char *name); @@ -214,14 +206,27 @@ H5_DLL herr_t H5A_attr_iterate_table(const H5A_attr_table_t *atable, const H5A_attr_iter_op_t *attr_op, void *op_data); H5_DLL herr_t H5A_attr_release_table(H5A_attr_table_t *atable); -/* Attribute object header routines */ -H5_DLL herr_t H5O_attr_reset(void *_mesg); -H5_DLL herr_t H5O_attr_delete(H5F_t *f, hid_t dxpl_id, const void *_mesg); -H5_DLL herr_t H5O_attr_link(H5F_t *f, hid_t dxpl_id, const void *_mesg); - /* Attribute operations */ +H5_DLL herr_t H5O_attr_create(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr); +H5_DLL H5A_t *H5O_attr_open_by_name(const H5O_loc_t *loc, const char *name, + hid_t dxpl_id); +H5_DLL H5A_t *H5O_attr_open_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, + H5_iter_order_t order, hsize_t n, hid_t dxpl_id); H5_DLL herr_t H5O_attr_update_shared(H5F_t *f, hid_t dxpl_id, H5A_t *attr, H5O_shared_t *sh_mesg); +H5_DLL herr_t H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, + H5A_t *attr); +H5_DLL herr_t H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id, + const char *old_name, const char *new_name); +H5_DLL herr_t H5O_attr_iterate(hid_t loc_id, const H5O_loc_t *loc, hid_t dxpl_id, + H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, + hsize_t *last_attr, const H5A_attr_iter_op_t *op, void *op_data); +H5_DLL herr_t H5O_attr_remove(const H5O_loc_t *loc, const char *name, + hid_t dxpl_id); +H5_DLL herr_t 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); +H5_DLL int H5O_attr_count(const H5O_loc_t *loc, hid_t dxpl_id); +H5_DLL htri_t H5O_attr_exists(const H5O_loc_t *loc, const char *name, hid_t dxpl_id); /* Testing functions */ #ifdef H5A_TESTING diff --git a/src/H5Apublic.h b/src/H5Apublic.h index 757f320..818fc30 100644 --- a/src/H5Apublic.h +++ b/src/H5Apublic.h @@ -53,7 +53,8 @@ H5_DLL hid_t H5Aget_type(hid_t attr_id); H5_DLL hid_t H5Aget_create_plist(hid_t attr_id); H5_DLL ssize_t H5Aget_name(hid_t attr_id, size_t buf_size, char *buf); H5_DLL hsize_t H5Aget_storage_size(hid_t attr_id); -H5_DLL herr_t H5Aget_info(hid_t loc_id, const char *name, H5A_info_t *ainfo /*out*/); +H5_DLL herr_t H5Aget_info(hid_t loc_id, const char *obj_name, + const char *attr_name, H5A_info_t *ainfo /*out*/, hid_t lapl_id); H5_DLL herr_t H5Aget_info_by_idx(hid_t loc_id, const char *obj_name, H5_index_t idx_type, H5_iter_order_t order, hsize_t n, H5A_info_t *ainfo /*out*/, hid_t lapl_id); @@ -64,6 +65,8 @@ H5_DLL herr_t H5Arename(hid_t loc_id, const char *old_name, const char *new_nam H5_DLL herr_t H5Aiterate(hid_t loc_id, unsigned *attr_num, H5A_operator_t op, void *op_data); H5_DLL herr_t H5Adelete(hid_t loc_id, const char *name); +H5_DLL herr_t H5Adelete_by_idx(hid_t loc_id, const char *obj_name, + H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t lapl_id); /* Functions and variables defined for compatibility with previous versions * of the HDF5 API. diff --git a/src/H5Gdense.c b/src/H5Gdense.c index 5cea19c..ded0549 100644 --- a/src/H5Gdense.c +++ b/src/H5Gdense.c @@ -147,7 +147,7 @@ typedef struct { H5F_t *f; /* Pointer to file that fractal heap is in */ hid_t dxpl_id; /* DXPL for operation */ H5HF_t *fheap; /* Fractal heap handle */ - H5_index_t idx_type; /* Primary index for removing link */ + H5_index_t idx_type; /* Primary index for removing link */ haddr_t other_bt2_addr; /* Address of "other" v2 B-tree indexing link */ H5RS_str_t *grp_full_path_r; /* Full path of group where link is removed */ } H5G_bt2_ud_rmbi_t; diff --git a/src/H5Oattribute.c b/src/H5Oattribute.c index 2f8a1ea..7aea0df 100644 --- a/src/H5Oattribute.c +++ b/src/H5Oattribute.c @@ -997,7 +997,7 @@ H5O_attr_iterate(hid_t loc_id, const H5O_loc_t *loc, hid_t dxpl_id, else { /* Build table of attributes for compact storage */ if(H5A_compact_build_table(loc->file, dxpl_id, oh, idx_type, order, &atable, &oh_flags) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "error building attribute table") + HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table") /* Release the object header */ if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) @@ -1025,6 +1025,108 @@ done: /*------------------------------------------------------------------------- + * Function: H5O_attr_remove_update + * + * Purpose: Check for reverting from dense to compact attribute storage + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, February 14, 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_attr_remove_update(const H5O_loc_t *loc, H5O_t *oh, unsigned *oh_flags, + hid_t dxpl_id) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_attr_remove_update) + + /* Check arguments */ + HDassert(loc); + HDassert(oh); + HDassert(oh_flags); + + /* Reset the creation order min/max if there's no more attributes on the object */ + if(oh->nattrs == 0) + oh->max_attr_crt_idx = 0; + + /* Check for shifting from dense storage back to compact storage */ + if(H5F_addr_defined(oh->attr_fheap_addr)) { + /* Check if there's no more attributes */ + if(oh->nattrs == 0) { + /* Delete 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") + } /* end if */ + else if(oh->nattrs < oh->min_dense) { + H5A_attr_table_t atable = {0, NULL}; /* Table of attributes */ + hbool_t can_convert = TRUE; /* Whether converting to attribute messages is possible */ + size_t u; /* Local index */ + + /* Build the table of attributes for this object */ + if(H5A_dense_build_table(loc->file, dxpl_id, oh->attr_fheap_addr, oh->name_bt2_addr, H5_INDEX_NAME, H5_ITER_NATIVE, &atable) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table") + + /* Inspect attributes in table for ones that can't be converted back + * into attribute message form (currently only attributes which + * can't fit into an object header message) + */ + for(u = 0; u < oh->nattrs; u++) + if(H5O_msg_mesg_size(loc->file, H5O_ATTR_ID, &(atable.attrs[u]), (size_t)0) >= H5O_MESG_MAX_SIZE) { + can_convert = FALSE; + break; + } /* end if */ + + /* If ok, insert attributes as object header messages */ + if(can_convert) { + /* Iterate over attributes, to put them into header */ + for(u = 0; u < oh->nattrs; u++) { + htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */ + + /* Check if attribute is shared */ + if((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, &(atable.attrs[u]))) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error determining if message is shared") + else if(shared_mesg == 0) { + /* Increment reference count on attribute components */ + /* (so that they aren't deleted when the dense attribute storage is deleted) */ + if(H5O_attr_link(loc->file, dxpl_id, &(atable.attrs[u])) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count") + } /* end if */ + else { + /* Reset 'shared' status, so attributes will be shared again */ + atable.attrs[u].sh_loc.flags = 0; + } /* end else */ + + /* Insert attribute message into object header */ + /* (Will increment reference count on shared attributes) */ + if(H5O_msg_append_real(loc->file, dxpl_id, oh, H5O_MSG_ATTR, 0, 0, &(atable.attrs[u]), oh_flags) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't create message") + } /* end for */ + + /* 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, oh_flags) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") + } /* end if */ + + /* Free attribute table information */ + if(H5A_attr_release_table(&atable) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table") + } /* end else */ + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_attr_remove_update() */ + + +/*------------------------------------------------------------------------- * Function: H5O_attr_remove_cb * * Purpose: Object header iterator callback routine to remove an @@ -1083,7 +1185,7 @@ done: /*------------------------------------------------------------------------- * Function: H5O_attr_remove * - * Purpose: Delete an attributes on an object. + * Purpose: Delete an attribute on an object. * * Return: Non-negative on success/Negative on failure * @@ -1138,80 +1240,98 @@ H5O_attr_remove(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute") } /* end else */ - /* Check for shifting from dense storage back to compact storage */ - if(H5F_addr_defined(oh->attr_fheap_addr) && (oh->nattrs == 0 || oh->nattrs < oh->min_dense)) { - /* Check if there's no more attributes */ - if(oh->nattrs == 0) { - /* Delete 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") - } /* end if */ - else { - H5A_attr_table_t atable = {0, NULL}; /* Table of attributes */ - hbool_t can_convert = TRUE; /* Whether converting to attribute messages is possible */ - size_t u; /* Local index */ + /* Update the object header information after removing an attribute */ + if(H5O_attr_remove_update(loc, oh, &oh_flags, dxpl_id) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info") - /* Build the table of attributes for this object */ - if(H5A_dense_build_table(loc->file, dxpl_id, oh->attr_fheap_addr, oh->name_bt2_addr, H5_INDEX_NAME, H5_ITER_NATIVE, &atable) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "error building attribute table") +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") - /* Inspect attributes in table for ones that can't be converted back - * into attribute message form (currently only attributes which - * can't fit into an object header message) - */ - for(u = 0; u < oh->nattrs; u++) - if(H5O_msg_mesg_size(loc->file, H5O_ATTR_ID, &(atable.attrs[u]), (size_t)0) >= H5O_MESG_MAX_SIZE) { - can_convert = FALSE; - break; - } /* end if */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_attr_remove() */ - /* If ok, insert attributes as object header messages */ - if(can_convert) { - /* Iterate over attributes, to put them into header */ - for(u = 0; u < oh->nattrs; u++) { - htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */ + +/*------------------------------------------------------------------------- + * Function: H5O_attr_remove_by_idx + * + * Purpose: Delete an attribute on an object, according to an order within + * an index. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, February 14, 2007 + * + *------------------------------------------------------------------------- + */ +herr_t +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 */ + H5A_attr_table_t atable = {0, NULL}; /* Table of attributes */ + unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Check if attribute is shared */ - if((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, &(atable.attrs[u]))) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error determining if message is shared") - else if(shared_mesg == 0) { - /* Increment reference count on attribute components */ - /* (so that they aren't deleted when the dense attribute storage is deleted) */ - if(H5O_attr_link(loc->file, dxpl_id, &(atable.attrs[u])) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count") - } /* end if */ - else { - /* Reset 'shared' status, so attributes will be shared again */ - atable.attrs[u].sh_loc.flags = 0; - } /* end else */ + FUNC_ENTER_NOAPI_NOINIT(H5O_attr_remove_by_idx) - /* Insert attribute message into object header */ - /* (Will increment reference count on shared attributes) */ - if(H5O_msg_append_real(loc->file, dxpl_id, oh, H5O_MSG_ATTR, 0, 0, &(atable.attrs[u]), &oh_flags) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't create message") - } /* end for */ + /* Check arguments */ + HDassert(loc); - /* 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") + /* Protect the object header to iterate over */ + 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") - /* Update the modification time, if any */ - if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE, &oh_flags) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") - } /* end if */ + /* Check for attributes stored densely */ + if(H5F_addr_defined(oh->attr_fheap_addr)) { + /* Delete attribute from dense storage */ + if(H5A_dense_remove_by_idx(loc->file, dxpl_id, oh, idx_type, order, n) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage") - /* Free attribute table information */ - if(H5A_attr_release_table(&atable) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table") - } /* end else */ + /* Decrement # of attributes on object */ + oh->nattrs--; } /* end if */ + else { + H5O_iter_rm_t udata; /* User data for callback */ + H5O_mesg_operator_t op; /* Wrapper for operator */ + + /* Build table of attributes for compact storage */ + if(H5A_compact_build_table(loc->file, dxpl_id, oh, idx_type, order, &atable, &oh_flags) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table") + + /* Check for skipping too many attributes */ + if(n >= atable.nattrs) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified") + + /* Set up user data for callback, to remove the attribute by name */ + udata.f = loc->file; + udata.dxpl_id = dxpl_id; + udata.name = atable.attrs[n].name; + udata.found = FALSE; + + /* Iterate over attributes, to locate correct one to delete */ + op.lib_op = H5O_attr_remove_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_CANTDELETE, FAIL, "error deleting attribute") + + /* Check that we found the attribute */ + if(!udata.found) + HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute") + } /* end else */ + + /* Update the object header information after removing an attribute */ + if(H5O_attr_remove_update(loc, oh, &oh_flags, dxpl_id) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute info") 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") + if(atable.attrs && H5A_attr_release_table(&atable) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_attr_remove */ +} /* end H5O_attr_remove_by_idx() */ /*------------------------------------------------------------------------- diff --git a/src/H5Opkg.h b/src/H5Opkg.h index d3ff9c9..29c9052 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -471,23 +471,10 @@ H5_DLL herr_t H5O_shared_copy_file(H5F_t *file_src, H5F_t *file_dst, hid_t dxpl_ H5_DLL herr_t H5O_shared_debug(const H5O_shared_t *mesg, FILE *stream, int indent, int fwidth); -/* Attribute operations */ -H5_DLL herr_t H5O_attr_create(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr); -H5_DLL H5A_t *H5O_attr_open_by_name(const H5O_loc_t *loc, const char *name, - hid_t dxpl_id); -H5_DLL H5A_t *H5O_attr_open_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, - H5_iter_order_t order, hsize_t n, hid_t dxpl_id); -H5_DLL herr_t H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, - H5A_t *attr); -H5_DLL herr_t H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id, - const char *old_name, const char *new_name); -H5_DLL herr_t H5O_attr_iterate(hid_t loc_id, const H5O_loc_t *loc, hid_t dxpl_id, - H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, - hsize_t *last_attr, const H5A_attr_iter_op_t *op, void *op_data); -H5_DLL herr_t H5O_attr_remove(const H5O_loc_t *loc, const char *name, - hid_t dxpl_id); -H5_DLL int H5O_attr_count(const H5O_loc_t *loc, hid_t dxpl_id); -H5_DLL htri_t H5O_attr_exists(const H5O_loc_t *loc, const char *name, hid_t dxpl_id); +/* Attribute operators */ +H5_DLL herr_t H5O_attr_reset(void *_mesg); +H5_DLL herr_t H5O_attr_delete(H5F_t *f, hid_t dxpl_id, const void *_mesg); +H5_DLL herr_t H5O_attr_link(H5F_t *f, hid_t dxpl_id, const void *_mesg); /* These functions operate on object locations */ H5_DLL H5O_loc_t *H5O_get_loc(hid_t id); diff --git a/test/tattr.c b/test/tattr.c index 3036aab..bfb0a9b 100644 --- a/test/tattr.c +++ b/test/tattr.c @@ -2947,7 +2947,7 @@ test_attr_corder_create_compact(hid_t fcpl, hid_t fapl) /* Retrieve information for attribute */ sprintf(attrname, "attr %02u", u); - ret = H5Aget_info(my_dataset, attrname, &ainfo); + ret = H5Aget_info(my_dataset, ".", attrname, &ainfo, H5P_DEFAULT); CHECK(ret, FAIL, "H5Aget_info"); /* Verify creation order of attribute */ @@ -3173,7 +3173,7 @@ test_attr_corder_create_dense(hid_t fcpl, hid_t fapl) /* Retrieve information for attribute */ sprintf(attrname, "attr %02u", u); - ret = H5Aget_info(my_dataset, attrname, &ainfo); + ret = H5Aget_info(my_dataset, ".", attrname, &ainfo, H5P_DEFAULT); CHECK(ret, FAIL, "H5Aget_info"); /* Verify creation order of attribute */ @@ -4047,94 +4047,94 @@ test_attr_info_by_idx(hbool_t new_format, hid_t fcpl, hid_t fapl) VERIFY(ret, FAIL, "H5Aget_info_by_idx"); ret = H5Aget_name_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)0, tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); VERIFY(ret, FAIL, "H5Aget_name_by_idx"); - } /* end for */ - /* Create attributes, up to limit of compact form */ - for(u = 0; u < max_compact; u++) { - /* Create attribute */ - sprintf(attrname, "attr %02u", u); - attr = H5Acreate(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT); - CHECK(attr, FAIL, "H5Acreate"); + /* Create attributes, up to limit of compact form */ + for(u = 0; u < max_compact; u++) { + /* Create attribute */ + sprintf(attrname, "attr %02u", u); + attr = H5Acreate(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate"); - /* Write data into the attribute */ - ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); - CHECK(ret, FAIL, "H5Awrite"); + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); - /* Close attribute */ - ret = H5Aclose(attr); - CHECK(ret, FAIL, "H5Aclose"); + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); - /* Verify information for new attribute */ - ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); - CHECK(ret, FAIL, "attr_info_by_idx_check"); - } /* end for */ + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ - /* Verify state of object */ - ret = H5O_num_attrs_test(my_dataset, &nattrs); - CHECK(ret, FAIL, "H5O_num_attrs_test"); - VERIFY(nattrs, max_compact, "H5O_num_attrs_test"); - is_empty = H5O_is_attr_empty_test(my_dataset); - VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); - is_dense = H5O_is_attr_dense_test(my_dataset); - VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); + /* Verify state of object */ + ret = H5O_num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O_num_attrs_test"); + VERIFY(nattrs, max_compact, "H5O_num_attrs_test"); + is_empty = H5O_is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); - /* Check for out of bound offset queries */ - ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, &ainfo, H5P_DEFAULT); - VERIFY(ret, FAIL, "H5Aget_info_by_idx"); - ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, (hsize_t)u, &ainfo, H5P_DEFAULT); - VERIFY(ret, FAIL, "H5Aget_info_by_idx"); - ret = H5Aget_name_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); - VERIFY(ret, FAIL, "H5Aget_name_by_idx"); + /* Check for out of bound offset queries */ + ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, &ainfo, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Aget_info_by_idx"); + ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, (hsize_t)u, &ainfo, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Aget_info_by_idx"); + ret = H5Aget_name_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Aget_name_by_idx"); - /* Create more attributes, to push into dense form */ - for(; u < (max_compact * 2); u++) { - /* Create attribute */ - sprintf(attrname, "attr %02u", u); - attr = H5Acreate(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT); - CHECK(attr, FAIL, "H5Acreate"); + /* Create more attributes, to push into dense form */ + for(; u < (max_compact * 2); u++) { + /* Create attribute */ + sprintf(attrname, "attr %02u", u); + attr = H5Acreate(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate"); - /* Write data into the attribute */ - ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); - CHECK(ret, FAIL, "H5Awrite"); + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); - /* Close attribute */ - ret = H5Aclose(attr); - CHECK(ret, FAIL, "H5Aclose"); + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Verify state of object */ + is_dense = H5O_is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O_is_attr_dense_test"); + + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ /* Verify state of object */ + ret = H5O_num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O_num_attrs_test"); + VERIFY(nattrs, (max_compact * 2), "H5O_num_attrs_test"); + is_empty = H5O_is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); is_dense = H5O_is_attr_dense_test(my_dataset); VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O_is_attr_dense_test"); - /* Verify information for new attribute */ - ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); - CHECK(ret, FAIL, "attr_info_by_idx_check"); - } /* end for */ - - /* Verify state of object */ - ret = H5O_num_attrs_test(my_dataset, &nattrs); - CHECK(ret, FAIL, "H5O_num_attrs_test"); - VERIFY(nattrs, (max_compact * 2), "H5O_num_attrs_test"); - is_empty = H5O_is_attr_empty_test(my_dataset); - VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); - is_dense = H5O_is_attr_dense_test(my_dataset); - VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O_is_attr_dense_test"); - - if(new_format) { - /* Retrieve & verify # of records in the name & creation order indices */ - ret = H5O_attr_dense_info_test(my_dataset, &name_count, &corder_count); - CHECK(ret, FAIL, "H5O_attr_dense_info_test"); - if(use_index) - VERIFY(name_count, corder_count, "H5O_attr_dense_info_test"); - VERIFY(name_count, (max_compact * 2), "H5O_attr_dense_info_test"); - } /* end if */ + if(new_format) { + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O_attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O_attr_dense_info_test"); + if(use_index) + VERIFY(name_count, corder_count, "H5O_attr_dense_info_test"); + VERIFY(name_count, (max_compact * 2), "H5O_attr_dense_info_test"); + } /* end if */ - /* Check for out of bound offset queries */ - ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, &ainfo, H5P_DEFAULT); - VERIFY(ret, FAIL, "H5Aget_info_by_idx"); - ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, (hsize_t)u, &ainfo, H5P_DEFAULT); - VERIFY(ret, FAIL, "H5Aget_info_by_idx"); - ret = H5Aget_name_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); - VERIFY(ret, FAIL, "H5Aget_name_by_idx"); + /* Check for out of bound offset queries */ + ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, &ainfo, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Aget_info_by_idx"); + ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, (hsize_t)u, &ainfo, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Aget_info_by_idx"); + ret = H5Aget_name_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Aget_name_by_idx"); + } /* end for */ /* Close Datasets */ ret = H5Dclose(dset1); @@ -4152,6 +4152,273 @@ test_attr_info_by_idx(hbool_t new_format, hid_t fcpl, hid_t fapl) /**************************************************************** ** +** test_attr_delete_by_idx(): Test basic H5A (attribute) code. +** Tests deleting attribute by index +** +****************************************************************/ +static void +test_attr_delete_by_idx(hbool_t new_format, hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + H5A_info_t ainfo; /* Attribute information */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ + hsize_t name_count; /* # of records in name index */ + hsize_t corder_count; /* # of records in creation order index */ + H5_index_t idx_type; /* Type of index to operate on */ + H5_iter_order_t order; /* Order within in the index */ + hbool_t use_index; /* Use index on creation order values */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + char tmpname[NAME_BUF_SIZE]; /* Temporary attribute name */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Loop over operating on different indices on link fields */ + for(idx_type = H5_INDEX_NAME; idx_type <=H5_INDEX_CRT_ORDER; idx_type++) { + /* Loop over operating in different orders */ + for(order = H5_ITER_INC; order <=H5_ITER_DEC; order++) { + /* Loop over using index for creation order value */ + for(use_index = FALSE; use_index <= TRUE; use_index++) { + /* Print appropriate test message */ + if(idx_type == H5_INDEX_CRT_ORDER) { + if(order == H5_ITER_INC) { + if(use_index) + MESSAGE(5, ("Testing Deleting Attribute By Creation Order Index in Increasing Order w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Deleting Attribute By Creation Order Index in Increasing Order w/o Creation Order Index\n")) + } /* end if */ + else { + if(use_index) + MESSAGE(5, ("Testing Deleting Attribute By Creation Order Index in Decreasing Order w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Deleting Attribute By Creation Order Index in Decreasing Order w/o Creation Order Index\n")) + } /* end else */ + } /* end if */ + else { + if(order == H5_ITER_INC) { + if(use_index) + MESSAGE(5, ("Testing Deleting Attribute By Name Index in Increasing Order w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Deleting Attribute By Name Index in Increasing Order w/o Creation Order Index\n")) + } /* end if */ + else { + if(use_index) + MESSAGE(5, ("Testing Deleting Attribute By Name Index in Decreasing Order w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Deleting Attribute By Name Index in Decreasing Order w/o Creation Order Index\n")) + } /* end else */ + } /* end else */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set attribute creation order tracking & indexing for object */ + ret = H5Pset_attr_creation_order(dcpl, (H5P_CRT_ORDER_TRACKED | (use_index ? H5P_CRT_ORDER_INDEXED : (unsigned)0))); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Create datasets */ + dset1 = H5Dcreate(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, dcpl); + CHECK(dset1, FAIL, "H5Dcreate"); + dset2 = H5Dcreate(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, dcpl); + CHECK(dset2, FAIL, "H5Dcreate"); + dset3 = H5Dcreate(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, dcpl); + CHECK(dset3, FAIL, "H5Dcreate"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Work on all the datasets */ + for(curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch(curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Check on dataset's attribute storage status */ + is_empty = H5O_is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); + + /* Check for deleting non-existant attribute */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Adelete_by_idx"); + + /* Create attributes, up to limit of compact form */ + for(u = 0; u < max_compact; u++) { + /* Create attribute */ + sprintf(attrname, "attr %02u", u); + attr = H5Acreate(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ + + /* Verify state of object */ + ret = H5O_num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O_num_attrs_test"); + VERIFY(nattrs, max_compact, "H5O_num_attrs_test"); + is_empty = H5O_is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O_is_attr_dense_test"); + + /* Check for out of bound deletions */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)u, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Adelete_by_idx"); + + /* Delete attributes from compact storage */ + for(u = 0; u < (max_compact - 1); u++) { + /* Delete first attribute in appropriate order */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_idx"); + + /* Verify the attribute information for first attribute in appropriate order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, &ainfo, H5P_DEFAULT); + if(new_format) { + if(order == H5_ITER_INC) { + VERIFY(ainfo.corder, (u + 1), "H5Aget_info_by_idx"); + } /* end if */ + else { + VERIFY(ainfo.corder, (max_compact - (u + 2)), "H5Aget_info_by_idx"); + } /* end else */ + } /* end if */ + + /* Verify the name for first attribute in appropriate order */ + HDmemset(tmpname, 0, (size_t)NAME_BUF_SIZE); + ret = H5Aget_name_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + if(order == H5_ITER_INC) + sprintf(attrname, "attr %02u", (u + 1)); + else + sprintf(attrname, "attr %02u", (max_compact - (u + 2))); + ret = HDstrcmp(attrname, tmpname); + VERIFY(ret, 0, "H5Aget_name_by_idx"); + } /* end for */ + + /* Delete last attribute */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_idx"); + + /* Verify state of attribute storage (empty) */ + is_empty = H5O_is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O_is_attr_empty_test"); + + /* Create more attributes, to push into dense form */ + for(u = 0; u < (max_compact * 2); u++) { + /* Create attribute */ + sprintf(attrname, "attr %02u", u); + attr = H5Acreate(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Verify state of object */ + if(u >= max_compact) { + is_dense = H5O_is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O_is_attr_dense_test"); + } /* end if */ + + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ + + /* Verify state of object */ + ret = H5O_num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O_num_attrs_test"); + VERIFY(nattrs, (max_compact * 2), "H5O_num_attrs_test"); + is_empty = H5O_is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O_is_attr_empty_test"); + is_dense = H5O_is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O_is_attr_dense_test"); + + if(new_format) { + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O_attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O_attr_dense_info_test"); + if(use_index) + VERIFY(name_count, corder_count, "H5O_attr_dense_info_test"); + VERIFY(name_count, (max_compact * 2), "H5O_attr_dense_info_test"); + } /* end if */ + +#ifdef NOT_YET + /* Check for out of bound deletion */ +HDfprintf(stderr, "new_format = %t, use_index = %t, idx_type = %u, order = %u\n", new_format, use_index, (unsigned)idx_type, (unsigned)order); + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)u, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Adelete_by_idx"); +#endif /* NOT_YET */ + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + } /* end for */ + } /* end for */ +} /* test_attr_delete_by_idx() */ + +/**************************************************************** +** ** test_attr_shared_write(): Test basic H5A (attribute) code. ** Tests writing mix of shared & un-shared attributes in "compact" & "dense" storage ** @@ -5761,7 +6028,8 @@ test_attr(void) test_attr_corder_delete(my_fcpl, my_fapl); /* Test deleting object using dense storage w/attribute creation order info */ /* New attribute API routine tests */ - test_attr_info_by_idx(new_format, my_fcpl, my_fapl); /* Test querying attribute info by index */ + test_attr_info_by_idx(new_format, my_fcpl, my_fapl); /* Test querying attribute info by index */ + test_attr_delete_by_idx(new_format, my_fcpl, my_fapl); /* Test deleting attribute by index */ /* More complex tests with both "new format" and "shared" attributes */ if(use_shared == TRUE) { @@ -5774,7 +6042,8 @@ test_attr(void) } /* end if */ else { /* New attribute API routine tests, on old-format storage */ - test_attr_info_by_idx(new_format, fcpl, my_fapl); /* Test querying attribute info by index */ + test_attr_info_by_idx(new_format, fcpl, my_fapl); /* Test querying attribute info by index */ + test_attr_delete_by_idx(new_format, fcpl, my_fapl); /* Test deleting attribute by index */ } /* end else */ } /* end for */ -- cgit v0.12