/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Purpose: v1 B-tree indexed (chunked) I/O functions. The chunks are * given a multi-dimensional index which is used as a lookup key * in a B-tree that maps chunk index to disk address. */ /****************/ /* Module Setup */ /****************/ #include "H5Dmodule.h" /* This source code file is part of the H5D module */ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Bprivate.h" /* B-link trees */ #include "H5Dpkg.h" /* Datasets */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* Files */ #include "H5FDprivate.h" /* File drivers */ #include "H5FLprivate.h" /* Free Lists */ #include "H5MFprivate.h" /* File space management */ #include "H5MMprivate.h" /* Memory management */ #include "H5Oprivate.h" /* Object headers */ #include "H5Sprivate.h" /* Dataspaces */ #include "H5VMprivate.h" /* Vector and array functions */ /****************/ /* Local Macros */ /****************/ #define H5D_BTREE_IDX_IS_OPEN(idx_info) (NULL != (idx_info)->storage->u.btree.shared) /******************/ /* Local Typedefs */ /******************/ /* * B-tree key. A key contains the minimum logical N-dimensional coordinates and * the logical size of the chunk to which this key refers. The * fastest-varying dimension is assumed to reference individual bytes of the * array, so a 100-element 1-d array of 4-byte integers would really be a 2-d * array with the slow varying dimension of size 100 and the fast varying * dimension of size 4 (the storage dimensionality has very little to do with * the real dimensionality). * * Only the first few values of the OFFSET and SIZE fields are actually * stored on disk, depending on the dimensionality. * * The chunk's file address is part of the B-tree and not part of the key. */ typedef struct H5D_btree_key_t { hsize_t scaled[H5O_LAYOUT_NDIMS]; /*logical offset to start */ uint32_t nbytes; /*size of stored data */ unsigned filter_mask; /*excluded filters */ } H5D_btree_key_t; /* B-tree callback info for iteration over chunks */ typedef struct H5D_btree_it_ud_t { H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */ H5D_chunk_cb_func_t cb; /* Chunk callback routine */ void *udata; /* User data for chunk callback routine */ } H5D_btree_it_ud_t; /* B-tree callback info for debugging */ typedef struct H5D_btree_dbg_t { H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */ unsigned ndims; /* Number of dimensions */ } H5D_btree_dbg_t; /********************/ /* Local Prototypes */ /********************/ static herr_t H5D__btree_shared_free(void *_shared); static herr_t H5D__btree_shared_create(const H5F_t *f, H5O_storage_chunk_t *store, const H5O_layout_chunk_t *layout); /* B-tree iterator callbacks */ static int H5D__btree_idx_iterate_cb(H5F_t *f, const void *left_key, haddr_t addr, const void *right_key, void *_udata); /* B-tree callbacks */ static H5UC_t *H5D__btree_get_shared(const H5F_t *f, const void *_udata); static herr_t H5D__btree_new_node(H5F_t *f, H5B_ins_t, void *_lt_key, void *_udata, void *_rt_key, haddr_t *addr_p /*out*/); static int H5D__btree_cmp2(void *_lt_key, void *_udata, void *_rt_key); static int H5D__btree_cmp3(void *_lt_key, void *_udata, void *_rt_key); static htri_t H5D__btree_found(H5F_t *f, haddr_t addr, const void *_lt_key, bool *found, void *_udata); static H5B_ins_t H5D__btree_insert(H5F_t *f, haddr_t addr, void *_lt_key, bool *lt_key_changed, void *_md_key, void *_udata, void *_rt_key, bool *rt_key_changed, haddr_t *new_node /*out*/); static H5B_ins_t H5D__btree_remove(H5F_t *f, haddr_t addr, void *_lt_key, bool *lt_key_changed, void *_udata, void *_rt_key, bool *rt_key_changed); static herr_t H5D__btree_decode_key(const H5B_shared_t *shared, const uint8_t *raw, void *_key); static herr_t H5D__btree_encode_key(const H5B_shared_t *shared, uint8_t *raw, const void *_key); static herr_t H5D__btree_debug_key(FILE *stream, int indent, int fwidth, const void *key, const void *udata); /* Chunked layout indexing callbacks */ static herr_t H5D__btree_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t *space, haddr_t dset_ohdr_addr); static herr_t H5D__btree_idx_create(const H5D_chk_idx_info_t *idx_info); static herr_t H5D__btree_idx_open(const H5D_chk_idx_info_t *idx_info); static herr_t H5D__btree_idx_close(const H5D_chk_idx_info_t *idx_info); static herr_t H5D__btree_idx_is_open(const H5D_chk_idx_info_t *idx_info, bool *is_open); static bool H5D__btree_idx_is_space_alloc(const H5O_storage_chunk_t *storage); static herr_t H5D__btree_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata, const H5D_t *dset); static herr_t H5D__btree_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata); static herr_t H5D__btree_idx_load_metadata(const H5D_chk_idx_info_t *idx_info); static int H5D__btree_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb, void *chunk_udata); static herr_t H5D__btree_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata); static herr_t H5D__btree_idx_delete(const H5D_chk_idx_info_t *idx_info); static herr_t H5D__btree_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src, const H5D_chk_idx_info_t *idx_info_dst); static herr_t H5D__btree_idx_copy_shutdown(H5O_storage_chunk_t *storage_src, H5O_storage_chunk_t *storage_dst); static herr_t H5D__btree_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *size); static herr_t H5D__btree_idx_reset(H5O_storage_chunk_t *storage, bool reset_addr); static herr_t H5D__btree_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream); static herr_t H5D__btree_idx_dest(const H5D_chk_idx_info_t *idx_info); /*********************/ /* Package Variables */ /*********************/ /* v1 B-tree indexed chunk I/O ops */ const H5D_chunk_ops_t H5D_COPS_BTREE[1] = {{ false, /* v1 B-tree indices does not support SWMR access */ H5D__btree_idx_init, /* insert */ H5D__btree_idx_create, /* create */ H5D__btree_idx_open, /* open */ H5D__btree_idx_close, /* close */ H5D__btree_idx_is_open, /* is_open */ H5D__btree_idx_is_space_alloc, /* is_space_alloc */ H5D__btree_idx_insert, /* insert */ H5D__btree_idx_get_addr, /* get_addr */ H5D__btree_idx_load_metadata, /* load_metadata */ NULL, /* resize */ H5D__btree_idx_iterate, /* iterate */ H5D__btree_idx_remove, /* remove */ H5D__btree_idx_delete, /* delete */ H5D__btree_idx_copy_setup, /* copy_setup */ H5D__btree_idx_copy_shutdown, /* copy_shutdown */ H5D__btree_idx_size, /* size */ H5D__btree_idx_reset, /* reset */ H5D__btree_idx_dump, /* dump */ H5D__btree_idx_dest /* destroy */ }}; /*****************************/ /* Library Private Variables */ /*****************************/ /* inherits B-tree like properties from H5B */ static H5B_class_t H5B_BTREE[1] = {{ H5B_CHUNK_ID, /* id */ sizeof(H5D_btree_key_t), /* sizeof_nkey */ H5D__btree_get_shared, /* get_shared */ H5D__btree_new_node, /* new */ H5D__btree_cmp2, /* cmp2 */ H5D__btree_cmp3, /* cmp3 */ H5D__btree_found, /* found */ H5D__btree_insert, /* insert */ false, /* follow min branch? */ false, /* follow max branch? */ H5B_LEFT, /* critical key */ H5D__btree_remove, /* remove */ H5D__btree_decode_key, /* decode */ H5D__btree_encode_key, /* encode */ H5D__btree_debug_key /* debug */ }}; /*******************/ /* Local Variables */ /*******************/ /* Declare a free list to manage H5O_layout_chunk_t objects */ H5FL_DEFINE_STATIC(H5O_layout_chunk_t); /*------------------------------------------------------------------------- * Function: H5D__btree_get_shared * * Purpose: Returns the shared B-tree info for the specified UDATA. * * Return: Success: Pointer to the raw B-tree page for this dataset * * Failure: Can't fail * *------------------------------------------------------------------------- */ static H5UC_t * H5D__btree_get_shared(const H5F_t H5_ATTR_UNUSED *f, const void *_udata) { const H5D_chunk_common_ud_t *udata = (const H5D_chunk_common_ud_t *)_udata; FUNC_ENTER_PACKAGE_NOERR assert(udata); assert(udata->storage); assert(udata->storage->idx_type == H5D_CHUNK_IDX_BTREE); assert(udata->storage->u.btree.shared); /* Return the pointer to the ref-count object */ FUNC_LEAVE_NOAPI(udata->storage->u.btree.shared) } /* end H5D__btree_get_shared() */ /*------------------------------------------------------------------------- * Function: H5D__btree_new_node * * Purpose: Adds a new entry to an i-storage B-tree. We can assume * that the domain represented by UDATA doesn't intersect the * domain already represented by the B-tree. * * Return: Success: Non-negative. The address of leaf is returned * through the ADDR argument. It is also added * to the UDATA. * * Failure: Negative * *------------------------------------------------------------------------- */ static herr_t H5D__btree_new_node(H5F_t H5_ATTR_NDEBUG_UNUSED *f, H5B_ins_t op, void *_lt_key, void *_udata, void *_rt_key, haddr_t *addr_p /*out*/) { H5D_btree_key_t *lt_key = (H5D_btree_key_t *)_lt_key; H5D_btree_key_t *rt_key = (H5D_btree_key_t *)_rt_key; H5D_chunk_ud_t *udata = (H5D_chunk_ud_t *)_udata; unsigned u; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE_NOERR /* check args */ assert(f); assert(lt_key); assert(rt_key); assert(udata); assert(udata->common.layout->ndims > 0 && udata->common.layout->ndims < H5O_LAYOUT_NDIMS); assert(addr_p); /* Set address */ assert(H5_addr_defined(udata->chunk_block.offset)); assert(udata->chunk_block.length > 0); *addr_p = udata->chunk_block.offset; /* * The left key describes the storage of the UDATA chunk being * inserted into the tree. */ H5_CHECKED_ASSIGN(lt_key->nbytes, uint32_t, udata->chunk_block.length, hsize_t); lt_key->filter_mask = udata->filter_mask; for (u = 0; u < udata->common.layout->ndims; u++) lt_key->scaled[u] = udata->common.scaled[u]; /* * The right key might already be present. If not, then add a zero-width * chunk. */ if (H5B_INS_LEFT != op) { rt_key->nbytes = 0; rt_key->filter_mask = 0; for (u = 0; u < udata->common.layout->ndims; u++) { assert(udata->common.scaled[u] + 1 > udata->common.scaled[u]); rt_key->scaled[u] = udata->common.scaled[u] + 1; } /* end if */ } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_new_node() */ /*------------------------------------------------------------------------- * Function: H5D__btree_cmp2 * * Purpose: Compares two keys sort of like strcmp(). The UDATA pointer * is only to supply extra information not carried in the keys * (in this case, the dimensionality) and is not compared * against the keys. * * Return: Success: -1 if LT_KEY is less than RT_KEY; * 1 if LT_KEY is greater than RT_KEY; * 0 if LT_KEY and RT_KEY are equal. * * Failure: FAIL (same as LT_KEY < RT_KEY) * *------------------------------------------------------------------------- */ static int H5D__btree_cmp2(void *_lt_key, void *_udata, void *_rt_key) { H5D_btree_key_t *lt_key = (H5D_btree_key_t *)_lt_key; H5D_btree_key_t *rt_key = (H5D_btree_key_t *)_rt_key; H5D_chunk_common_ud_t *udata = (H5D_chunk_common_ud_t *)_udata; int ret_value = -1; /* Return value */ FUNC_ENTER_PACKAGE_NOERR assert(lt_key); assert(rt_key); assert(udata); assert(udata->layout->ndims > 0 && udata->layout->ndims <= H5O_LAYOUT_NDIMS); /* Compare the offsets but ignore the other fields */ ret_value = H5VM_vector_cmp_u(udata->layout->ndims, lt_key->scaled, rt_key->scaled); FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_cmp2() */ /*------------------------------------------------------------------------- * Function: H5D__btree_cmp3 * * Purpose: Compare the requested datum UDATA with the left and right * keys of the B-tree. * * Return: Success: negative if the min_corner of UDATA is less * than the min_corner of LT_KEY. * * positive if the min_corner of UDATA is * greater than or equal the min_corner of * RT_KEY. * * zero otherwise. The min_corner of UDATA is * not necessarily contained within the address * space represented by LT_KEY, but a key that * would describe the UDATA min_corner address * would fall lexicographically between LT_KEY * and RT_KEY. * * Failure: FAIL (same as UDATA < LT_KEY) * *------------------------------------------------------------------------- */ static int H5D__btree_cmp3(void *_lt_key, void *_udata, void *_rt_key) { H5D_btree_key_t *lt_key = (H5D_btree_key_t *)_lt_key; H5D_btree_key_t *rt_key = (H5D_btree_key_t *)_rt_key; H5D_chunk_common_ud_t *udata = (H5D_chunk_common_ud_t *)_udata; int ret_value = 0; FUNC_ENTER_PACKAGE_NOERR assert(lt_key); assert(rt_key); assert(udata); assert(udata->layout->ndims > 0 && udata->layout->ndims <= H5O_LAYOUT_NDIMS); /* Special case for faster checks on 1-D chunks */ /* (Checking for ndims==2 because last dimension is the datatype size) */ /* The additional checking for the right key is necessary due to the */ /* slightly odd way the library initializes the right-most node in the */ /* indexed storage B-tree... */ /* (Dump the B-tree with h5debug to look at it) -QAK */ if (udata->layout->ndims == 2) { if (udata->scaled[0] > rt_key->scaled[0]) ret_value = 1; else if (udata->scaled[0] == rt_key->scaled[0] && udata->scaled[1] >= rt_key->scaled[1]) ret_value = 1; else if (udata->scaled[0] < lt_key->scaled[0]) ret_value = (-1); } /* end if */ else { if (H5VM_vector_ge_u(udata->layout->ndims, udata->scaled, rt_key->scaled)) ret_value = 1; else if (H5VM_vector_lt_u(udata->layout->ndims, udata->scaled, lt_key->scaled)) ret_value = (-1); } /* end else */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_cmp3() */ /*------------------------------------------------------------------------- * Function: H5D__btree_found * * Purpose: This function is called when the B-tree search engine has * found the leaf entry that points to a chunk of storage that * contains the beginning of the logical address space * represented by UDATA. The LT_KEY is the left key (the one * that describes the chunk) and RT_KEY is the right key (the * one that describes the next or last chunk). * * Note: It's possible that the chunk isn't really found. For * instance, in a sparse dataset the requested chunk might fall * between two stored chunks in which case this function is * called with the maximum stored chunk indices less than the * requested chunk indices. * * Return: Non-negative on success with information about the * chunk returned through the UDATA argument, if *FOUND is * true. * Negative on failure. * *------------------------------------------------------------------------- */ static htri_t H5D__btree_found(H5F_t H5_ATTR_UNUSED *f, haddr_t addr, const void *_lt_key, bool *found, void *_udata) { H5D_chunk_ud_t *udata = (H5D_chunk_ud_t *)_udata; const H5D_btree_key_t *lt_key = (const H5D_btree_key_t *)_lt_key; unsigned u; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE_NOERR /* Check arguments */ assert(f); assert(H5_addr_defined(addr)); assert(lt_key); assert(found); assert(udata); /* Is this *really* the requested chunk? */ for (u = 0; u < udata->common.layout->ndims; u++) if (udata->common.scaled[u] >= (lt_key->scaled[u] + 1)) { *found = false; HGOTO_DONE(SUCCEED); } /* Initialize return values */ assert(lt_key->nbytes > 0); udata->chunk_block.offset = addr; udata->chunk_block.length = lt_key->nbytes; udata->filter_mask = lt_key->filter_mask; *found = true; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_found() */ /*------------------------------------------------------------------------- * Function: H5D__chunk_disjoint * * Purpose: Determines if two chunks are disjoint. * * Return: Success: false if they are not disjoint. * true if they are disjoint. * * Note: Assumes that the chunk offsets are scaled coordinates * *------------------------------------------------------------------------- */ static bool H5D__chunk_disjoint(unsigned n, const hsize_t *scaled1, const hsize_t *scaled2) { unsigned u; /* Local index variable */ bool ret_value = false; /* Return value */ FUNC_ENTER_PACKAGE_NOERR /* Sanity checks */ assert(n); assert(scaled1); assert(scaled2); /* Loop over two chunks, detecting disjointness and getting out quickly */ for (u = 0; u < n; u++) if ((scaled1[u] + 1) <= scaled2[u] || (scaled2[u] + 1) <= scaled1[u]) HGOTO_DONE(true); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__chunk_disjoint() */ /*------------------------------------------------------------------------- * Function: H5D__btree_insert * * Purpose: This function is called when the B-tree insert engine finds * the node to use to insert new data. The UDATA argument * points to a struct that describes the logical addresses being * added to the file. This function allocates space for the * data and returns information through UDATA describing a * file chunk to receive (part of) the data. * * The LT_KEY is always the key describing the chunk of file * memory at address ADDR. On entry, UDATA describes the logical * addresses for which storage is being requested (through the * `offset' and `size' fields). On return, UDATA describes the * logical addresses contained in a chunk on disk. * * Return: Success: An insertion command for the caller, one of * the H5B_INS_* constants. The address of the * new chunk is returned through the NEW_NODE * argument. * * Failure: H5B_INS_ERROR * *------------------------------------------------------------------------- */ static H5B_ins_t H5D__btree_insert(H5F_t H5_ATTR_NDEBUG_UNUSED *f, haddr_t H5_ATTR_NDEBUG_UNUSED addr, void *_lt_key, bool *lt_key_changed, void *_md_key, void *_udata, void *_rt_key, bool H5_ATTR_UNUSED *rt_key_changed, haddr_t *new_node_p /*out*/) { H5D_btree_key_t *lt_key = (H5D_btree_key_t *)_lt_key; H5D_btree_key_t *md_key = (H5D_btree_key_t *)_md_key; H5D_btree_key_t *rt_key = (H5D_btree_key_t *)_rt_key; H5D_chunk_ud_t *udata = (H5D_chunk_ud_t *)_udata; int cmp; unsigned u; H5B_ins_t ret_value = H5B_INS_ERROR; /* Return value */ FUNC_ENTER_PACKAGE /* check args */ assert(f); assert(H5_addr_defined(addr)); assert(lt_key); assert(lt_key_changed); assert(md_key); assert(udata); assert(rt_key); assert(new_node_p); cmp = H5D__btree_cmp3(lt_key, udata, rt_key); assert(cmp <= 0); if (cmp < 0) { /* Negative indices not supported yet */ HGOTO_ERROR(H5E_STORAGE, H5E_UNSUPPORTED, H5B_INS_ERROR, "internal error"); } else if (H5VM_vector_eq_u(udata->common.layout->ndims, udata->common.scaled, lt_key->scaled) && lt_key->nbytes > 0) { /* * Already exists. If the new size is not the same as the old size * then we should reallocate storage. */ if (lt_key->nbytes != udata->chunk_block.length) { /* Set node's address (already re-allocated by main chunk routines) */ assert(H5_addr_defined(udata->chunk_block.offset)); *new_node_p = udata->chunk_block.offset; H5_CHECKED_ASSIGN(lt_key->nbytes, uint32_t, udata->chunk_block.length, hsize_t); lt_key->filter_mask = udata->filter_mask; *lt_key_changed = true; ret_value = H5B_INS_CHANGE; } else { /* Already have address in udata, from main chunk routines */ assert(H5_addr_defined(udata->chunk_block.offset)); ret_value = H5B_INS_NOOP; } } else if (H5D__chunk_disjoint(udata->common.layout->ndims, lt_key->scaled, udata->common.scaled)) { assert(H5D__chunk_disjoint(udata->common.layout->ndims, rt_key->scaled, udata->common.scaled)); /* * Split this node, inserting the new new node to the right of the * current node. The MD_KEY is where the split occurs. */ H5_CHECKED_ASSIGN(md_key->nbytes, uint32_t, udata->chunk_block.length, hsize_t); md_key->filter_mask = udata->filter_mask; for (u = 0; u < udata->common.layout->ndims; u++) md_key->scaled[u] = udata->common.scaled[u]; assert(H5_addr_defined(udata->chunk_block.offset)); *new_node_p = udata->chunk_block.offset; ret_value = H5B_INS_RIGHT; } else { HGOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, H5B_INS_ERROR, "internal error"); } done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_insert() */ /*------------------------------------------------------------------------- * Function: H5D__btree_remove * * Purpose: Removes chunks that are no longer necessary in the B-tree. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static H5B_ins_t H5D__btree_remove(H5F_t *f, haddr_t addr, void *_lt_key /*in,out */, bool *lt_key_changed /*out */, void H5_ATTR_UNUSED *_udata /*in,out */, void H5_ATTR_UNUSED *_rt_key /*in,out */, bool *rt_key_changed /*out */) { H5D_btree_key_t *lt_key = (H5D_btree_key_t *)_lt_key; H5B_ins_t ret_value = H5B_INS_REMOVE; /* Return value */ FUNC_ENTER_PACKAGE /* Remove raw data chunk from file */ H5_CHECK_OVERFLOW(lt_key->nbytes, uint32_t, hsize_t); if (H5MF_xfree(f, H5FD_MEM_DRAW, addr, (hsize_t)lt_key->nbytes) < 0) HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, H5B_INS_ERROR, "unable to free chunk"); /* Mark keys as unchanged */ *lt_key_changed = false; *rt_key_changed = false; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_remove() */ /*------------------------------------------------------------------------- * Function: H5D__btree_decode_key * * Purpose: Decodes a raw key into a native key for the B-tree * * Return: SUCCEED/FAIL *------------------------------------------------------------------------- */ static herr_t H5D__btree_decode_key(const H5B_shared_t *shared, const uint8_t *raw, void *_key) { const H5O_layout_chunk_t *layout; /* Chunk layout description */ H5D_btree_key_t *key = (H5D_btree_key_t *)_key; /* Pointer to decoded key */ hsize_t tmp_offset; /* Temporary coordinate offset, from file */ herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE assert(shared); assert(raw); assert(key); layout = (const H5O_layout_chunk_t *)shared->udata; assert(layout); if (layout->ndims > H5O_LAYOUT_NDIMS) HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "bad number of dimensions"); UINT32DECODE(raw, key->nbytes); UINT32DECODE(raw, key->filter_mask); for (unsigned u = 0; u < layout->ndims; u++) { if (layout->dim[u] == 0) HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", u); /* Retrieve coordinate offset */ UINT64DECODE(raw, tmp_offset); if (0 != (tmp_offset % layout->dim[u])) HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "bad coordinate offset"); /* Convert to a scaled offset */ key->scaled[u] = tmp_offset / layout->dim[u]; } done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_decode_key() */ /*------------------------------------------------------------------------- * Function: H5D__btree_encode_key * * Purpose: Encode a key from native format to raw format. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_encode_key(const H5B_shared_t *shared, uint8_t *raw, const void *_key) { const H5O_layout_chunk_t *layout; /* Chunk layout description */ const H5D_btree_key_t *key = (const H5D_btree_key_t *)_key; hsize_t tmp_offset; /* Temporary coordinate offset, from file */ unsigned u; /* Local index variable */ FUNC_ENTER_PACKAGE_NOERR /* check args */ assert(shared); assert(raw); assert(key); layout = (const H5O_layout_chunk_t *)shared->udata; assert(layout); assert(layout->ndims > 0 && layout->ndims <= H5O_LAYOUT_NDIMS); /* encode */ UINT32ENCODE(raw, key->nbytes); UINT32ENCODE(raw, key->filter_mask); for (u = 0; u < layout->ndims; u++) { /* Compute coordinate offset from scaled offset */ tmp_offset = key->scaled[u] * layout->dim[u]; UINT64ENCODE(raw, tmp_offset); } /* end for */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__btree_encode_key() */ /*------------------------------------------------------------------------- * Function: H5D__btree_debug_key * * Purpose: Prints a key. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_debug_key(FILE *stream, int indent, int fwidth, const void *_key, const void *_udata) { const H5D_btree_key_t *key = (const H5D_btree_key_t *)_key; const H5D_btree_dbg_t *udata = (const H5D_btree_dbg_t *)_udata; unsigned u; FUNC_ENTER_PACKAGE_NOERR assert(key); fprintf(stream, "%*s%-*s %u bytes\n", indent, "", fwidth, "Chunk size:", (unsigned)key->nbytes); fprintf(stream, "%*s%-*s 0x%08x\n", indent, "", fwidth, "Filter mask:", key->filter_mask); fprintf(stream, "%*s%-*s {", indent, "", fwidth, "Logical offset:"); for (u = 0; u < udata->ndims; u++) fprintf(stream, "%s%" PRIuHSIZE, u ? ", " : "", (key->scaled[u] * udata->common.layout->dim[u])); fputs("}\n", stream); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__btree_debug_key() */ /*------------------------------------------------------------------------- * Function: H5D__btree_shared_free * * Purpose: Free "local" B-tree shared info * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_shared_free(void *_shared) { H5B_shared_t *shared = (H5B_shared_t *)_shared; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Free the chunk layout information */ shared->udata = H5FL_FREE(H5O_layout_chunk_t, shared->udata); /* Chain up to the generic B-tree shared info free routine */ if (H5B_shared_free(shared) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't free shared B-tree info"); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_shared_free() */ /*------------------------------------------------------------------------- * Function: H5D__btree_shared_create * * Purpose: Create & initialize B-tree shared info * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_shared_create(const H5F_t *f, H5O_storage_chunk_t *store, const H5O_layout_chunk_t *layout) { H5B_shared_t *shared; /* Shared B-tree node info */ H5O_layout_chunk_t *my_layout = NULL; /* Pointer to copy of layout info */ size_t sizeof_rkey; /* Size of raw (disk) key */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Set the raw key size */ sizeof_rkey = 4 + /*storage size */ 4 + /*filter mask */ layout->ndims * 8; /*dimension indices */ /* Allocate & initialize global info for the shared structure */ if (NULL == (shared = H5B_shared_new(f, H5B_BTREE, sizeof_rkey))) HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "memory allocation failed for shared B-tree info"); /* Set up the "local" information for this dataset's chunks */ if (NULL == (my_layout = H5FL_MALLOC(H5O_layout_chunk_t))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk layout"); H5MM_memcpy(my_layout, layout, sizeof(H5O_layout_chunk_t)); shared->udata = my_layout; /* Make shared B-tree info reference counted */ if (NULL == (store->u.btree.shared = H5UC_create(shared, H5D__btree_shared_free))) HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "can't create ref-count wrapper for shared B-tree info"); done: if (ret_value < 0) if (my_layout) my_layout = H5FL_FREE(H5O_layout_chunk_t, my_layout); FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_shared_create() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_init * * Purpose: Initialize the indexing information for a dataset. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t H5_ATTR_UNUSED *space, haddr_t dset_ohdr_addr) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Check args */ assert(idx_info); assert(idx_info->f); assert(idx_info->pline); assert(idx_info->layout); assert(idx_info->storage); assert(H5_addr_defined(dset_ohdr_addr)); idx_info->storage->u.btree.dset_ohdr_addr = dset_ohdr_addr; /* Allocate the shared structure */ if (H5D__btree_shared_create(idx_info->f, idx_info->storage, idx_info->layout) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create wrapper for shared B-tree info"); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_idx_init() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_create * * Purpose: Creates a new indexed-storage B-tree and initializes the * layout struct with information about the storage. The * struct should be immediately written to the object header. * * This function must be called before passing LAYOUT to any * of the other indexed storage functions! * * Return: Non-negative on success (with the LAYOUT argument * initialized and ready to write to an object header). * Negative on failure. * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_create(const H5D_chk_idx_info_t *idx_info) { H5D_chunk_common_ud_t udata; /* User data for B-tree callback */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Check args */ assert(idx_info); assert(idx_info->f); assert(idx_info->pline); assert(idx_info->layout); assert(idx_info->storage); assert(!H5_addr_defined(idx_info->storage->idx_addr)); /* Initialize "user" data for B-tree callbacks, etc. */ udata.layout = idx_info->layout; udata.storage = idx_info->storage; /* Create the v1 B-tree for the chunk index */ if (H5B_create(idx_info->f, H5B_BTREE, &udata, &(idx_info->storage->idx_addr) /*out*/) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create B-tree"); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_idx_create() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_open * * Purpose: Opens an existing B-tree. Currently a no-op. * * Return: SUCCEED (can't fail) * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_open(const H5D_chk_idx_info_t H5_ATTR_UNUSED *idx_info) { FUNC_ENTER_PACKAGE_NOERR /* NO OP */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__btree_idx_open() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_close * * Purpose: Closes an existing B-tree. Currently a no-op. * * Return: SUCCEED (can't fail) * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_close(const H5D_chk_idx_info_t H5_ATTR_UNUSED *idx_info) { FUNC_ENTER_PACKAGE_NOERR /* NO OP */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__btree_idx_close() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_is_open * * Purpose: Query if the index is opened or not * * Return: SUCCEED (can't fail) * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_is_open(const H5D_chk_idx_info_t *idx_info, bool *is_open) { FUNC_ENTER_PACKAGE_NOERR assert(idx_info); assert(idx_info->storage); assert(H5D_CHUNK_IDX_BTREE == idx_info->storage->idx_type); assert(is_open); *is_open = H5D_BTREE_IDX_IS_OPEN(idx_info); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__btree_idx_is_open() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_is_space_alloc * * Purpose: Query if space is allocated for index method * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static bool H5D__btree_idx_is_space_alloc(const H5O_storage_chunk_t *storage) { FUNC_ENTER_PACKAGE_NOERR /* Check args */ assert(storage); FUNC_LEAVE_NOAPI((bool)H5_addr_defined(storage->idx_addr)) } /* end H5D__btree_idx_is_space_alloc() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_insert * * Purpose: Insert chunk entry into the indexing structure. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata, const H5D_t H5_ATTR_UNUSED *dset) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE assert(idx_info); assert(idx_info->f); assert(idx_info->pline); assert(idx_info->layout); assert(idx_info->storage); assert(H5_addr_defined(idx_info->storage->idx_addr)); assert(udata); /* * Create the chunk it if it doesn't exist, or reallocate the chunk if * its size changed. */ if (H5B_insert(idx_info->f, H5B_BTREE, idx_info->storage->idx_addr, udata) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to allocate chunk"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5D__btree_idx_insert() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_get_addr * * Purpose: Get the file address of a chunk if file space has been * assigned. Save the retrieved information in the udata * supplied. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata) { bool found; /* Whether chunk was found */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE assert(idx_info); assert(idx_info->f); assert(idx_info->pline); assert(idx_info->layout); assert(idx_info->layout->ndims > 0); assert(idx_info->storage); assert(H5_addr_defined(idx_info->storage->idx_addr)); assert(udata); /* Go get the chunk information from the B-tree */ found = false; if (H5B_find(idx_info->f, H5B_BTREE, idx_info->storage->idx_addr, &found, udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTFIND, FAIL, "can't check for chunk in B-tree"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5D__btree_idx_get_addr() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_load_metadata * * Purpose: Load additional chunk index metadata beyond the chunk index * itself. Currently a no-op. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_load_metadata(const H5D_chk_idx_info_t H5_ATTR_UNUSED *idx_info) { FUNC_ENTER_PACKAGE_NOERR /* NO OP */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__btree_idx_load_metadata() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_iterate_cb * * Purpose: Translate the B-tree specific chunk record into a generic * form and make the callback to the generic chunk callback * routine. * * Return: Success: Non-negative * Failure: Negative * *------------------------------------------------------------------------- */ static int H5D__btree_idx_iterate_cb(H5F_t H5_ATTR_UNUSED *f, const void *_lt_key, haddr_t addr, const void H5_ATTR_UNUSED *_rt_key, void *_udata) { H5D_btree_it_ud_t *udata = (H5D_btree_it_ud_t *)_udata; /* User data */ const H5D_btree_key_t *lt_key = (const H5D_btree_key_t *)_lt_key; /* B-tree key for chunk */ H5D_chunk_rec_t chunk_rec; /* Generic chunk record for callback */ int ret_value = -1; /* Return value */ FUNC_ENTER_PACKAGE_NOERR /* Sanity check for memcpy() */ HDcompile_assert(offsetof(H5D_chunk_rec_t, nbytes) == offsetof(H5D_btree_key_t, nbytes)); HDcompile_assert(sizeof(chunk_rec.nbytes) == sizeof(lt_key->nbytes)); HDcompile_assert(offsetof(H5D_chunk_rec_t, scaled) == offsetof(H5D_btree_key_t, scaled)); HDcompile_assert(sizeof(chunk_rec.scaled) == sizeof(lt_key->scaled)); HDcompile_assert(offsetof(H5D_chunk_rec_t, filter_mask) == offsetof(H5D_btree_key_t, filter_mask)); HDcompile_assert(sizeof(chunk_rec.filter_mask) == sizeof(lt_key->filter_mask)); /* Compose generic chunk record for callback */ H5MM_memcpy(&chunk_rec, lt_key, sizeof(*lt_key)); chunk_rec.chunk_addr = addr; /* Make "generic chunk" callback */ if ((ret_value = (udata->cb)(&chunk_rec, udata->udata)) < 0) HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback"); FUNC_LEAVE_NOAPI(ret_value) } /* H5D__btree_idx_iterate_cb() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_iterate * * Purpose: Iterate over the chunks in an index, making a callback * for each one. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static int H5D__btree_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb, void *chunk_udata) { H5D_btree_it_ud_t udata; /* User data for B-tree iterator callback */ int ret_value = -1; /* Return value */ FUNC_ENTER_PACKAGE_NOERR assert(idx_info); assert(idx_info->f); assert(idx_info->pline); assert(idx_info->layout); assert(idx_info->storage); assert(H5_addr_defined(idx_info->storage->idx_addr)); assert(chunk_cb); assert(chunk_udata); /* Initialize userdata */ memset(&udata, 0, sizeof udata); udata.common.layout = idx_info->layout; udata.common.storage = idx_info->storage; udata.cb = chunk_cb; udata.udata = chunk_udata; /* Iterate over existing chunks */ if ((ret_value = H5B_iterate(idx_info->f, H5B_BTREE, idx_info->storage->idx_addr, H5D__btree_idx_iterate_cb, &udata)) < 0) HERROR(H5E_DATASET, H5E_BADITER, "unable to iterate over chunk B-tree"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_idx_iterate() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_remove * * Purpose: Remove chunk from index. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE assert(idx_info); assert(idx_info->f); assert(idx_info->pline); assert(idx_info->layout); assert(idx_info->storage); assert(H5_addr_defined(idx_info->storage->idx_addr)); assert(udata); /* Remove the chunk from the v1 B-tree index and release the space for the * chunk (in the B-tree callback). */ if (H5B_remove(idx_info->f, H5B_BTREE, idx_info->storage->idx_addr, udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to remove chunk entry"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5D__btree_idx_remove() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_delete * * Purpose: Delete index and raw data storage for entire dataset * (i.e. all chunks) * * Return: Success: Non-negative * Failure: negative * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_delete(const H5D_chk_idx_info_t *idx_info) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity checks */ assert(idx_info); assert(idx_info->f); assert(idx_info->pline); assert(idx_info->layout); assert(idx_info->storage); /* Check if the index data structure has been allocated */ if (H5_addr_defined(idx_info->storage->idx_addr)) { H5O_storage_chunk_t tmp_storage; /* Local copy of storage info */ H5D_chunk_common_ud_t udata; /* User data for B-tree operations */ /* Set up temporary chunked storage info */ tmp_storage = *idx_info->storage; /* Set up the shared structure */ if (H5D__btree_shared_create(idx_info->f, &tmp_storage, idx_info->layout) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't create wrapper for shared B-tree info"); /* Set up B-tree user data */ memset(&udata, 0, sizeof udata); udata.layout = idx_info->layout; udata.storage = &tmp_storage; /* Delete entire B-tree */ if (H5B_delete(idx_info->f, H5B_BTREE, tmp_storage.idx_addr, &udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "unable to delete chunk B-tree"); /* Release the shared B-tree page */ if (NULL == tmp_storage.u.btree.shared) HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "ref-counted page nil"); if (H5UC_DEC(tmp_storage.u.btree.shared) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to decrement ref-counted page"); } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_idx_delete() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_copy_setup * * Purpose: Set up any necessary information for copying chunks * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src, const H5D_chk_idx_info_t *idx_info_dst) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE_TAG(H5AC__COPIED_TAG) assert(idx_info_src); assert(idx_info_src->f); assert(idx_info_src->pline); assert(idx_info_src->layout); assert(idx_info_src->storage); assert(idx_info_dst); assert(idx_info_dst->f); assert(idx_info_dst->pline); assert(idx_info_dst->layout); assert(idx_info_dst->storage); assert(!H5_addr_defined(idx_info_dst->storage->idx_addr)); /* Create shared B-tree info for each file */ if (H5D__btree_shared_create(idx_info_src->f, idx_info_src->storage, idx_info_src->layout) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create wrapper for source shared B-tree info"); if (H5D__btree_shared_create(idx_info_dst->f, idx_info_dst->storage, idx_info_dst->layout) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create wrapper for destination shared B-tree info"); /* Create the root of the B-tree that describes chunked storage in the dest. file */ if (H5D__btree_idx_create(idx_info_dst) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to initialize chunked storage"); assert(H5_addr_defined(idx_info_dst->storage->idx_addr)); done: FUNC_LEAVE_NOAPI_TAG(ret_value) } /* end H5D__btree_idx_copy_setup() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_copy_shutdown * * Purpose: Shutdown any information from copying chunks * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_copy_shutdown(H5O_storage_chunk_t *storage_src, H5O_storage_chunk_t *storage_dst) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE assert(storage_src); assert(storage_dst); /* Decrement refcount on shared B-tree info */ if (H5UC_DEC(storage_src->u.btree.shared) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "unable to decrement ref-counted page"); if (H5UC_DEC(storage_dst->u.btree.shared) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTDEC, FAIL, "unable to decrement ref-counted page"); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_idx_copy_shutdown() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_size * * Purpose: Retrieve the amount of index storage for chunked dataset * * Return: Success: Non-negative * Failure: negative * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size) { H5D_chunk_common_ud_t udata; /* User-data for loading B-tree nodes */ H5B_info_t bt_info; /* B-tree info */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Check args */ assert(idx_info); assert(idx_info->f); assert(idx_info->pline); assert(idx_info->layout); assert(idx_info->storage); assert(index_size); /* Initialize B-tree node user-data */ memset(&udata, 0, sizeof udata); udata.layout = idx_info->layout; udata.storage = idx_info->storage; /* Get metadata information for B-tree */ if (H5B_get_info(idx_info->f, H5B_BTREE, idx_info->storage->idx_addr, &bt_info, NULL, &udata) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to iterate over chunk B-tree"); /* Set the size of the B-tree */ *index_size = bt_info.size; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_idx_size() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_reset * * Purpose: Reset indexing information. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_reset(H5O_storage_chunk_t *storage, bool reset_addr) { FUNC_ENTER_PACKAGE_NOERR assert(storage); /* Reset index info */ if (reset_addr) storage->idx_addr = HADDR_UNDEF; storage->u.btree.shared = NULL; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__btree_idx_reset() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_dump * * Purpose: Dump indexing information to a stream. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream) { FUNC_ENTER_PACKAGE_NOERR assert(storage); assert(stream); fprintf(stream, " Address: %" PRIuHADDR "\n", storage->idx_addr); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__btree_idx_dump() */ /*------------------------------------------------------------------------- * Function: H5D__btree_idx_dest * * Purpose: Release indexing information in memory. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5D__btree_idx_dest(const H5D_chk_idx_info_t *idx_info) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE assert(idx_info); assert(idx_info->f); assert(idx_info->pline); assert(idx_info->layout); assert(idx_info->storage); /* Free the raw B-tree node buffer */ if (NULL == idx_info->storage->u.btree.shared) HGOTO_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "ref-counted page nil"); if (H5UC_DEC(idx_info->storage->u.btree.shared) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "unable to decrement ref-counted page"); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree_idx_dest() */ /*------------------------------------------------------------------------- * Function: H5D_btree_debug * * Purpose: Debugs a B-tree node for indexed raw data storage. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5D_btree_debug(H5F_t *f, haddr_t addr, FILE *stream, int indent, int fwidth, unsigned ndims, const uint32_t *dim) { H5D_btree_dbg_t udata; /* User data for B-tree callback */ H5O_storage_chunk_t storage; /* Storage information for B-tree callback */ H5O_layout_chunk_t layout; /* Layout information for B-tree callback */ bool shared_init = false; /* Whether B-tree shared info is initialized */ unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Reset "fake" storage info */ memset(&storage, 0, sizeof(storage)); storage.idx_type = H5D_CHUNK_IDX_BTREE; /* Reset "fake" layout info */ memset(&layout, 0, sizeof(layout)); layout.ndims = ndims; for (u = 0; u < ndims; u++) layout.dim[u] = dim[u]; /* Allocate the shared structure */ if (H5D__btree_shared_create(f, &storage, &layout) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't create wrapper for shared B-tree info"); shared_init = true; /* Set up user data for callback */ udata.common.layout = &layout; udata.common.storage = &storage; udata.common.scaled = NULL; udata.ndims = ndims; /* Dump the records for the B-tree */ (void)H5B_debug(f, addr, stream, indent, fwidth, H5B_BTREE, &udata); done: if (shared_init) { /* Free the raw B-tree node buffer */ if (NULL == storage.u.btree.shared) HDONE_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "ref-counted shared info nil"); else if (H5UC_DEC(storage.u.btree.shared) < 0) HDONE_ERROR(H5E_IO, H5E_CANTFREE, FAIL, "unable to decrement ref-counted shared info"); } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_btree_debug() */