summaryrefslogtreecommitdiff
path: root/src/H5Dbtree2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5Dbtree2.c')
-rw-r--r--src/H5Dbtree2.c1575
1 files changed, 1575 insertions, 0 deletions
diff --git a/src/H5Dbtree2.c b/src/H5Dbtree2.c
new file mode 100644
index 0000000..2e19392
--- /dev/null
+++ b/src/H5Dbtree2.c
@@ -0,0 +1,1575 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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 "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;
+
+/* User data for the chunk's removal callback routine */
+typedef struct H5D_bt2_remove_ud_t {
+ H5F_t *f; /* File pointer for operation */
+ hid_t dxpl_id; /* DXPL ID for operation */
+} H5D_bt2_remove_ud_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, hid_t dxpl_id);
+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 */
+}};
+
+
+/*****************************/
+/* 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_BLK_DEFINE(chunk_dim);
+
+
+
+
+/*-------------------------------------------------------------------------
+ * 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_BLK_MALLOC(chunk_dim, H5O_LAYOUT_NDIMS * sizeof(uint32_t))))
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate chunk dims")
+ HDmemcpy(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)
+ (void)H5FL_BLK_FREE(chunk_dim, 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 varible */
+
+ 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, idx_info->dxpl_id, 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, idx_info->dxpl_id, 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, idx_info->dxpl_id, 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->dxpl_id, 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, idx_info->dxpl_id, &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, idx_info->dxpl_id, &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, idx_info->dxpl_id, &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, idx_info->dxpl_id, 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 */
+ H5D_bt2_remove_ud_t *udata = (H5D_bt2_remove_ud_t *)_udata; /* User data for removal callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
+ HDassert(udata);
+ HDassert(udata->f);
+
+ /* Free the space in the file for the object being removed */
+ H5_CHECK_OVERFLOW(record->nbytes, uint32_t, hsize_t);
+ if(H5MF_xfree(udata->f, H5FD_MEM_DRAW, udata->dxpl_id, 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_remove_ud_t remove_udata; /* User data for removal callback */
+ 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;
+
+ /* Initialize user data for removal callback */
+ remove_udata.f = idx_info->f;
+ remove_udata.dxpl_id = idx_info->dxpl_id;
+
+ /* 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, idx_info->dxpl_id, &bt2_udata, (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) ? NULL : H5D__bt2_remove_cb, &remove_udata) < 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)
+{
+ H5D_bt2_remove_ud_t remove_udata; /* User data for removal callback */
+ 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;
+
+ /* Initialize user data for removal callback */
+ remove_udata.f = idx_info->f;
+ remove_udata.dxpl_id = idx_info->dxpl_id;
+
+ /* 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->dxpl_id, idx_info->storage->idx_addr, &u_ctx, remove_op, &remove_udata) < 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(idx_info_dst->dxpl_id, H5AC__COPIED_TAG, FAIL);
+
+ /* 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(FAIL);
+
+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, hid_t H5_ATTR_UNUSED dxpl_id)
+{
+ 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, dxpl_id) < 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, dxpl_id) < 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, idx_info->dxpl_id, 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, idx_info->dxpl_id) < 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, idx_info->dxpl_id) < 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() */
+