/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * Purpose: v2 B-tree indexing for chunked datasets with > 1 unlimited dimensions. * Each dataset chunk in the b-tree is identified by its dimensional offset. * */ /****************/ /* Module Setup */ /****************/ #include "H5Dmodule.h" /* This source code file is part of the H5D module */ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Dpkg.h" /* Datasets */ #include "H5FLprivate.h" /* Free Lists */ #include "H5MFprivate.h" /* File space management */ #include "H5MMprivate.h" /* Memory management */ #include "H5VMprivate.h" /* Vector and array functions */ /****************/ /* Local Macros */ /****************/ /******************/ /* Local Typedefs */ /******************/ /* User data for creating callback context */ typedef struct H5D_bt2_ctx_ud_t { const H5F_t *f; /* Pointer to file info */ uint32_t chunk_size; /* Size of chunk (bytes; for filtered object) */ unsigned ndims; /* Number of dimensions */ uint32_t *dim; /* Size of chunk in elements */ } H5D_bt2_ctx_ud_t; /* The callback context */ typedef struct H5D_bt2_ctx_t { uint32_t chunk_size; /* Size of chunk (bytes; constant for unfiltered object) */ size_t sizeof_addr; /* Size of file addresses in the file (bytes) */ size_t chunk_size_len; /* Size of chunk sizes in the file (bytes) */ unsigned ndims; /* Number of dimensions in chunk */ uint32_t *dim; /* Size of chunk in elements */ } H5D_bt2_ctx_t; /* Callback info for iteration over chunks in v2 B-tree */ typedef struct H5D_bt2_it_ud_t { H5D_chunk_cb_func_t cb; /* Callback routine for the chunk */ void *udata; /* User data for the chunk's callback routine */ } H5D_bt2_it_ud_t; /* User data for compare callback */ typedef struct H5D_bt2_ud_t { H5D_chunk_rec_t rec; /* The record to search for */ unsigned ndims; /* Number of dimensions for the chunked dataset */ } H5D_bt2_ud_t; /********************/ /* Local Prototypes */ /********************/ /* Shared v2 B-tree methods for indexing filtered and non-filtered chunked datasets */ static void *H5D__bt2_crt_context(void *udata); static herr_t H5D__bt2_dst_context(void *ctx); static herr_t H5D__bt2_store(void *native, const void *udata); static herr_t H5D__bt2_compare(const void *rec1, const void *rec2, int *result); /* v2 B-tree class for indexing non-filtered chunked datasets */ static herr_t H5D__bt2_unfilt_encode(uint8_t *raw, const void *native, void *ctx); static herr_t H5D__bt2_unfilt_decode(const uint8_t *raw, void *native, void *ctx); static herr_t H5D__bt2_unfilt_debug(FILE *stream, int indent, int fwidth, const void *record, const void *u_ctx); /* v2 B-tree class for indexing filtered chunked datasets */ static herr_t H5D__bt2_filt_encode(uint8_t *raw, const void *native, void *ctx); static herr_t H5D__bt2_filt_decode(const uint8_t *raw, void *native, void *ctx); static herr_t H5D__bt2_filt_debug(FILE *stream, int indent, int fwidth, const void *record, const void *u_ctx); /* Helper routine */ static herr_t H5D__bt2_idx_open(const H5D_chk_idx_info_t *idx_info); static herr_t H5D__btree2_idx_depend(const H5D_chk_idx_info_t *idx_info); /* Callback for H5B2_iterate() which is called in H5D__bt2_idx_iterate() */ static int H5D__bt2_idx_iterate_cb(const void *_record, void *_udata); /* Callback for H5B2_find() which is called in H5D__bt2_idx_get_addr() */ static herr_t H5D__bt2_found_cb(const void *nrecord, void *op_data); /* * Callback for H5B2_remove() and H5B2_delete() which is called * in H5D__bt2_idx_remove() and H5D__bt2_idx_delete(). */ static herr_t H5D__bt2_remove_cb(const void *nrecord, void *_udata); /* Callback for H5B2_modify() which is called in H5D__bt2_idx_insert() */ static herr_t H5D__bt2_mod_cb(void *_record, void *_op_data, hbool_t *changed); /* Chunked layout indexing callbacks for v2 B-tree indexing */ static herr_t H5D__bt2_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t *space, haddr_t dset_ohdr_addr); static herr_t H5D__bt2_idx_create(const H5D_chk_idx_info_t *idx_info); static hbool_t H5D__bt2_idx_is_space_alloc(const H5O_storage_chunk_t *storage); static herr_t H5D__bt2_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata, const H5D_t *dset); static herr_t H5D__bt2_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata); static int H5D__bt2_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb, void *chunk_udata); static herr_t H5D__bt2_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata); static herr_t H5D__bt2_idx_delete(const H5D_chk_idx_info_t *idx_info); static herr_t H5D__bt2_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__bt2_idx_copy_shutdown(H5O_storage_chunk_t *storage_src, H5O_storage_chunk_t *storage_dst); static herr_t H5D__bt2_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *size); static herr_t H5D__bt2_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr); static herr_t H5D__bt2_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream); static herr_t H5D__bt2_idx_dest(const H5D_chk_idx_info_t *idx_info); /*********************/ /* Package Variables */ /*********************/ /* Chunked dataset I/O ops for v2 B-tree indexing */ const H5D_chunk_ops_t H5D_COPS_BT2[1] = {{ TRUE, /* Fixed array indices support SWMR access */ H5D__bt2_idx_init, /* init */ H5D__bt2_idx_create, /* create */ H5D__bt2_idx_is_space_alloc, /* is_space_alloc */ H5D__bt2_idx_insert, /* insert */ H5D__bt2_idx_get_addr, /* get_addr */ NULL, /* resize */ H5D__bt2_idx_iterate, /* iterate */ H5D__bt2_idx_remove, /* remove */ H5D__bt2_idx_delete, /* delete */ H5D__bt2_idx_copy_setup, /* copy_setup */ H5D__bt2_idx_copy_shutdown, /* copy_shutdown */ H5D__bt2_idx_size, /* size */ H5D__bt2_idx_reset, /* reset */ H5D__bt2_idx_dump, /* dump */ H5D__bt2_idx_dest, /* destroy */ H5D__bt2_idx_dest /* close (same as destroy) */ }}; /*****************************/ /* Library Private Variables */ /*****************************/ /* v2 B-tree class for indexing non-filtered chunked datasets */ const H5B2_class_t H5D_BT2[1] = {{ /* B-tree class information */ H5B2_CDSET_ID, /* Type of B-tree */ "H5B2_CDSET_ID", /* Name of B-tree class */ sizeof(H5D_chunk_rec_t), /* Size of native record */ H5D__bt2_crt_context, /* Create client callback context */ H5D__bt2_dst_context, /* Destroy client callback context */ H5D__bt2_store, /* Record storage callback */ H5D__bt2_compare, /* Record comparison callback */ H5D__bt2_unfilt_encode, /* Record encoding callback */ H5D__bt2_unfilt_decode, /* Record decoding callback */ H5D__bt2_unfilt_debug /* Record debugging callback */ }}; /* v2 B-tree class for indexing filtered chunked datasets */ const H5B2_class_t H5D_BT2_FILT[1] = {{ /* B-tree class information */ H5B2_CDSET_FILT_ID, /* Type of B-tree */ "H5B2_CDSET_FILT_ID", /* Name of B-tree class */ sizeof(H5D_chunk_rec_t), /* Size of native record */ H5D__bt2_crt_context, /* Create client callback context */ H5D__bt2_dst_context, /* Destroy client callback context */ H5D__bt2_store, /* Record storage callback */ H5D__bt2_compare, /* Record comparison callback */ H5D__bt2_filt_encode, /* Record encoding callback */ H5D__bt2_filt_decode, /* Record decoding callback */ H5D__bt2_filt_debug /* Record debugging callback */ }}; /*******************/ /* Local Variables */ /*******************/ /* Declare a free list to manage the H5D_bt2_ctx_t struct */ H5FL_DEFINE_STATIC(H5D_bt2_ctx_t); /* Declare a free list to manage the page elements */ H5FL_ARR_DEFINE_STATIC(uint32_t, H5O_LAYOUT_NDIMS); /*------------------------------------------------------------------------- * Function: H5D__bt2_crt_context * * Purpose: Create client callback context * * Return: Success: non-NULL * Failure: NULL * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static void * H5D__bt2_crt_context(void *_udata) { H5D_bt2_ctx_ud_t *udata = (H5D_bt2_ctx_ud_t *)_udata; /* User data for building callback context */ H5D_bt2_ctx_t *ctx; /* Callback context structure */ uint32_t *my_dim = NULL; /* Pointer to copy of chunk dimension size */ void *ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC /* Sanity check */ HDassert(udata); HDassert(udata->f); HDassert(udata->ndims > 0 && udata->ndims < H5O_LAYOUT_NDIMS); /* Allocate callback context */ if(NULL == (ctx = H5FL_MALLOC(H5D_bt2_ctx_t))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate callback context") /* Determine the size of addresses and set the chunk size and # of dimensions for the dataset */ ctx->sizeof_addr = H5F_SIZEOF_ADDR(udata->f); ctx->chunk_size = udata->chunk_size; ctx->ndims = udata->ndims; /* Set up the "local" information for this dataset's chunk dimension sizes */ if(NULL == (my_dim = (uint32_t *)H5FL_ARR_MALLOC(uint32_t, H5O_LAYOUT_NDIMS))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate chunk dims") H5MM_memcpy(my_dim, udata->dim, H5O_LAYOUT_NDIMS * sizeof(uint32_t)); ctx->dim = my_dim; /* * Compute the size required for encoding the size of a chunk, * allowing for an extra byte, in case the filter makes the chunk larger. */ ctx->chunk_size_len = 1 + ((H5VM_log2_gen((uint64_t)udata->chunk_size) + 8) / 8); if(ctx->chunk_size_len > 8) ctx->chunk_size_len = 8; /* Set return value */ ret_value = ctx; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5D__bt2_crt_context() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_dst_context * * Purpose: Destroy client callback context * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_dst_context(void *_ctx) { H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */ FUNC_ENTER_STATIC_NOERR /* Sanity check */ HDassert(ctx); /* Free array for chunk dimension sizes */ if(ctx->dim) H5FL_ARR_FREE(uint32_t, ctx->dim); /* Release callback context */ ctx = H5FL_FREE(H5D_bt2_ctx_t, ctx); FUNC_LEAVE_NOAPI(SUCCEED) } /* H5D__bt2_dst_context() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_store * * Purpose: Store native information into record for v2 B-tree * (non-filtered) * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_store(void *record, const void *_udata) { const H5D_bt2_ud_t *udata = (const H5D_bt2_ud_t *)_udata; /* User data */ FUNC_ENTER_STATIC_NOERR *(H5D_chunk_rec_t *)record = udata->rec; FUNC_LEAVE_NOAPI(SUCCEED) } /* H5D__bt2_store() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_compare * * Purpose: Compare two native information records, according to some key * (non-filtered) * * Return: <0 if rec1 < rec2 * =0 if rec1 == rec2 * >0 if rec1 > rec2 * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_compare(const void *_udata, const void *_rec2, int *result) { const H5D_bt2_ud_t *udata = (const H5D_bt2_ud_t *)_udata; /* User data */ const H5D_chunk_rec_t *rec1 = &(udata->rec); /* The search record */ const H5D_chunk_rec_t *rec2 = (const H5D_chunk_rec_t *)_rec2; /* The native record */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC_NOERR /* Sanity checks */ HDassert(rec1); HDassert(rec2); /* Compare the offsets but ignore the other fields */ *result = H5VM_vector_cmp_u(udata->ndims, rec1->scaled, rec2->scaled); FUNC_LEAVE_NOAPI(ret_value) } /* H5D__bt2_compare() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_unfilt_encode * * Purpose: Encode native information into raw form for storing on disk * (non-filtered) * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_unfilt_encode(uint8_t *raw, const void *_record, void *_ctx) { H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */ const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */ unsigned u; /* Local index variable */ FUNC_ENTER_STATIC_NOERR /* Sanity check */ HDassert(ctx); /* Encode the record's fields */ H5F_addr_encode_len(ctx->sizeof_addr, &raw, record->chunk_addr); /* (Don't encode the chunk size & filter mask for non-filtered B-tree records) */ for(u = 0; u < ctx->ndims; u++) UINT64ENCODE(raw, record->scaled[u]); FUNC_LEAVE_NOAPI(SUCCEED) } /* H5D__bt2_unfilt_encode() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_unfilt_decode * * Purpose: Decode raw disk form of record into native form * (non-filtered) * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_unfilt_decode(const uint8_t *raw, void *_record, void *_ctx) { H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */ H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* The native record */ unsigned u; /* Local index variable */ FUNC_ENTER_STATIC_NOERR /* Sanity check */ HDassert(ctx); /* Decode the record's fields */ H5F_addr_decode_len(ctx->sizeof_addr, &raw, &record->chunk_addr); record->nbytes = ctx->chunk_size; record->filter_mask = 0; for(u = 0; u < ctx->ndims; u++) UINT64DECODE(raw, record->scaled[u]); FUNC_LEAVE_NOAPI(SUCCEED) } /* H5D__bt2_unfilt_decode() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_unfilt_debug * * Purpose: Debug native form of record (non-filtered) * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_unfilt_debug(FILE *stream, int indent, int fwidth, const void *_record, const void *_ctx) { const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */ const H5D_bt2_ctx_t *ctx = (const H5D_bt2_ctx_t *)_ctx; /* Callback context */ unsigned u; /* Local index variable */ FUNC_ENTER_STATIC_NOERR /* Sanity checks */ HDassert(record); HDassert(ctx->chunk_size == record->nbytes); HDassert(0 == record->filter_mask); HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth, "Chunk address:", record->chunk_addr); HDfprintf(stream, "%*s%-*s {", indent, "", fwidth, "Logical offset:"); for(u = 0; u < ctx->ndims; u++) HDfprintf(stream, "%s%Hd", u?", ":"", record->scaled[u] * ctx->dim[u]); HDfputs("}\n", stream); FUNC_LEAVE_NOAPI(SUCCEED) } /* H5D__bt2_unfilt_debug() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_filt_encode * * Purpose: Encode native information into raw form for storing on disk * (filtered) * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_filt_encode(uint8_t *raw, const void *_record, void *_ctx) { H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */ const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */ unsigned u; /* Local index variable */ FUNC_ENTER_STATIC_NOERR /* Sanity check */ HDassert(ctx); HDassert(record); HDassert(H5F_addr_defined(record->chunk_addr)); HDassert(0 != record->nbytes); /* Encode the record's fields */ H5F_addr_encode_len(ctx->sizeof_addr, &raw, record->chunk_addr); UINT64ENCODE_VAR(raw, record->nbytes, ctx->chunk_size_len); UINT32ENCODE(raw, record->filter_mask); for(u = 0; u < ctx->ndims; u++) UINT64ENCODE(raw, record->scaled[u]); FUNC_LEAVE_NOAPI(SUCCEED) } /* H5D__bt2_filt_encode() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_filt_decode * * Purpose: Decode raw disk form of record into native form * (filtered) * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_filt_decode(const uint8_t *raw, void *_record, void *_ctx) { H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */ H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* The native record */ unsigned u; /* Local index variable */ FUNC_ENTER_STATIC_NOERR /* Sanity check */ HDassert(ctx); HDassert(record); /* Decode the record's fields */ H5F_addr_decode_len(ctx->sizeof_addr, &raw, &record->chunk_addr); UINT64DECODE_VAR(raw, record->nbytes, ctx->chunk_size_len); UINT32DECODE(raw, record->filter_mask); for(u = 0; u < ctx->ndims; u++) UINT64DECODE(raw, record->scaled[u]); /* Sanity checks */ HDassert(H5F_addr_defined(record->chunk_addr)); HDassert(0 != record->nbytes); FUNC_LEAVE_NOAPI(SUCCEED) } /* H5D__bt2_filt_decode() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_filt_debug * * Purpose: Debug native form of record (filtered) * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_filt_debug(FILE *stream, int indent, int fwidth, const void *_record, const void *_ctx) { const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */ const H5D_bt2_ctx_t *ctx = (const H5D_bt2_ctx_t *)_ctx; /* Callback context */ unsigned u; /* Local index variable */ FUNC_ENTER_STATIC_NOERR /* Sanity checks */ HDassert(record); HDassert(H5F_addr_defined(record->chunk_addr)); HDassert(0 != record->nbytes); HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth, "Chunk address:", record->chunk_addr); HDfprintf(stream, "%*s%-*s %u bytes\n", indent, "", fwidth, "Chunk size:", (unsigned)record->nbytes); HDfprintf(stream, "%*s%-*s 0x%08x\n", indent, "", fwidth, "Filter mask:", record->filter_mask); HDfprintf(stream, "%*s%-*s {", indent, "", fwidth, "Logical offset:"); for(u = 0; u < ctx->ndims; u++) HDfprintf(stream, "%s%Hd", u?", ":"", record->scaled[u] * ctx->dim[u]); HDfputs("}\n", stream); FUNC_LEAVE_NOAPI(SUCCEED) } /* H5D__bt2_filt_debug() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_init * * Purpose: Initialize the indexing information for a dataset. * * Return: Non-negative on success/Negative on failure * * Programmer: Neil Fortner * Wednesday, May 23, 2012 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_init(const H5D_chk_idx_info_t H5_ATTR_UNUSED *idx_info, const H5S_t H5_ATTR_UNUSED *space, haddr_t dset_ohdr_addr) { FUNC_ENTER_STATIC_NOERR /* Check args */ HDassert(H5F_addr_defined(dset_ohdr_addr)); idx_info->storage->u.btree2.dset_ohdr_addr = dset_ohdr_addr; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__bt2_idx_init() */ /*------------------------------------------------------------------------- * Function: H5D__btree2_idx_depend * * Purpose: Create flush dependency between v2 B-tree and dataset's * object header. * * Return: Success: non-negative * Failure: negative * * Programmer: Quincey Koziol * Friday, December 18, 2015 * *------------------------------------------------------------------------- */ static herr_t H5D__btree2_idx_depend(const H5D_chk_idx_info_t *idx_info) { H5O_t *oh = NULL; /* Object header */ H5O_loc_t oloc; /* Temporary object header location for dataset */ H5AC_proxy_entry_t *oh_proxy; /* Dataset's object header proxy */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Check args */ HDassert(idx_info); HDassert(idx_info->f); HDassert(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE); HDassert(idx_info->pline); HDassert(idx_info->layout); HDassert(H5D_CHUNK_IDX_BT2 == idx_info->layout->idx_type); HDassert(idx_info->storage); HDassert(H5D_CHUNK_IDX_BT2 == idx_info->storage->idx_type); HDassert(H5F_addr_defined(idx_info->storage->idx_addr)); HDassert(idx_info->storage->u.btree2.bt2); /* Set up object header location for dataset */ H5O_loc_reset(&oloc); oloc.file = idx_info->f; oloc.addr = idx_info->storage->u.btree.dset_ohdr_addr; /* Get header */ if(NULL == (oh = H5O_protect(&oloc, H5AC__READ_ONLY_FLAG, TRUE))) HGOTO_ERROR(H5E_DATASET, H5E_CANTPROTECT, FAIL, "unable to protect object header") /* Retrieve the dataset's object header proxy */ if(NULL == (oh_proxy = H5O_get_proxy(oh))) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get dataset object header proxy") /* Make the v2 B-tree a child flush dependency of the dataset's object header proxy */ if(H5B2_depend(idx_info->storage->u.btree2.bt2, oh_proxy) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header proxy") done: /* Release the object header from the cache */ if(oh && H5O_unprotect(&oloc, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__btree2_idx_depend() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_open() * * Purpose: Opens an existing v2 B-tree. * * Note: This information is passively initialized from each index * operation callback because those abstract chunk index operations * are designed to work with the v2 B-tree chunk indices also, * which don't require an 'open' for the data structure. * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_open(const H5D_chk_idx_info_t *idx_info) { H5D_bt2_ctx_ud_t u_ctx; /* user data for creating context */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Check args */ HDassert(idx_info); HDassert(idx_info->f); HDassert(idx_info->pline); HDassert(idx_info->layout); HDassert(H5D_CHUNK_IDX_BT2 == idx_info->layout->idx_type); HDassert(idx_info->storage); HDassert(H5F_addr_defined(idx_info->storage->idx_addr)); HDassert(NULL == idx_info->storage->u.btree2.bt2); /* Set up the user data */ u_ctx.f = idx_info->f; u_ctx.ndims = idx_info->layout->ndims - 1; u_ctx.chunk_size = idx_info->layout->size; u_ctx.dim = idx_info->layout->dim; /* Open v2 B-tree for the chunk index */ if(NULL == (idx_info->storage->u.btree2.bt2 = H5B2_open(idx_info->f, idx_info->storage->idx_addr, &u_ctx))) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't open v2 B-tree for tracking chunked dataset") /* Check for SWMR writes to the file */ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) if(H5D__btree2_idx_depend(idx_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__bt2_idx_open() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_create * * Purpose: Create the v2 B-tree for tracking dataset chunks * * Return: SUCCEED/FAIL * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_create(const H5D_chk_idx_info_t *idx_info) { H5B2_create_t bt2_cparam; /* v2 B-tree creation parameters */ H5D_bt2_ctx_ud_t u_ctx; /* data for context call */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Check args */ HDassert(idx_info); HDassert(idx_info->f); HDassert(idx_info->pline); HDassert(idx_info->layout); HDassert(idx_info->storage); HDassert(!H5F_addr_defined(idx_info->storage->idx_addr)); bt2_cparam.rrec_size = H5F_SIZEOF_ADDR(idx_info->f) /* Address of chunk */ + (idx_info->layout->ndims - 1) * 8; /* # of dimensions x 64-bit chunk offsets */ /* General parameters */ if(idx_info->pline->nused > 0) { unsigned chunk_size_len; /* Size of encoded chunk size */ /* * Compute the size required for encoding the size of a chunk, * allowing for an extra byte, in case the filter makes the chunk larger. */ chunk_size_len = 1 + ((H5VM_log2_gen((uint64_t)idx_info->layout->size) + 8) / 8); if(chunk_size_len > 8) chunk_size_len = 8; bt2_cparam.rrec_size += chunk_size_len + 4; /* Size of encoded chunk size & filter mask */ bt2_cparam.cls = H5D_BT2_FILT; } /* end if */ else bt2_cparam.cls = H5D_BT2; bt2_cparam.node_size = idx_info->layout->u.btree2.cparam.node_size; bt2_cparam.split_percent = idx_info->layout->u.btree2.cparam.split_percent; bt2_cparam.merge_percent = idx_info->layout->u.btree2.cparam.merge_percent; u_ctx.f = idx_info->f; u_ctx.ndims = idx_info->layout->ndims - 1; u_ctx.chunk_size = idx_info->layout->size; u_ctx.dim = idx_info->layout->dim; /* Create the v2 B-tree for the chunked dataset */ if(NULL == (idx_info->storage->u.btree2.bt2 = H5B2_create(idx_info->f, &bt2_cparam, &u_ctx))) HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create v2 B-tree for tracking chunked dataset") /* Retrieve the v2 B-tree's address in the file */ if(H5B2_get_addr(idx_info->storage->u.btree2.bt2, &(idx_info->storage->idx_addr)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get v2 B-tree address for tracking chunked dataset") /* Check for SWMR writes to the file */ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) if(H5D__btree2_idx_depend(idx_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, "unable to create flush dependency on object header") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__bt2_idx_create() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_is_space_alloc * * Purpose: Query if space is allocated for index method * * Return: Non-negative on success/Negative on failure * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static hbool_t H5D__bt2_idx_is_space_alloc(const H5O_storage_chunk_t *storage) { FUNC_ENTER_STATIC_NOERR /* Check args */ HDassert(storage); FUNC_LEAVE_NOAPI((hbool_t)H5F_addr_defined(storage->idx_addr)) } /* end H5D__bt2_idx_is_space_alloc() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_mod_cb * * Purpose: Modify record for dataset chunk when it is found in a v2 B-tree. * This is the callback for H5B2_modify() which is called in * H5D__bt2_idx_insert(). * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_mod_cb(void *_record, void *_op_data, hbool_t *changed) { H5D_bt2_ud_t *op_data = (H5D_bt2_ud_t *)_op_data; /* User data for v2 B-tree calls */ H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* Chunk record */ FUNC_ENTER_STATIC_NOERR /* Sanity check */ #ifndef NDEBUG { unsigned u; /* Local index variable */ for(u = 0; u < op_data->ndims; u++) HDassert(record->scaled[u] == op_data->rec.scaled[u]); } #endif /* NDEBUG */ /* Modify record */ *record = op_data->rec; /* Note that the record changed */ *changed = TRUE; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__bt2_mod_cb() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_insert * * Purpose: Insert chunk address into the indexing structure. * A non-filtered chunk: * Should not exist * Allocate the chunk and pass chunk address back up * A filtered chunk: * If it was not found, create the chunk and pass chunk address back up * If it was found but its size changed, reallocate the chunk and pass chunk address back up * If it was found but its size was the same, pass chunk address back up * * Return: Non-negative on success/Negative on failure * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata, const H5D_t H5_ATTR_UNUSED *dset) { H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */ H5D_bt2_ud_t bt2_udata; /* User data for v2 B-tree calls */ unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Sanity checks */ HDassert(idx_info); HDassert(idx_info->f); HDassert(idx_info->pline); HDassert(idx_info->layout); HDassert(idx_info->storage); HDassert(H5F_addr_defined(idx_info->storage->idx_addr)); HDassert(udata); HDassert(H5F_addr_defined(udata->chunk_block.offset)); /* Check if the v2 B-tree is open yet */ if(NULL == idx_info->storage->u.btree2.bt2) { /* Open existing v2 B-tree */ if(H5D__bt2_idx_open(idx_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree") } /* end if */ else /* Patch the top level file pointer contained in bt2 if needed */ if(H5B2_patch_file(idx_info->storage->u.btree2.bt2, idx_info->f) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer") /* Set convenience pointer to v2 B-tree structure */ bt2 = idx_info->storage->u.btree2.bt2; /* Set up callback info */ bt2_udata.ndims = idx_info->layout->ndims - 1; bt2_udata.rec.chunk_addr = udata->chunk_block.offset; if(idx_info->pline->nused > 0) { /* filtered chunk */ H5_CHECKED_ASSIGN(bt2_udata.rec.nbytes, uint32_t, udata->chunk_block.length, hsize_t); bt2_udata.rec.filter_mask = udata->filter_mask; } /* end if */ else { /* non-filtered chunk */ bt2_udata.rec.nbytes = idx_info->layout->size; bt2_udata.rec.filter_mask = 0; } /* end else */ for(u = 0; u < (idx_info->layout->ndims - 1); u++) bt2_udata.rec.scaled[u] = udata->common.scaled[u]; /* Update record for v2 B-tree (could be insert or modify) */ if(H5B2_update(bt2, &bt2_udata, H5D__bt2_mod_cb, &bt2_udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTUPDATE, FAIL, "unable to update record in v2 B-tree") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5D__bt2_idx_insert() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_found_cb * * Purpose: Retrieve record for dataset chunk when it is found in a v2 B-tree. * This is the callback for H5B2_find() which is called in * H5D__bt2_idx_get_addr() and H5D__bt2_idx_insert(). * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_found_cb(const void *nrecord, void *op_data) { FUNC_ENTER_STATIC_NOERR *(H5D_chunk_rec_t *)op_data = *(const H5D_chunk_rec_t *)nrecord; FUNC_LEAVE_NOAPI(SUCCEED) } /* H5D__bt2_found_cb() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_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 * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata) { H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */ H5D_bt2_ud_t bt2_udata; /* User data for v2 B-tree calls */ H5D_chunk_rec_t found_rec; /* Record found from searching for object */ unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Sanity checks */ HDassert(idx_info); HDassert(idx_info->f); HDassert(idx_info->pline); HDassert(idx_info->layout); HDassert(idx_info->layout->ndims > 0); HDassert(idx_info->storage); HDassert(H5F_addr_defined(idx_info->storage->idx_addr)); HDassert(udata); /* Check if the v2 B-tree is open yet */ if(NULL == idx_info->storage->u.btree2.bt2) { /* Open existing v2 B-tree */ if(H5D__bt2_idx_open(idx_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree") } /* end if */ else /* Patch the top level file pointer contained in bt2 if needed */ if(H5B2_patch_file(idx_info->storage->u.btree2.bt2, idx_info->f) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer") /* Set convenience pointer to v2 B-tree structure */ bt2 = idx_info->storage->u.btree2.bt2; /* Clear the found record */ found_rec.chunk_addr = HADDR_UNDEF; found_rec.nbytes = 0; found_rec.filter_mask = 0; /* Prepare user data for compare callback */ bt2_udata.rec.chunk_addr = HADDR_UNDEF; bt2_udata.ndims = idx_info->layout->ndims - 1; /* Set the chunk offset to be searched for */ for(u = 0; u < (idx_info->layout->ndims - 1); u++) bt2_udata.rec.scaled[u] = udata->common.scaled[u]; /* Go get chunk information from v2 B-tree */ if(H5B2_find(bt2, &bt2_udata, H5D__bt2_found_cb, &found_rec) < 0) HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "can't find object in v2 B-tree") /* Set common info for the chunk */ udata->chunk_block.offset = found_rec.chunk_addr; /* Check for setting other info */ if(H5F_addr_defined(udata->chunk_block.offset)) { /* Sanity check */ HDassert(0 != found_rec.nbytes); /* Set other info for the chunk */ if(idx_info->pline->nused > 0) { /* filtered chunk */ udata->chunk_block.length = found_rec.nbytes; udata->filter_mask = found_rec.filter_mask; } /* end if */ else { /* non-filtered chunk */ udata->chunk_block.length = idx_info->layout->size; udata->filter_mask = 0; } /* end else */ } /* end if */ else { udata->chunk_block.length = 0; udata->filter_mask = 0; } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5D__bt2_idx_get_addr() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_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. * This is the callback for H5B2_iterate() which is called in * H5D__bt2_idx_iterate(). * * Return: Success: Non-negative * Failure: Negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static int H5D__bt2_idx_iterate_cb(const void *_record, void *_udata) { H5D_bt2_it_ud_t *udata = (H5D_bt2_it_ud_t *)_udata; /* User data */ const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* Native record */ int ret_value = -1; /* Return value */ FUNC_ENTER_STATIC_NOERR /* Make "generic chunk" callback */ if((ret_value = (udata->cb)(record, udata->udata)) < 0) HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback"); FUNC_LEAVE_NOAPI(ret_value) } /* H5D__bt2_idx_iterate_cb() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_iterate * * Purpose: Iterate over the chunks in an index, making a callback * for each one. * * Return: Non-negative on success/Negative on failure * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static int H5D__bt2_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb, void *chunk_udata) { H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */ H5D_bt2_it_ud_t udata; /* User data for B-tree iterator callback */ int ret_value = FAIL; /* Return value */ FUNC_ENTER_STATIC /* Sanity checks */ HDassert(idx_info); HDassert(idx_info->f); HDassert(idx_info->pline); HDassert(idx_info->layout); HDassert(idx_info->storage); HDassert(H5F_addr_defined(idx_info->storage->idx_addr)); HDassert(chunk_cb); HDassert(chunk_udata); /* Check if the v2 B-tree is open yet */ if(NULL == idx_info->storage->u.btree2.bt2) { /* Open existing v2 B-tree */ if(H5D__bt2_idx_open(idx_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree") } /* end if */ else /* Patch the top level file pointer contained in bt2 if needed */ if(H5B2_patch_file(idx_info->storage->u.btree2.bt2, idx_info->f) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer") /* Set convenience pointer to v2 B-tree structure */ bt2 = idx_info->storage->u.btree2.bt2; /* Prepare user data for iterate callback */ udata.cb = chunk_cb; udata.udata = chunk_udata; /* Iterate over the records in the v2 B-tree */ if((ret_value = H5B2_iterate(bt2, H5D__bt2_idx_iterate_cb, &udata)) < 0) HERROR(H5E_DATASET, H5E_BADITER, "unable to iterate over chunk v2 B-tree"); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__bt2_idx_iterate() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_remove_cb() * * Purpose: Free space for 'dataset chunk' object as v2 B-tree * is being deleted or v2 B-tree node is removed. * This is the callback for H5B2_remove() and H5B2_delete() which * which are called in H5D__bt2_idx_remove() and H5D__bt2_idx_delete(). * * Return: Success: non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_remove_cb(const void *_record, void *_udata) { const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */ H5F_t *f = (H5F_t *)_udata; /* User data for removal callback */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Sanity checks */ HDassert(f); /* Free the space in the file for the object being removed */ H5_CHECK_OVERFLOW(record->nbytes, uint32_t, hsize_t); if(H5MF_xfree(f, H5FD_MEM_DRAW, record->chunk_addr, (hsize_t)record->nbytes) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5D__bt2_remove_cb() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_remove * * Purpose: Remove chunk from index. * * Return: Non-negative on success/Negative on failure * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata) { H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */ H5D_bt2_ud_t bt2_udata; /* User data for v2 B-tree find call */ unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Sanity checks */ HDassert(idx_info); HDassert(idx_info->f); HDassert(idx_info->pline); HDassert(idx_info->layout); HDassert(idx_info->storage); HDassert(H5F_addr_defined(idx_info->storage->idx_addr)); HDassert(udata); /* Check if the v2 B-tree is open yet */ if(NULL == idx_info->storage->u.btree2.bt2) { /* Open existing v2 B-tree */ if(H5D__bt2_idx_open(idx_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree") } /* end if */ else /* Patch the top level file pointer contained in bt2 if needed */ if(H5B2_patch_file(idx_info->storage->u.btree2.bt2, idx_info->f) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer") /* Set convenience pointer to v2 B-tree structure */ bt2 = idx_info->storage->u.btree2.bt2; /* Prepare user data for compare callback */ bt2_udata.ndims = idx_info->layout->ndims - 1; /* Initialize the record to search for */ for(u = 0; u < (idx_info->layout->ndims - 1); u++) bt2_udata.rec.scaled[u] = udata->scaled[u]; /* Remove the record for the "dataset chunk" object from the v2 B-tree */ /* (space in the file for the object is freed in the 'remove' callback) */ if(H5B2_remove(bt2, &bt2_udata, (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) ? NULL : H5D__bt2_remove_cb, idx_info->f) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "can't remove object from B-tree") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5D__bt2_idx_remove() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_delete * * Purpose: Delete index and raw data storage for entire dataset * (i.e. all chunks) * * Return: Success: Non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * * Modifications: * Vailin Choi; March 2011 * Initialize size of an unfiltered chunk. * This is a fix for for the assertion failure in: * [src/H5FSsection.c:968: H5FS_sect_link_size: Assertion `bin < sinfo->nbins' failed.] * which is uncovered by test_unlink_chunked_dataset() in test/unlink.c * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_delete(const H5D_chk_idx_info_t *idx_info) { H5B2_remove_t remove_op; /* The removal callback */ H5D_bt2_ctx_ud_t u_ctx; /* data for context call */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Sanity checks */ HDassert(idx_info); HDassert(idx_info->f); HDassert(idx_info->pline); HDassert(idx_info->layout); HDassert(idx_info->storage); /* Check if the index data structure has been allocated */ if(H5F_addr_defined(idx_info->storage->idx_addr)) { /* Set up user data for creating context */ u_ctx.f = idx_info->f; u_ctx.ndims = idx_info->layout->ndims - 1; u_ctx.chunk_size = idx_info->layout->size; u_ctx.dim = idx_info->layout->dim; /* Set remove operation. Do not remove chunks in SWMR_WRITE mode */ if(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) remove_op = NULL; else remove_op = H5D__bt2_remove_cb; /* Delete the v2 B-tree */ /*(space in the file for each object is freed in the 'remove' callback) */ if(H5B2_delete(idx_info->f, idx_info->storage->idx_addr, &u_ctx, remove_op, idx_info->f) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "can't delete v2 B-tree") idx_info->storage->idx_addr = HADDR_UNDEF; } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__bt2_idx_delete() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_copy_setup * * Purpose: Set up any necessary information for copying chunks * * Return: Non-negative on success/Negative on failure * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_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_STATIC /* Source file */ HDassert(idx_info_src); HDassert(idx_info_src->f); HDassert(idx_info_src->pline); HDassert(idx_info_src->layout); HDassert(idx_info_src->storage); /* Destination file */ HDassert(idx_info_dst); HDassert(idx_info_dst->f); HDassert(idx_info_dst->pline); HDassert(idx_info_dst->layout); HDassert(idx_info_dst->storage); HDassert(!H5F_addr_defined(idx_info_dst->storage->idx_addr)); /* Check if the source v2 B-tree is open yet */ if(NULL == idx_info_src->storage->u.btree2.bt2) if(H5D__bt2_idx_open(idx_info_src) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree") /* Set copied metadata tag */ H5_BEGIN_TAG(H5AC__COPIED_TAG); /* Create v2 B-tree that describes the chunked dataset in the destination file */ if(H5D__bt2_idx_create(idx_info_dst) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunked storage") HDassert(H5F_addr_defined(idx_info_dst->storage->idx_addr)); /* Reset metadata tag */ H5_END_TAG done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__bt2_idx_copy_setup() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_copy_shutdown * * Purpose: Shutdown any information from copying chunks * * Return: Non-negative on success/Negative on failure * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_copy_shutdown(H5O_storage_chunk_t *storage_src, H5O_storage_chunk_t *storage_dst) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Check args */ HDassert(storage_src); HDassert(storage_src->u.btree2.bt2); HDassert(storage_dst); HDassert(storage_dst->u.btree2.bt2); /* Close v2 B-tree for source file */ if(H5B2_close(storage_src->u.btree2.bt2) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close v2 B-tree") storage_src->u.btree2.bt2 = NULL; /* Close v2 B-tree for destination file */ if(H5B2_close(storage_dst->u.btree2.bt2) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close v2 B-tree") storage_dst->u.btree2.bt2 = NULL; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__bt2_idx_copy_shutdown() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_size * * Purpose: Retrieve the amount of index storage for chunked dataset * * Return: Success: Non-negative * Failure: negative * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size) { H5B2_t *bt2_cdset = NULL; /* Pointer to v2 B-tree structure */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Check args */ HDassert(idx_info); HDassert(idx_info->f); HDassert(idx_info->pline); HDassert(idx_info->layout); HDassert(idx_info->storage); HDassert(H5F_addr_defined(idx_info->storage->idx_addr)); HDassert(index_size); /* Open v2 B-tree */ if(H5D__bt2_idx_open(idx_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree") /* Set convenience pointer to v2 B-tree structure */ bt2_cdset = idx_info->storage->u.btree2.bt2; /* Get v2 B-tree size for indexing chunked dataset */ if(H5B2_size(bt2_cdset, index_size) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve v2 B-tree storage info for chunked dataset") done: /* Close v2 B-tree index */ if(bt2_cdset && H5B2_close(bt2_cdset) < 0) HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for tracking chunked dataset") idx_info->storage->u.btree2.bt2 = NULL; FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__bt2_idx_size() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_reset * * Purpose: Reset indexing information. * * Return: Non-negative on success/Negative on failure * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr) { FUNC_ENTER_STATIC_NOERR /* Sanity checks */ HDassert(storage); /* Reset index info */ if(reset_addr) storage->idx_addr = HADDR_UNDEF; storage->u.btree2.bt2 = NULL; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__bt2_idx_reset() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_dump * * Purpose: Dump indexing information to a stream. * * Return: Non-negative on success/Negative on failure * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream) { FUNC_ENTER_STATIC_NOERR /* Sanity checks */ HDassert(storage); HDassert(stream); HDfprintf(stream, " Address: %a\n", storage->idx_addr); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__bt2_idx_dump() */ /*------------------------------------------------------------------------- * Function: H5D__bt2_idx_dest * * Purpose: Release indexing information in memory. * * Return: Non-negative on success/Negative on failure * * Programmer: Vailin Choi; June 2010 * *------------------------------------------------------------------------- */ static herr_t H5D__bt2_idx_dest(const H5D_chk_idx_info_t *idx_info) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Check args */ HDassert(idx_info); HDassert(idx_info->f); HDassert(idx_info->storage); /* Check if the v2-btree is open */ if(idx_info->storage->u.btree2.bt2) { /* Patch the top level file pointer contained in bt2 if needed */ if(H5B2_patch_file(idx_info->storage->u.btree2.bt2, idx_info->f) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer") /* Close v2 B-tree */ if(H5B2_close(idx_info->storage->u.btree2.bt2) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree") idx_info->storage->u.btree2.bt2 = NULL; } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__bt2_idx_dest() */