summaryrefslogtreecommitdiffstats
path: root/src/H5HFdblock.c
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2006-04-15 21:11:42 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2006-04-15 21:11:42 (GMT)
commitc83c1eb42d2ac0c252b13fa125d8bb4c0fc4665b (patch)
tree68192e89b3d768aa69dc5b4d618359cfcc78a30b /src/H5HFdblock.c
parent838b4449cfb3271aa7c13f811e7e91c5beb7560b (diff)
downloadhdf5-c83c1eb42d2ac0c252b13fa125d8bb4c0fc4665b.zip
hdf5-c83c1eb42d2ac0c252b13fa125d8bb4c0fc4665b.tar.gz
hdf5-c83c1eb42d2ac0c252b13fa125d8bb4c0fc4665b.tar.bz2
[svn-r12258] Purpose:
Code checkpoint Description: Add in more fractal heap support for odd allocation patterns (entries that are too large for various block sizes, etc.) Broke out fractal heap code into more source code modules. Refactored fractal heap test to make it more understandable and maintainable for the long term. Platforms tested: FreeBSD 4.11 (sleipnir) Linux 2.4 (heping) Linux 2.4/64 (mir) Solaris 2.9 (shanti)
Diffstat (limited to 'src/H5HFdblock.c')
-rw-r--r--src/H5HFdblock.c585
1 files changed, 585 insertions, 0 deletions
diff --git a/src/H5HFdblock.c b/src/H5HFdblock.c
new file mode 100644
index 0000000..dcb704c
--- /dev/null
+++ b/src/H5HFdblock.c
@@ -0,0 +1,585 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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 files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5HFdblock.c
+ * Apr 10 2006
+ * Quincey Koziol <koziol@ncsa.uiuc.edu>
+ *
+ * Purpose: Direct block routines for fractal heaps.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5HF_PACKAGE /*suppress error about including H5HFpkg */
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5HFpkg.h" /* Fractal heaps */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5Vprivate.h" /* Vectors and arrays */
+
+/****************/
+/* Local Macros */
+/****************/
+
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Declare a free list to manage the H5HF_direct_t struct */
+H5FL_DEFINE(H5HF_direct_t);
+
+/* Declare a free list to manage the H5HF_direct_free_head_t struct */
+H5FL_DEFINE(H5HF_direct_free_head_t);
+
+/* Declare a free list to manage the H5HF_direct_free_node_t struct */
+H5FL_DEFINE(H5HF_direct_free_node_t);
+
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_create
+ *
+ * Purpose: Allocate & initialize a managed direct block
+ *
+ * Return: Pointer to new direct block on success, NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 27 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_dblock_create(hid_t dxpl_id, H5HF_t *hdr, H5HF_indirect_t *par_iblock,
+ unsigned par_entry, size_t block_size, hsize_t block_off, haddr_t *addr_p,
+ H5HF_free_section_t **ret_sec_node)
+{
+ H5HF_direct_free_node_t *node; /* Pointer to free list node for block */
+ H5HF_free_section_t *sec_node; /* Pointer to free list section for block */
+ H5HF_direct_t *dblock = NULL; /* Pointer to direct block */
+ size_t free_space; /* Free space in new block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5HF_man_dblock_create)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(block_size > 0);
+ HDassert(addr_p);
+
+ /*
+ * Allocate file and memory data structures.
+ */
+ if(NULL == (dblock = H5FL_MALLOC(H5HF_direct_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for fractal heap direct block")
+
+ /* Reset the metadata cache info for the heap header */
+ HDmemset(&dblock->cache_info, 0, sizeof(H5AC_info_t));
+
+ /* Share common heap information */
+ dblock->shared = hdr;
+ if(H5HF_hdr_incr(hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared heap header")
+
+ /* Set info for direct block */
+#ifdef QAK
+HDfprintf(stderr, "%s: size = %Zu, block_off = %Hu\n", FUNC, block_size, block_off);
+#endif /* QAK */
+ dblock->parent = par_iblock;
+ if(dblock->parent) {
+ if(H5HF_iblock_incr(par_iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared indirect block")
+ dblock->par_addr = par_iblock->addr;
+ dblock->par_nrows = par_iblock->nrows;
+ } /* end if */
+ else {
+ dblock->par_addr = HADDR_UNDEF;
+ dblock->par_nrows = 0;
+ } /* end else */
+ dblock->par_entry = par_entry;
+ dblock->size = block_size;
+ dblock->block_off = block_off;
+ dblock->blk_off_size = H5HF_SIZEOF_OFFSET_LEN(block_size);
+ dblock->free_list_head = H5HF_MAN_ABS_DIRECT_OVERHEAD_DBLOCK(hdr, dblock);
+ dblock->blk_free_space = block_size -
+ (H5HF_MAN_ABS_DIRECT_OVERHEAD_SIZE(hdr, block_size) + H5HF_MAN_ABS_DIRECT_OBJ_PREFIX_LEN(hdr));
+ free_space = block_size - dblock->free_list_head;
+
+ /* Allocate buffer for block */
+/* XXX: Change to using free-list factories */
+ if((dblock->blk = H5FL_BLK_MALLOC(direct_block, block_size)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+#ifdef H5_USING_PURIFY
+HDmemset(dblock->blk, 0, dblock->size);
+#endif /* H5_USING_PURIFY */
+
+ /* Set up free list head */
+ if(NULL == (dblock->free_list = H5FL_MALLOC(H5HF_direct_free_head_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list head")
+ dblock->free_list->dirty = TRUE;
+
+ /* Set up free list node for all unused space in block */
+ if(NULL == (node = H5FL_MALLOC(H5HF_direct_free_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list node")
+
+ /* Set node's information */
+ node->size = free_space;
+ node->my_offset = dblock->free_list_head;
+ node->next_offset = 0;
+ node->prev = node->next = NULL;
+
+ /* Attach to free list head */
+/* XXX: Convert this list to a skip list? */
+ dblock->free_list->first = node;
+
+ /* Allocate space for the header on disk */
+ if(HADDR_UNDEF == (*addr_p = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)block_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block")
+
+ /* Create free list section node */
+ if(NULL == (sec_node = H5FL_MALLOC(H5HF_free_section_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list section")
+
+ /* Set section's information */
+ sec_node->sect_addr = block_off + node->my_offset;
+ /* (section size is "object size", without the metadata overhead) */
+ sec_node->sect_size = node->size - H5HF_MAN_ABS_DIRECT_OBJ_PREFIX_LEN(hdr);
+ sec_node->type = H5HF_SECT_SINGLE;
+ sec_node->u.single.dblock_addr = *addr_p;
+ sec_node->u.single.dblock_size = block_size;
+
+ /* Check what to do with section node */
+ if(ret_sec_node)
+ /* Pass back the pointer to the section instead of adding it to the free list */
+ *ret_sec_node = sec_node;
+ else {
+ /* Add new free space to the global list of space */
+ if(H5HF_flist_add(hdr->flist, sec_node, &sec_node->sect_size, &sec_node->sect_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add direct block free space to global list")
+ } /* end else */
+
+ /* Cache the new fractal heap direct block */
+ if(H5AC_set(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, *addr_p, dblock, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add fractal heap direct block to cache")
+
+done:
+ if(ret_value < 0)
+ if(dblock)
+ (void)H5HF_cache_dblock_dest(hdr->f, dblock);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_build_freelist
+ *
+ * Purpose: Parse the free list information for a direct block and build
+ * block's free list
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Feb 28 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_dblock_build_freelist(H5HF_direct_t *dblock, haddr_t dblock_addr)
+{
+ H5HF_direct_free_head_t *head = NULL; /* Pointer to free list head for block */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5HF_man_dblock_build_freelist)
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dblock);
+
+ /* Allocate head of list */
+ if(NULL == (head = H5FL_MALLOC(H5HF_direct_free_head_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list head")
+ head->dirty = FALSE;
+
+ /* Check for any nodes on free list */
+ if(dblock->free_list_head == 0)
+ head->first = NULL;
+ else {
+ H5HF_t *hdr; /* Pointer to shared heap header */
+ H5HF_free_section_t *sec_node; /* Pointer to free list section for block */
+ H5HF_direct_free_node_t *node = NULL; /* Pointer to free list node for block */
+ H5HF_direct_free_node_t *prev_node; /* Pointer to previous free list node for block */
+ hsize_t free_len; /* Length of free list info */
+ hsize_t next_off; /* Next node offset in block */
+ hsize_t prev_off; /* Prev node offset in block */
+ uint8_t *p; /* Temporary pointer to free node info */
+
+ /* Get the pointer to the shared heap info */
+ hdr = dblock->shared;
+
+ /* Point to first node in free list */
+ p = dblock->blk + dblock->free_list_head;
+
+ /* Decode information for first node on free list */
+ UINT64DECODE_VAR(p, free_len, dblock->blk_off_size);
+ UINT64DECODE_VAR(p, next_off, dblock->blk_off_size);
+
+ /* Allocate node on list */
+ if(NULL == (node = H5FL_MALLOC(H5HF_direct_free_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list node")
+
+ /* Set node's information */
+ node->size = free_len;
+ node->my_offset = dblock->free_list_head;
+ node->next_offset = next_off;
+ node->prev = node->next = NULL;
+
+ /* Attach to free list head */
+ head->first = node;
+
+ /* Set block's free space */
+ dblock->blk_free_space = free_len;
+
+ /* Create free list section node */
+ if(NULL == (sec_node = H5FL_MALLOC(H5HF_free_section_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list section")
+
+ /* Set section's information */
+ sec_node->sect_addr = dblock->block_off + node->my_offset;
+ /* (section size is "object size", without the metadata overhead) */
+ sec_node->sect_size = node->size - H5HF_MAN_ABS_DIRECT_OBJ_PREFIX_LEN(hdr);
+ sec_node->type = H5HF_SECT_SINGLE;
+ sec_node->u.single.dblock_addr = dblock_addr;
+ sec_node->u.single.dblock_size = dblock->size;
+
+ /* Add new free space to the global list of space */
+ if(H5HF_flist_add(hdr->flist, sec_node, &sec_node->sect_size, &sec_node->sect_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add direct block free space to global list")
+
+ /* Set up trailing node pointer */
+ prev_node = node;
+ prev_off = next_off;
+
+ /* Bring in rest of node on free list */
+ while(next_off != 0) {
+ /* Point to first node in free list */
+ p = dblock->blk + next_off;
+
+ /* Decode information for first node on free list */
+ UINT64DECODE_VAR(p, free_len, dblock->blk_off_size);
+ UINT64DECODE_VAR(p, next_off, dblock->blk_off_size);
+
+ /* Allocate node on list */
+ if(NULL == (node = H5FL_MALLOC(H5HF_direct_free_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list node")
+
+ /* Set node's information */
+ node->size = free_len;
+ node->my_offset = prev_off;
+ node->next_offset = next_off;
+ node->prev = prev_node;
+ node->next = NULL;
+
+ /* Adjust block's free space */
+ dblock->blk_free_space += free_len;
+
+ /* Create free list section node */
+ if(NULL == (sec_node = H5FL_MALLOC(H5HF_free_section_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for direct block free list section")
+
+ /* Set section's information */
+ sec_node->sect_addr = dblock->block_off + node->my_offset;
+ /* (section size is "object size", without the metadata overhead) */
+ sec_node->sect_size = node->size - H5HF_MAN_ABS_DIRECT_OBJ_PREFIX_LEN(hdr);
+ sec_node->type = H5HF_SECT_SINGLE;
+ sec_node->u.single.dblock_addr = dblock_addr;
+ sec_node->u.single.dblock_size = dblock->size;
+
+ /* Add new free space to the global list of space */
+ if(H5HF_flist_add(hdr->flist, sec_node, &sec_node->sect_size, &sec_node->sect_addr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add direct block free space to global list")
+
+ /* Update trailing info */
+ prev_node->next = node;
+ prev_off = next_off;
+
+ /* Advance to next node */
+ prev_node = node;
+ } /* end while */
+ } /* end else */
+
+ /* Assign free list head to block */
+ dblock->free_list = head;
+
+done:
+/* XXX: cleanup on failure? */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_build_freelist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_adj_free
+ *
+ * Purpose: Adjust the free space for a direct block, and it's parents
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 14 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_dblock_adj_free(hid_t dxpl_id, H5HF_direct_t *dblock, ssize_t amt)
+{
+ H5HF_t *hdr; /* Shared heap information */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5HF_man_dblock_adj_free)
+#ifdef QAK
+HDfprintf(stderr, "%s: amt = %Zd\n", FUNC, amt);
+#endif /* QAK */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(dblock);
+
+ /* Get the pointer to the shared heap header */
+ hdr = dblock->shared;
+
+ /* Adjust space available in block */
+ HDassert(amt > 0 || dblock->blk_free_space >= (size_t)-amt);
+ dblock->blk_free_space += amt;
+
+ /* Check if the parent info is set */
+ if(dblock->parent) {
+ H5HF_indirect_t *iblock; /* Block's parent */
+
+ /* Get the pointer to the shared parent indirect block */
+ iblock = dblock->parent;
+
+ /* Adjust this indirect block's child free space */
+#ifdef QAK
+HDfprintf(stderr, "%s: dblock->par_entry = %u\n", FUNC, dblock->par_entry);
+HDfprintf(stderr, "%s: iblock->block_off = %a\n", FUNC, iblock->block_off);
+HDfprintf(stderr, "%s: iblock->child_free_space = %Hu\n", FUNC, iblock->child_free_space);
+HDfprintf(stderr, "%s: iblock->ents[dblock->par_entry].free_space = %Hu\n", FUNC, iblock->ents[dblock->par_entry].free_space);
+#endif /* QAK */
+ HDassert(amt > 0 || iblock->ents[dblock->par_entry].free_space >= (hsize_t)-amt);
+ iblock->ents[dblock->par_entry].free_space += amt;
+ HDassert(amt > 0 || iblock->child_free_space >= (hsize_t)-amt);
+ iblock->child_free_space += amt;
+
+ /* Mark indirect block as dirty */
+ if(H5HF_iblock_dirty(dxpl_id, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
+
+ /* Modify the free space in parent block(s) */
+ while(iblock->parent) {
+ size_t par_entry; /* Entry in parent */
+
+ /* Get the pointer to the shared parent indirect block */
+ par_entry = iblock->par_entry;
+ iblock = iblock->parent;
+ HDassert(iblock);
+
+ /* Adjust this indirect block's child free space */
+ HDassert(amt > 0 || iblock->ents[par_entry].free_space >= (hsize_t)-amt);
+ iblock->ents[par_entry].free_space += amt;
+ HDassert(amt > 0 || iblock->child_free_space >= (hsize_t)-amt);
+ iblock->child_free_space += amt;
+
+ /* Mark indirect block as dirty */
+ if(H5HF_iblock_dirty(dxpl_id, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
+ } /* end while */
+ } /* end if */
+
+ /* Update shared heap free space header */
+ HDassert(amt > 0 || hdr->total_man_free >= (hsize_t)-amt);
+ hdr->total_man_free += amt;
+#ifdef QAK
+HDfprintf(stderr, "%s: hdr->total_man_free = %Hu\n", FUNC, hdr->total_man_free);
+#endif /* QAK */
+
+ /* Mark heap header as modified */
+ if(H5HF_hdr_dirty(dxpl_id, hdr) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_adj_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5HF_man_dblock_new
+ *
+ * Purpose: Create a direct block large enough to hold an object of
+ * the requested size
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 13 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5HF_man_dblock_new(H5HF_t *hdr, hid_t dxpl_id, size_t request)
+{
+ haddr_t dblock_addr; /* Address of new direct block */
+ size_t dblock_size; /* Size of new direct block */
+ size_t min_dblock_size; /* Min. size of direct block to allocate */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5HF_man_dblock_new)
+#ifdef QAK
+HDfprintf(stderr, "%s: request = %Zu\n", FUNC, request);
+#endif /* QAK */
+
+ /*
+ * Check arguments.
+ */
+ HDassert(hdr);
+ HDassert(request > 0);
+
+ /* Compute the min. size of the direct block needed to fulfill the request */
+ if(request < hdr->man_dtable.cparam.start_block_size)
+ min_dblock_size = hdr->man_dtable.cparam.start_block_size;
+ else {
+ min_dblock_size = 1 << (1 + H5V_log2_gen((hsize_t)request));
+ HDassert(min_dblock_size <= hdr->man_dtable.cparam.max_direct_size);
+ } /* end else */
+
+ /* Adjust the size of block needed to fulfill request, with overhead */
+#ifdef QAK
+HDfprintf(stderr, "%s: Check 1 - min_dblock_size = %Zu\n", FUNC, min_dblock_size);
+HDfprintf(stderr, "%s: H5HF_MAN_ABS_DIRECT_OVERHEAD_SIZE = %u\n", FUNC, H5HF_MAN_ABS_DIRECT_OVERHEAD_SIZE(hdr, hdr->man_dtable.cparam.start_block_size));
+HDfprintf(stderr, "%s: H5HF_MAN_ABS_DIRECT_OBJ_PREFIX_LEN = %u\n", FUNC, H5HF_MAN_ABS_DIRECT_OBJ_PREFIX_LEN(hdr));
+#endif /* QAK */
+ if((min_dblock_size - request) < (H5HF_MAN_ABS_DIRECT_OVERHEAD_SIZE(hdr, min_dblock_size)
+ + H5HF_MAN_ABS_DIRECT_OBJ_PREFIX_LEN(hdr)))
+ min_dblock_size *= 2;
+#ifdef QAK
+HDfprintf(stderr, "%s: Check 2 - min_dblock_size = %Zu\n", FUNC, min_dblock_size);
+#endif /* QAK */
+
+ /* Check if this is the first block in the heap */
+ if(!H5F_addr_defined(hdr->man_dtable.table_addr) &&
+ min_dblock_size == hdr->man_dtable.cparam.start_block_size) {
+ /* Create new direct block at starting offset */
+ dblock_size = hdr->man_dtable.cparam.start_block_size;
+ if(H5HF_man_dblock_create(dxpl_id, hdr, NULL, 0, dblock_size, (hsize_t)0, &dblock_addr, NULL) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block")
+
+#ifdef QAK
+HDfprintf(stderr, "%s: dblock_addr = %a\n", FUNC, dblock_addr);
+#endif /* QAK */
+
+ /* Point root at new direct block */
+ hdr->man_dtable.curr_root_rows = 0;
+ hdr->man_dtable.table_addr = dblock_addr;
+
+ /* Extend heap to cover new direct block */
+ if(H5HF_hdr_extend_heap(hdr, (hsize_t)dblock_size, hdr->man_dtable.row_dblock_free[0]) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block")
+ } /* end if */
+ /* Root entry already exists, go get indirect block for new direct block */
+ else {
+ H5HF_indirect_t *iblock; /* Pointer to indirect block to create */
+ haddr_t iblock_addr; /* Indirect block's address */
+ size_t dblock_entry; /* Direct entry for new direct block */
+ hsize_t dblock_off; /* Direct block offset in heap address space */
+
+ /* Find indirect block with room for block of correct size */
+ if(NULL == (iblock = H5HF_man_iblock_place_dblock(hdr, dxpl_id, min_dblock_size, &iblock_addr, &dblock_entry, &dblock_size)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to locate indirect block with space for direct block")
+#ifdef QAK
+HDfprintf(stderr, "%s: iblock_addr = %a\n", FUNC, iblock_addr);
+HDfprintf(stderr, "%s: dblock_entry = %Zu\n", FUNC, dblock_entry);
+HDfprintf(stderr, "%s: dblock_size = %Zu\n", FUNC, dblock_size);
+#endif /* QAK */
+
+ /* Compute the direct block's offset in the heap's address space */
+ dblock_off = iblock->block_off;
+ dblock_off += hdr->man_dtable.row_block_off[dblock_entry / hdr->man_dtable.cparam.width];
+ dblock_off += hdr->man_dtable.row_block_size[dblock_entry / hdr->man_dtable.cparam.width] * (dblock_entry % hdr->man_dtable.cparam.width);
+
+ /* Create new direct block at current location*/
+ if(H5HF_man_dblock_create(dxpl_id, hdr, iblock, dblock_entry, dblock_size, dblock_off, &dblock_addr, NULL) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block")
+
+#ifdef QAK
+HDfprintf(stderr, "%s: dblock_addr = %a\n", FUNC, dblock_addr);
+#endif /* QAK */
+
+ /* Point indirect block at new direct block */
+ iblock->ents[dblock_entry].addr = dblock_addr;
+
+ /* Mark indirect block as modified */
+ if(H5HF_iblock_dirty(dxpl_id, iblock) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark indirect block as dirty")
+
+ /* Release the indirect block (marked as dirty) */
+ if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, iblock_addr, iblock, H5AC__DIRTIED_FLAG) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5HF_man_dblock_new() */
+