summaryrefslogtreecommitdiff
path: root/src/H5B2cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5B2cache.c')
-rw-r--r--src/H5B2cache.c1362
1 files changed, 1362 insertions, 0 deletions
diff --git a/src/H5B2cache.c b/src/H5B2cache.c
new file mode 100644
index 0000000..2e1d37b
--- /dev/null
+++ b/src/H5B2cache.c
@@ -0,0 +1,1362 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5B2cache.c
+ * Jan 31 2005
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Implement v2 B-tree metadata cache methods.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5B2module.h" /* This source code file is part of the H5B2 module */
+
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5B2pkg.h" /* v2 B-trees */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5WBprivate.h" /* Wrapped Buffers */
+
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* B-tree format version #'s */
+#define H5B2_HDR_VERSION 0 /* Header */
+#define H5B2_INT_VERSION 0 /* Internal node */
+#define H5B2_LEAF_VERSION 0 /* Leaf node */
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Metadata cache callbacks */
+static herr_t H5B2__cache_hdr_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5B2__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata);
+static void *H5B2__cache_hdr_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5B2__cache_hdr_image_len(const void *thing, size_t *image_len);
+static herr_t H5B2__cache_hdr_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5B2__cache_hdr_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5B2__cache_hdr_free_icr(void *thing);
+
+static herr_t H5B2__cache_int_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5B2__cache_int_verify_chksum(const void *image_ptr, size_t len, void *udata);
+static void *H5B2__cache_int_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5B2__cache_int_image_len(const void *thing, size_t *image_len);
+static herr_t H5B2__cache_int_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5B2__cache_int_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5B2__cache_int_free_icr(void *thing);
+
+static herr_t H5B2__cache_leaf_get_initial_load_size(void *udata, size_t *image_len);
+static htri_t H5B2__cache_leaf_verify_chksum(const void *image_ptr, size_t len, void *udata);
+static void *H5B2__cache_leaf_deserialize(const void *image, size_t len,
+ void *udata, hbool_t *dirty);
+static herr_t H5B2__cache_leaf_image_len(const void *thing, size_t *image_len);
+static herr_t H5B2__cache_leaf_serialize(const H5F_t *f, void *image, size_t len,
+ void *thing);
+static herr_t H5B2__cache_leaf_notify(H5AC_notify_action_t action, void *thing);
+static herr_t H5B2__cache_leaf_free_icr(void *thing);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* H5B2 inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_BT2_HDR[1] = {{
+ H5AC_BT2_HDR_ID, /* Metadata client ID */
+ "v2 B-tree header", /* Metadata client name (for debugging) */
+ H5FD_MEM_BTREE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5B2__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5B2__cache_hdr_verify_chksum, /* 'verify_chksum' callback */
+ H5B2__cache_hdr_deserialize, /* 'deserialize' callback */
+ H5B2__cache_hdr_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5B2__cache_hdr_serialize, /* 'serialize' callback */
+ H5B2__cache_hdr_notify, /* 'notify' callback */
+ H5B2__cache_hdr_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5B2 inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_BT2_INT[1] = {{
+ H5AC_BT2_INT_ID, /* Metadata client ID */
+ "v2 B-tree internal node", /* Metadata client name (for debugging) */
+ H5FD_MEM_BTREE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5B2__cache_int_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5B2__cache_int_verify_chksum, /* 'verify_chksum' callback */
+ H5B2__cache_int_deserialize, /* 'deserialize' callback */
+ H5B2__cache_int_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5B2__cache_int_serialize, /* 'serialize' callback */
+ H5B2__cache_int_notify, /* 'notify' callback */
+ H5B2__cache_int_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+/* H5B2 inherits cache-like properties from H5AC */
+const H5AC_class_t H5AC_BT2_LEAF[1] = {{
+ H5AC_BT2_LEAF_ID, /* Metadata client ID */
+ "v2 B-tree leaf node", /* Metadata client name (for debugging) */
+ H5FD_MEM_BTREE, /* File space memory type for client */
+ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
+ H5B2__cache_leaf_get_initial_load_size, /* 'get_initial_load_size' callback */
+ NULL, /* 'get_final_load_size' callback */
+ H5B2__cache_leaf_verify_chksum, /* 'verify_chksum' callback */
+ H5B2__cache_leaf_deserialize, /* 'deserialize' callback */
+ H5B2__cache_leaf_image_len, /* 'image_len' callback */
+ NULL, /* 'pre_serialize' callback */
+ H5B2__cache_leaf_serialize, /* 'serialize' callback */
+ H5B2__cache_leaf_notify, /* 'notify' callback */
+ H5B2__cache_leaf_free_icr, /* 'free_icr' callback */
+ NULL, /* 'fsf_size' callback */
+}};
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->f);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = H5B2_HEADER_SIZE_FILE(udata->f);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_hdr_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5B2__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_hdr_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_deserialize
+ *
+ * Purpose: Loads a B-tree header from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 1 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5B2__cache_hdr_deserialize(const void *_image, size_t H5_ATTR_UNUSED len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5B2_hdr_t *hdr = NULL; /* B-tree header */
+ H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata;
+ H5B2_create_t cparam; /* B-tree creation parameters */
+ H5B2_subid_t id; /* ID of B-tree class, as found in file */
+ uint16_t depth; /* Depth of B-tree */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5B2_hdr_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Allocate new B-tree header and reset cache info */
+ if(NULL == (hdr = H5B2__hdr_alloc(udata->f)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "allocation failed for B-tree header")
+
+ /* Magic number */
+ if(HDmemcmp(image, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree header signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5B2_HDR_VERSION)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADRANGE, NULL, "wrong B-tree header version")
+
+ /* B-tree class */
+ id = (H5B2_subid_t)*image++;
+ if(id >= H5B2_NUM_BTREE_ID)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type")
+
+ /* Node size (in bytes) */
+ UINT32DECODE(image, cparam.node_size);
+
+ /* Raw key size (in bytes) */
+ UINT16DECODE(image, cparam.rrec_size);
+
+ /* Depth of tree */
+ UINT16DECODE(image, depth);
+
+ /* Split & merge %s */
+ cparam.split_percent = *image++;
+ cparam.merge_percent = *image++;
+
+ /* Root node pointer */
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &(hdr->root.addr));
+ UINT16DECODE(image, hdr->root.node_nrec);
+ H5F_DECODE_LENGTH(udata->f, image, hdr->root.all_nrec);
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) == hdr->hdr_size);
+
+ /* Initialize B-tree header info */
+ cparam.cls = H5B2_client_class_g[id];
+ if(H5B2__hdr_init(hdr, &cparam, udata->ctx_udata, depth) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, NULL, "can't initialize B-tree header info")
+
+ /* Set the B-tree header's address */
+ hdr->addr = udata->addr;
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= len);
+
+ /* Set return value */
+ ret_value = hdr;
+
+done:
+ if(!ret_value && hdr)
+ if(H5B2__hdr_free(hdr) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, NULL, "can't release v2 B-tree header")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_hdr_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 20, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_hdr_image_len(const void *_thing, size_t *image_len)
+{
+ const H5B2_hdr_t *hdr = (const H5B2_hdr_t *)_thing; /* Pointer to the B-tree header */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = hdr->hdr_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_hdr_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_serialize
+ *
+ * Purpose: Flushes a dirty B-tree header to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 1 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_hdr_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing)
+{
+ H5B2_hdr_t *hdr = (H5B2_hdr_t *)_thing; /* Pointer to the B-tree header */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(hdr);
+
+ /* Magic number */
+ HDmemcpy(image, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5B2_HDR_VERSION;
+
+ /* B-tree type */
+ *image++ = hdr->cls->id;
+
+ /* Node size (in bytes) */
+ UINT32ENCODE(image, hdr->node_size);
+
+ /* Raw key size (in bytes) */
+ UINT16ENCODE(image, hdr->rrec_size);
+
+ /* Depth of tree */
+ UINT16ENCODE(image, hdr->depth);
+
+ /* Split & merge %s */
+ H5_CHECK_OVERFLOW(hdr->split_percent, /* From: */ unsigned, /* To: */ uint8_t);
+ *image++ = (uint8_t)hdr->split_percent;
+ H5_CHECK_OVERFLOW(hdr->merge_percent, /* From: */ unsigned, /* To: */ uint8_t);
+ *image++ = (uint8_t)hdr->merge_percent;
+
+ /* Root node pointer */
+ H5F_addr_encode(f, &image, hdr->root.addr);
+ UINT16ENCODE(image, hdr->root.node_nrec);
+ H5F_ENCODE_LENGTH(f, image, hdr->root.all_nrec);
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (hdr->hdr_size - H5B2_SIZEOF_CHKSUM), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) == len);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* H5B2__cache_hdr_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * nfortne2@hdfgroup.org
+ * Apr 24 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_hdr_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5B2_hdr_t *hdr = (H5B2_hdr_t *)_thing;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(hdr->swmr_write) {
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ /* Increment the shadow epoch, forcing new modifications to
+ * internal and leaf nodes to create new shadow copies */
+ hdr->shadow_epoch++;
+ break;
+
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* If hdr->parent != NULL, hdr->parent is used to destroy
+ * the flush dependency before the header is evicted.
+ */
+ if(hdr->parent) {
+ /* Sanity check */
+ HDassert(hdr->top_proxy);
+
+ /* Destroy flush dependency on object header proxy */
+ if(H5AC_proxy_entry_remove_child((H5AC_proxy_entry_t *)hdr->parent, (void *)hdr->top_proxy) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency between v2 B-tree and proxy")
+ hdr->parent = NULL;
+ } /* end if */
+
+ /* Detach from 'top' proxy for extensible array */
+ if(hdr->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(hdr->top_proxy, hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency between header and v2 B-tree 'top' proxy")
+ /* Don't reset hdr->top_proxy here, it's destroyed when the header is freed -QAK */
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+ else
+ HDassert(NULL == hdr->parent);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_hdr_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_hdr_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * mcgreevy@hdfgroup.org
+ * June 18, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_hdr_free_icr(void *thing)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(thing);
+
+ /* Destroy v2 B-tree header */
+ if(H5B2__hdr_free((H5B2_hdr_t *)thing) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free v2 B-tree header")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_hdr_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_int_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = udata->hdr->node_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_int_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5B2__cache_int_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */
+ size_t chk_size; /* Exact size of the node with checksum at the end */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Internal node prefix header + records + child pointer triplets: size with checksum at the end */
+ chk_size = H5B2_INT_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size) + ((size_t)(udata->nrec + 1) * H5B2_INT_POINTER_SIZE(udata->hdr, udata->depth));
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_int_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_deserialize
+ *
+ * Purpose: Deserialize a B-tree internal node from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree internal node.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5B2__cache_int_deserialize(const void *_image, size_t H5_ATTR_UNUSED len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */
+ H5B2_internal_t *internal = NULL; /* Internal node read */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint8_t *native; /* Pointer to native record info */
+ H5B2_node_ptr_t *int_node_ptr; /* Pointer to node pointer info */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ unsigned u; /* Local index variable */
+ H5B2_internal_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Allocate new internal node and reset cache info */
+ if(NULL == (internal = H5FL_CALLOC(H5B2_internal_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Increment ref. count on B-tree header */
+ if(H5B2__hdr_incr(udata->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment ref. count on B-tree header")
+
+ /* Share B-tree information */
+ internal->hdr = udata->hdr;
+ internal->parent = udata->parent;
+ internal->shadow_epoch = udata->hdr->shadow_epoch;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree internal node signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5B2_INT_VERSION)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree internal node version")
+
+ /* B-tree type */
+ if(*image++ != (uint8_t)udata->hdr->cls->id)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type")
+
+ /* Allocate space for the native keys in memory */
+ if(NULL == (internal->int_native = (uint8_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[udata->depth].nat_rec_fac)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for B-tree internal native keys")
+
+ /* Allocate space for the node pointers in memory */
+ if(NULL == (internal->node_ptrs = (H5B2_node_ptr_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[udata->depth].node_ptr_fac)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for B-tree internal node pointers")
+
+ /* Set the number of records in the leaf & it's depth */
+ internal->nrec = udata->nrec;
+ internal->depth = udata->depth;
+
+ /* Deserialize records for internal node */
+ native = internal->int_native;
+ for(u = 0; u < internal->nrec; u++) {
+ /* Decode record */
+ if((udata->hdr->cls->decode)(image, native, udata->hdr->cb_ctx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode B-tree record")
+
+ /* Move to next record */
+ image += udata->hdr->rrec_size;
+ native += udata->hdr->cls->nrec_size;
+ } /* end for */
+
+ /* Deserialize node pointers for internal node */
+ int_node_ptr = internal->node_ptrs;
+ for(u = 0; u < (unsigned)(internal->nrec + 1); u++) {
+ /* Decode node pointer */
+ H5F_addr_decode(udata->f, (const uint8_t **)&image, &(int_node_ptr->addr));
+ UINT64DECODE_VAR(image, int_node_ptr->node_nrec, udata->hdr->max_nrec_size);
+ if(udata->depth > 1)
+ UINT64DECODE_VAR(image, int_node_ptr->all_nrec, udata->hdr->node_info[udata->depth - 1].cum_max_nrec_size)
+ else
+ int_node_ptr->all_nrec = int_node_ptr->node_nrec;
+
+ /* Move to next node pointer */
+ int_node_ptr++;
+ } /* end for */
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check parsing */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= len);
+
+ /* Set return value */
+ ret_value = internal;
+
+done:
+ if(!ret_value && internal)
+ if(H5B2__internal_free(internal) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree internal node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_int_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 20, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_int_image_len(const void *_thing, size_t *image_len)
+{
+ const H5B2_internal_t *internal = (const H5B2_internal_t *)_thing; /* Pointer to the B-tree internal node */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(internal);
+ HDassert(internal->hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = internal->hdr->node_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_int_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_serialize
+ *
+ * Purpose: Serializes a B-tree internal node for writing to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 3 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_int_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing)
+{
+ H5B2_internal_t *internal = (H5B2_internal_t *)_thing; /* Pointer to the B-tree internal node */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint8_t *native; /* Pointer to native record info */
+ H5B2_node_ptr_t *int_node_ptr; /* Pointer to node pointer info */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(internal);
+ HDassert(internal->hdr);
+
+ /* Magic number */
+ HDmemcpy(image, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version # */
+ *image++ = H5B2_INT_VERSION;
+
+ /* B-tree type */
+ *image++ = internal->hdr->cls->id;
+ HDassert((size_t)(image - (uint8_t *)_image) == (H5B2_INT_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM));
+
+ /* Serialize records for internal node */
+ native = internal->int_native;
+ for(u = 0; u < internal->nrec; u++) {
+ /* Encode record */
+ if((internal->hdr->cls->encode)(image, native, internal->hdr->cb_ctx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record")
+
+ /* Move to next record */
+ image += internal->hdr->rrec_size;
+ native += internal->hdr->cls->nrec_size;
+ } /* end for */
+
+ /* Serialize node pointers for internal node */
+ int_node_ptr = internal->node_ptrs;
+ for(u = 0; u < (unsigned)(internal->nrec + 1); u++) {
+ /* Encode node pointer */
+ H5F_addr_encode(f, &image, int_node_ptr->addr);
+ UINT64ENCODE_VAR(image, int_node_ptr->node_nrec, internal->hdr->max_nrec_size);
+ if(internal->depth > 1)
+ UINT64ENCODE_VAR(image, int_node_ptr->all_nrec, internal->hdr->node_info[internal->depth - 1].cum_max_nrec_size);
+
+ /* Move to next node pointer */
+ int_node_ptr++;
+ } /* end for */
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) <= len);
+
+ /* Clear rest of internal node */
+ HDmemset(image, 0, len - (size_t)(image - (uint8_t *)_image));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_int_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * nfortne2@hdfgroup.org
+ * Apr 25 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_int_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5B2_internal_t *internal = (H5B2_internal_t *)_thing;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(internal);
+ HDassert(internal->hdr);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(internal->hdr->swmr_write) {
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Create flush dependency on parent */
+ if(H5B2__create_flush_depend((H5AC_info_t *)internal->parent, (H5AC_info_t *)internal) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on parent */
+ if(H5B2__destroy_flush_depend((H5AC_info_t *)internal->parent, (H5AC_info_t *)internal) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+
+ /* Detach from 'top' proxy for v2 B-tree */
+ if(internal->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(internal->top_proxy, internal) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency between internal node and v2 B-tree 'top' proxy")
+ internal->top_proxy = NULL;
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+ else
+ HDassert(NULL == internal->top_proxy);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_int_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_int_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * mcgreevy@hdfgroup.org
+ * June 18, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_int_free_icr(void *_thing)
+{
+ H5B2_internal_t *internal = (H5B2_internal_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(internal);
+
+ /* Release v2 B-tree internal node */
+ if(H5B2__internal_free(internal) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release v2 B-tree internal node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_int_free_icr() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_get_initial_load_size
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 18, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_leaf_get_initial_load_size(void *_udata, size_t *image_len)
+{
+ H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata; /* User data for callback */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(udata);
+ HDassert(udata->hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = udata->hdr->node_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_leaf_get_initial_load_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_verify_chksum
+ *
+ * Purpose: Verify the computed checksum of the data structure is the
+ * same as the stored chksum.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: Negative
+ *
+ * Programmer: Vailin Choi; Aug 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5B2__cache_leaf_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata)
+{
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */
+ size_t chk_size; /* Exact size of the node with checksum at the end */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ uint32_t computed_chksum; /* Computed metadata checksum value */
+ htri_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Leaf node prefix header + records: size with checksum at the end */
+ chk_size = H5B2_LEAF_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size);
+
+ /* Get stored and computed checksums */
+ H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum);
+
+ if(stored_chksum != computed_chksum)
+ ret_value = FALSE;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_leaf_verify_chksum() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_deserialize
+ *
+ * Purpose: Deserialize a B-tree leaf from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree leaf node.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5B2__cache_leaf_deserialize(const void *_image, size_t H5_ATTR_UNUSED len,
+ void *_udata, hbool_t H5_ATTR_UNUSED *dirty)
+{
+ H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata;
+ H5B2_leaf_t *leaf = NULL; /* Pointer to lead node loaded */
+ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
+ uint8_t *native; /* Pointer to native keys */
+ uint32_t stored_chksum; /* Stored metadata checksum value */
+ unsigned u; /* Local index variable */
+ H5B2_leaf_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(image);
+ HDassert(udata);
+
+ /* Allocate new leaf node and reset cache info */
+ if(NULL == (leaf = H5FL_CALLOC(H5B2_leaf_t)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed")
+
+ /* Increment ref. count on B-tree header */
+ if(H5B2__hdr_incr(udata->hdr) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment ref. count on B-tree header")
+
+ /* Share B-tree header information */
+ leaf->hdr = udata->hdr;
+ leaf->parent = udata->parent;
+ leaf->shadow_epoch = udata->hdr->shadow_epoch;
+
+ /* Magic number */
+ if(HDmemcmp(image, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC))
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree leaf node signature")
+ image += H5_SIZEOF_MAGIC;
+
+ /* Version */
+ if(*image++ != H5B2_LEAF_VERSION)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADRANGE, NULL, "wrong B-tree leaf node version")
+
+ /* B-tree type */
+ if(*image++ != (uint8_t)udata->hdr->cls->id)
+ HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type")
+
+ /* Allocate space for the native keys in memory */
+ if(NULL == (leaf->leaf_native = (uint8_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[0].nat_rec_fac)))
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree leaf native keys")
+
+ /* Set the number of records in the leaf */
+ leaf->nrec = udata->nrec;
+
+ /* Deserialize records for leaf node */
+ native = leaf->leaf_native;
+ for(u = 0; u < leaf->nrec; u++) {
+ /* Decode record */
+ if((udata->hdr->cls->decode)(image, native, udata->hdr->cb_ctx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, NULL, "unable to decode B-tree record")
+
+ /* Move to next record */
+ image += udata->hdr->rrec_size;
+ native += udata->hdr->cls->nrec_size;
+ } /* end for */
+
+ /* checksum verification already done in verify_chksum cb */
+
+ /* Metadata checksum */
+ UINT32DECODE(image, stored_chksum);
+
+ /* Sanity check parsing */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= udata->hdr->node_size);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (const uint8_t *)_image) <= len);
+
+ /* Set return value */
+ ret_value = leaf;
+
+done:
+ if(!ret_value && leaf)
+ if(H5B2__leaf_free(leaf) < 0)
+ HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree leaf node")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_leaf_deserialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_image_len
+ *
+ * Purpose: Compute the size of the data structure on disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * May 20, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_leaf_image_len(const void *_thing, size_t *image_len)
+{
+ const H5B2_leaf_t *leaf = (const H5B2_leaf_t *)_thing; /* Pointer to the B-tree leaf node */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check arguments */
+ HDassert(leaf);
+ HDassert(leaf->hdr);
+ HDassert(image_len);
+
+ /* Set the image length size */
+ *image_len = leaf->hdr->node_size;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5B2__cache_leaf_image_len() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_serialize
+ *
+ * Purpose: Serializes a B-tree leaf node for writing to disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 2 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_leaf_serialize(const H5F_t H5_ATTR_UNUSED *f, void *_image, size_t H5_ATTR_UNUSED len,
+ void *_thing)
+{
+ H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing; /* Pointer to the B-tree leaf node */
+ uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */
+ uint8_t *native; /* Pointer to native keys */
+ uint32_t metadata_chksum; /* Computed metadata checksum value */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* check arguments */
+ HDassert(f);
+ HDassert(image);
+ HDassert(leaf);
+ HDassert(leaf->hdr);
+
+ /* magic number */
+ HDmemcpy(image, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC);
+ image += H5_SIZEOF_MAGIC;
+
+ /* version # */
+ *image++ = H5B2_LEAF_VERSION;
+
+ /* B-tree type */
+ *image++ = leaf->hdr->cls->id;
+ HDassert((size_t)(image - (uint8_t *)_image) == (H5B2_LEAF_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM));
+
+ /* Serialize records for leaf node */
+ native = leaf->leaf_native;
+ for(u = 0; u < leaf->nrec; u++) {
+ /* Encode record */
+ if((leaf->hdr->cls->encode)(image, native, leaf->hdr->cb_ctx) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record")
+
+ /* Move to next record */
+ image += leaf->hdr->rrec_size;
+ native += leaf->hdr->cls->nrec_size;
+ } /* end for */
+
+ /* Compute metadata checksum */
+ metadata_chksum = H5_checksum_metadata(_image, (size_t)((const uint8_t *)image - (const uint8_t *)_image), 0);
+
+ /* Metadata checksum */
+ UINT32ENCODE(image, metadata_chksum);
+
+ /* Sanity check */
+ HDassert((size_t)(image - (uint8_t *)_image) <= len);
+
+ /* Clear rest of leaf node */
+ HDmemset(image, 0, len - (size_t)(image - (uint8_t *)_image));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_leaf_serialize() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_notify
+ *
+ * Purpose: Handle cache action notifications
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * nfortne2@hdfgroup.org
+ * Apr 25 2012
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_leaf_notify(H5AC_notify_action_t action, void *_thing)
+{
+ H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /*
+ * Check arguments.
+ */
+ HDassert(leaf);
+ HDassert(leaf->hdr);
+
+ /* Check if the file was opened with SWMR-write access */
+ if(leaf->hdr->swmr_write) {
+ switch(action) {
+ case H5AC_NOTIFY_ACTION_AFTER_INSERT:
+ case H5AC_NOTIFY_ACTION_AFTER_LOAD:
+ /* Create flush dependency on parent */
+ if(H5B2__create_flush_depend((H5AC_info_t *)leaf->parent, (H5AC_info_t *)leaf) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ break;
+
+ case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
+ case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
+ case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
+ case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
+ case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
+ case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
+ /* do nothing */
+ break;
+
+ case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ /* Destroy flush dependency on parent */
+ if(H5B2__destroy_flush_depend((H5AC_info_t *)leaf->parent, (H5AC_info_t *)leaf) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+
+ /* Detach from 'top' proxy for v2 B-tree */
+ if(leaf->top_proxy) {
+ if(H5AC_proxy_entry_remove_child(leaf->top_proxy, leaf) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency between leaf node and v2 B-tree 'top' proxy")
+ leaf->top_proxy = NULL;
+ } /* end if */
+ break;
+
+ default:
+#ifdef NDEBUG
+ HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
+#else /* NDEBUG */
+ HDassert(0 && "Unknown action?!?");
+#endif /* NDEBUG */
+ } /* end switch */
+ } /* end if */
+ else
+ HDassert(NULL == leaf->top_proxy);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5B2__cache_leaf_notify() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B2__cache_leaf_free_icr
+ *
+ * Purpose: Destroy/release an "in core representation" of a data
+ * structure
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Mike McGreevy
+ * mcgreevy@hdfgroup.org
+ * June 18, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B2__cache_leaf_free_icr(void *_thing)
+{
+ H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check arguments */
+ HDassert(leaf);
+
+ /* Destroy v2 B-tree leaf node */
+ if(H5B2__leaf_free(leaf) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree leaf node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5B2__cache_leaf_free_icr() */
+