/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "h5test.h"

/*
 * This file needs to access private datatypes from the H5HF package.
 * This file also needs to access the fractal heap testing code.
 */
#define H5HF_FRIEND /*suppress error about including H5HFpkg      */
#define H5HF_TESTING
#include "H5HFpkg.h" /* Fractal heaps            */

#define H5F_FRIEND /*suppress error about including H5Fpkg   */
#define H5F_TESTING
#include "H5Fpkg.h"

/* Other private headers that this test requires */
#include "H5CXprivate.h" /* API Contexts                         */
#include "H5MMprivate.h" /* Memory management            */
#include "H5VLprivate.h" /* Virtual Object Layer                     */
#include "H5VMprivate.h" /* Vectors and arrays             */

/* Max. testfile name length */
#define FHEAP_FILENAME_LEN 1024

/* Object size macros */
#define SMALL_OBJ_SIZE1 10
#define SMALL_OBJ_SIZE2 20
#define NUM_FILL_OBJS   11

/* "Small" heap creation parameters */
#define SMALL_DBLOCK_OVERHEAD      21          /* Overhead for direct blocks */
#define SMALL_CHECKSUM_DBLOCKS     true        /* Whether to checksum direct blocks */
#define SMALL_MAN_WIDTH            4           /* Managed obj. table width */
#define SMALL_MAN_START_BLOCK_SIZE 512         /* Managed obj. starting block size */
#define SMALL_MAN_MAX_DIRECT_SIZE  (64 * 1024) /* Managed obj. max. direct block size */
#define SMALL_MAN_MAX_INDEX        32          /* Managed obj. # of bits for total heap size */
#define SMALL_MAN_START_ROOT_ROWS  1           /* Managed obj. starting # of root indirect block rows */
#define SMALL_ID_LEN               0           /* "Default" heap ID length */
#define SMALL_STAND_SIZE           (SMALL_MAN_MAX_DIRECT_SIZE - SMALL_DBLOCK_OVERHEAD) /* Standalone obj. min. size */

/* "Large" heap creation parameters */
#define LARGE_DBLOCK_OVERHEAD 21         /* Overhead for direct blocks */
                                         /* (coincidentally the same size as for small direct blocks) */
#define LARGE_CHECKSUM_DBLOCKS     false /* Whether to checksum direct blocks */
#define LARGE_MAN_WIDTH            32    /* Managed obj. table width */
#define LARGE_MAN_START_BLOCK_SIZE 4096  /* Managed obj. starting block size */
#define LARGE_MAN_MAX_DIRECT_SIZE  (1024 * 1024) /* Managed obj. max. direct block size */
#define LARGE_MAN_MAX_INDEX        64            /* Managed obj. # of bits for total heap size */
#define LARGE_MAN_START_ROOT_ROWS  1             /* Managed obj. starting # of root indirect block rows */
#define LARGE_ID_LEN               0             /* "Default" heap ID length */
#define LARGE_STAND_SIZE           (LARGE_MAN_MAX_DIRECT_SIZE - LARGE_DBLOCK_OVERHEAD) /* Standalone obj. min. size */

/* Define this macro to enable all insertion tests */
/* #define ALL_INSERT_TESTS */

/* Heap metadata macros */
#define MAX_HEAP_ID_LEN   64 /* Max. # of bytes to use for heap ID */
#define HEAP_ID_LEN       7  /* # of bytes to use for heap ID */
#define SMALL_HEAP_ID_LEN 7  /* # of bytes to use for "small" heap's IDs */
#define LARGE_HEAP_ID_LEN 12 /* # of bytes to use for "large" heap's IDs */
/* Max. # of rows in root indirect block */
#define HEAP_MAX_ROOT_ROWS(fh) H5HF_get_max_root_rows(fh)
/* Width of doubling table for heap */
#define DTABLE_WIDTH(fh) H5HF_get_dtable_width_test(fh)
/* Max. # of direct block rows in any indirect block */
#define DTABLE_MAX_DROWS(fh) H5HF_get_dtable_max_drows_test(fh)
/* Max. # of direct block rows in a indirect block */
#define IBLOCK_MAX_DROWS(fh, pos) H5HF_get_iblock_max_drows_test(fh, pos)
/* Size of a direct block in a given row */
#define DBLOCK_SIZE(fh, r) H5HF_get_dblock_size_test(fh, r)
/* Free space in a direct block of a given row */
#define DBLOCK_FREE(fh, r) H5HF_get_dblock_free_test(fh, r)

/* The number of settings for testing: page buffering, file space strategy and persisting free-space */
#define NUM_PB_FS             6
#define PAGE_BUFFER_PAGE_SIZE 4096

static const char *FILENAME[] = {"fheap", NULL};

/* Types of tests to perform */
typedef enum {
    FHEAP_TEST_NORMAL, /* "Normal" test, with no testing parameters set */
    FHEAP_TEST_REOPEN, /* Set the reopen_heap flag */
    FHEAP_TEST_NTESTS  /* The number of test types, must be last */
} fheap_test_type_t;

/* Order to delete objects */
typedef enum {
    FHEAP_DEL_FORWARD, /* Delete objects from 0 -> nobjs */
    FHEAP_DEL_REVERSE, /* Delete objects from nobjs -> 0 */
    FHEAP_DEL_HEAP,    /* Delete entire heap at once */
    FHEAP_DEL_NDIRS    /* The number of different deletion orders, must be last */
} fheap_test_del_dir_t;

/* Order to delete objects */
typedef enum {
    FHEAP_DEL_DRAIN_ALL,  /* Don't drain half of objects first */
    FHEAP_DEL_DRAIN_HALF, /* Don't drain half of objects first */
    FHEAP_DEL_DRAIN_N     /* The number of different ways to drain, must be last */
} fheap_test_del_drain_t;

/* Size of objects for "bulk" filling heap blocks */
typedef enum {
    FHEAP_TEST_FILL_LARGE,  /* Fill heap blocks with "large" objects */
    FHEAP_TEST_FILL_SINGLE, /* Fill heap blocks with single object */
    FHEAP_TEST_FILL_N       /* The number of different ways to test filling heap blocks, must be last */
} fheap_test_fill_t;

/* Whether to compress blocks (during random tests) */
typedef enum {
    FHEAP_TEST_NO_COMPRESS, /* Don't compress direct blocks */
    FHEAP_TEST_COMPRESS,    /* Compress direct blocks */
    FHEAP_TEST_COMP_N       /* The number of different ways to test compressing heap blocks, must be last */
} fheap_test_comp_t;

/* Testing parameters */
typedef struct fheap_test_param_t {
    fheap_test_type_t    reopen_heap; /* Whether to re-open the heap during the test */
    fheap_test_del_dir_t del_dir;     /* Whether to delete objects forward or reverse */
    fheap_test_del_drain_t
                      drain_half; /* Whether to drain half of the objects & refill, when deleting objects */
    fheap_test_fill_t fill;       /* How to "bulk" fill heap blocks */
    size_t            actual_id_len; /* The actual length of heap IDs for a test */
    fheap_test_comp_t comp;          /* Whether to compress the blocks or not */
    hid_t             my_fcpl;       /* File creation property list with file space strategy setting */
} fheap_test_param_t;

/* Heap state information */
typedef struct fheap_heap_state_t {
    size_t  man_nobjs;      /* # of managed objects within heap */
    hsize_t man_size;       /* Size of managed object heap */
    hsize_t man_alloc_size; /* Size of managed object heap allocated */
    hsize_t man_free_space; /* Managed object free space within heap */
    size_t  huge_nobjs;     /* # of 'huge' objects within heap */
    hsize_t huge_size;      /* Size of 'huge' object heap */
    size_t  tiny_nobjs;     /* # of 'tiny' objects within heap */
    hsize_t tiny_size;      /* Size of 'tiny' object heap */
} fheap_heap_state_t;

/* Heap IDs to retain */
typedef struct fheap_heap_ids_t {
    size_t         num_ids;   /* # of heap IDs in array */
    size_t         alloc_ids; /* # of heap IDs allocated in array */
    unsigned char *ids;       /* Array of object heap IDs */
    size_t        *lens;      /* Array of object lengths */
    size_t        *offs;      /* Array of object offsets (in global shared write buffer) */
} fheap_heap_ids_t;

/* Local variables */
unsigned char *shared_wobj_g;             /* Pointer to shared write buffer for objects */
unsigned char *shared_robj_g;             /* Pointer to shared read buffer for objects */
size_t         shared_obj_size_g;         /* Size of shared objects */
unsigned char *shared_ids_g       = NULL; /* Array of shared object heap IDs */
size_t        *shared_lens_g      = NULL; /* Array of shared object lengths */
size_t        *shared_offs_g      = NULL; /* Array of shared object offsets */
size_t         shared_alloc_ids_g = 0;    /* # of shared heap IDs allocated in array */

/* Local routines */
static int init_small_cparam(H5HF_create_t *cparam);
static int init_large_cparam(H5HF_create_t *cparam);
static int check_stats(const H5HF_t *fh, const fheap_heap_state_t *state);
static int del_objs(H5F_t *f, H5HF_t **fh, fheap_test_param_t *tparam, fheap_heap_state_t *state,
                    fheap_heap_ids_t *keep_ids);

/*-------------------------------------------------------------------------
 * Function:  init_small_cparam
 *
 * Purpose:   Initialize heap creation parameter structure with small
 *              settings
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
init_small_cparam(H5HF_create_t *cparam)
{
    /* Wipe out background */
    memset(cparam, 0, sizeof(H5HF_create_t));

    /* General parameters */
    cparam->id_len           = SMALL_ID_LEN;
    cparam->max_man_size     = SMALL_STAND_SIZE;
    cparam->checksum_dblocks = SMALL_CHECKSUM_DBLOCKS;

    /* Managed object doubling-table parameters */
    cparam->managed.width            = SMALL_MAN_WIDTH;
    cparam->managed.start_block_size = SMALL_MAN_START_BLOCK_SIZE;
    cparam->managed.max_direct_size  = SMALL_MAN_MAX_DIRECT_SIZE;
    cparam->managed.max_index        = SMALL_MAN_MAX_INDEX;
    cparam->managed.start_root_rows  = SMALL_MAN_START_ROOT_ROWS;

    return (0);
} /* init_small_cparam() */

/*-------------------------------------------------------------------------
 * Function:  init_large_cparam
 *
 * Purpose:   Initialize heap creation parameter structure with large
 *              settings
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
init_large_cparam(H5HF_create_t *cparam)
{
    /* Wipe out background */
    memset(cparam, 0, sizeof(H5HF_create_t));

    /* General parameters */
    cparam->id_len           = LARGE_ID_LEN;
    cparam->max_man_size     = LARGE_STAND_SIZE;
    cparam->checksum_dblocks = LARGE_CHECKSUM_DBLOCKS;

    /* Managed object doubling-table parameters */
    cparam->managed.width            = LARGE_MAN_WIDTH;
    cparam->managed.start_block_size = LARGE_MAN_START_BLOCK_SIZE;
    cparam->managed.max_direct_size  = LARGE_MAN_MAX_DIRECT_SIZE;
    cparam->managed.max_index        = LARGE_MAN_MAX_INDEX;
    cparam->managed.start_root_rows  = LARGE_MAN_START_ROOT_ROWS;

    return (0);
} /* init_large_cparam() */

/*-------------------------------------------------------------------------
 * Function:  check_stats
 *
 * Purpose:   Verify stats for a heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
check_stats(const H5HF_t *fh, const fheap_heap_state_t *state)
{
    H5HF_stat_t heap_stats; /* Statistics about the heap */

    /* Get statistics for heap and verify they are correct */
    if (H5HF_stat_info(fh, &heap_stats) < 0)
        FAIL_STACK_ERROR;
    if (heap_stats.man_nobjs != state->man_nobjs) {
        fprintf(stdout, "heap_stats.man_nobjs = %" PRIuHSIZE ", state->man_nobjs = %zu\n",
                heap_stats.man_nobjs, state->man_nobjs);
        TEST_ERROR;
    } /* end if */
    if (heap_stats.man_size != state->man_size) {
        fprintf(stdout, "heap_stats.man_size = %" PRIuHSIZE ", state->man_size = %" PRIuHSIZE "\n",
                heap_stats.man_size, state->man_size);
        TEST_ERROR;
    } /* end if */
    if (heap_stats.man_alloc_size != state->man_alloc_size) {
        fprintf(stdout,
                "heap_stats.man_alloc_size = %" PRIuHSIZE ", state->man_alloc_size = %" PRIuHSIZE "\n",
                heap_stats.man_alloc_size, state->man_alloc_size);
        TEST_ERROR;
    } /* end if */
    if (heap_stats.man_free_space != state->man_free_space) {
        fprintf(stdout,
                "heap_stats.man_free_space = %" PRIuHSIZE ", state->man_free_space = %" PRIuHSIZE "\n",
                heap_stats.man_free_space, state->man_free_space);
        TEST_ERROR;
    } /* end if */
    if (heap_stats.huge_nobjs != state->huge_nobjs) {
        fprintf(stdout, "heap_stats.huge_nobjs = %" PRIuHSIZE ", state->huge_nobjs = %zu\n",
                heap_stats.huge_nobjs, state->huge_nobjs);
        TEST_ERROR;
    } /* end if */
    if (heap_stats.huge_size != state->huge_size) {
        fprintf(stdout, "heap_stats.huge_size = %" PRIuHSIZE ", state->huge_size = %" PRIuHSIZE "\n",
                heap_stats.huge_size, state->huge_size);
        TEST_ERROR;
    } /* end if */
    if (heap_stats.tiny_nobjs != state->tiny_nobjs) {
        fprintf(stdout, "heap_stats.tiny_nobjs = %" PRIuHSIZE ", state->tiny_nobjs = %zu\n",
                heap_stats.tiny_nobjs, state->tiny_nobjs);
        TEST_ERROR;
    } /* end if */
    if (heap_stats.tiny_size != state->tiny_size) {
        fprintf(stdout, "heap_stats.tiny_size = %" PRIuHSIZE ", state->tiny_size = %" PRIuHSIZE "\n",
                heap_stats.tiny_size, state->tiny_size);
        TEST_ERROR;
    } /* end if */

    /* All tests passed */
    return (0);

error:
    return (1);
} /* check_stats() */

/*-------------------------------------------------------------------------
 * Function:  op_memcpy
 *
 * Purpose:   Perform 'memcpy' for an object
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static herr_t
op_memcpy(const void *obj, size_t obj_len, void *op_data)
{
    /* Make copy of the object */
    memcpy(op_data, obj, obj_len);

    return (SUCCEED);
} /* op_memcpy() */

/*-------------------------------------------------------------------------
 * Function:  add_obj
 *
 * Purpose:   Add an object to heap
 *
 * Note:        The following fields in the 'state' structure are set to
 *              the values expected _after_ any block created for the object:
 *                      man_size
 *                      man_alloc_size
 *                      man_free_space
 *
 *              The following fields in the 'state' structure are set to
 *              the current state, before any block has been created:
 *                      nobjs
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
add_obj(H5HF_t *fh, size_t obj_off, size_t obj_size, fheap_heap_state_t *state, fheap_heap_ids_t *keep_ids)
{
    unsigned char  heap_id[MAX_HEAP_ID_LEN]; /* Heap ID for object inserted */
    unsigned char *obj;                      /* Buffer for object to insert */
    size_t         id_len;                   /* Size of fractal heap IDs */
    size_t         robj_size;                /* Object size read in */

    /* Sanity check */
    assert(fh);

    /* Initialize object buffer */
    obj = &shared_wobj_g[obj_off];

    /* Get information about heap ID lengths */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > MAX_HEAP_ID_LEN)
        TEST_ERROR;

    /* Insert object */
    memset(heap_id, 0, id_len);
    if (H5HF_insert(fh, obj_size, obj, heap_id) < 0)
        FAIL_STACK_ERROR;

    /* Check for tracking the heap's state */
    if (state) {
        size_t tiny_max_len;      /* Max. length of tiny objects */
        bool   tiny_len_extended; /* Do tiny objects use two bytes for the length? */

        /* Check information about tiny objects */
        if (H5HF_get_tiny_info_test(fh, &tiny_max_len, &tiny_len_extended) < 0)
            FAIL_STACK_ERROR;

        /* Adjust state of heap */
        if (obj_size <= tiny_max_len) {
            state->tiny_nobjs++;
            state->tiny_size += obj_size;
        } /* end if */
        else {
            state->man_nobjs++;
            state->man_free_space -= obj_size;
        } /* end else */

        /* Check free space left in heap */
        if (check_stats(fh, state))
            TEST_ERROR;
    } /* end if */

    /* Read in object */
    if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    if (H5HF_read(fh, heap_id, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(obj, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* If the heap IDs are to be retained, append them to the list */
    if (keep_ids) {
        /* Check for needing to increase size of heap ID array */
        if (keep_ids->num_ids + 1 > keep_ids->alloc_ids) {
            unsigned char *tmp_ids;
            size_t        *tmp_lens;
            size_t        *tmp_offs;

            keep_ids->alloc_ids = MAX(1024, (keep_ids->alloc_ids * 2));
            if (NULL ==
                (tmp_ids = (unsigned char *)H5MM_realloc(keep_ids->ids, id_len * keep_ids->alloc_ids)))
                TEST_ERROR;
            keep_ids->ids = tmp_ids;
            if (NULL ==
                (tmp_lens = (size_t *)H5MM_realloc(keep_ids->lens, sizeof(size_t) * keep_ids->alloc_ids)))
                TEST_ERROR;
            keep_ids->lens = tmp_lens;
            if (NULL ==
                (tmp_offs = (size_t *)H5MM_realloc(keep_ids->offs, sizeof(size_t) * keep_ids->alloc_ids)))
                TEST_ERROR;
            keep_ids->offs = tmp_offs;
        } /* end if */

        /* Append the object info onto the array */
        memcpy(&keep_ids->ids[keep_ids->num_ids * id_len], heap_id, id_len);
        keep_ids->lens[keep_ids->num_ids] = obj_size;
        keep_ids->offs[keep_ids->num_ids] = obj_off;

        /* Increment the number of IDs kept */
        keep_ids->num_ids++;
    } /* end if */

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* add_obj() */

/* Return a string describing the kind of deletion to perform. */
static const char *
get_del_string(const fheap_test_param_t *tparam)
{
    /* Remove half of total objects from heap */
    if (tparam->del_dir == FHEAP_DEL_FORWARD)
        if (tparam->drain_half == FHEAP_DEL_DRAIN_ALL)
            return "(all - forward)";
        else
            return "(half, refill, all - forward)";
    else if (tparam->del_dir == FHEAP_DEL_REVERSE)
        if (tparam->drain_half == FHEAP_DEL_DRAIN_ALL)
            return "(all - reverse)";
        else
            return "(half, refill, all - reverse)";
    else
        return "(all - deleting heap)";

} /* get_del_string() */

/*-------------------------------------------------------------------------
 * Function:    get_fill_size
 *
 * Purpose:     Retrieve the size of objects to "bulk" fill blocks with
 *
 * Return:      Size of object to pass down to "fill_heap" routine on
 *              success/can't fail
 *
 *-------------------------------------------------------------------------
 */
H5_ATTR_PURE static size_t
get_fill_size(const fheap_test_param_t *tparam)
{
    switch (tparam->fill) {
        case FHEAP_TEST_FILL_LARGE:
            return ((size_t)(-1));

        case FHEAP_TEST_FILL_SINGLE:
            return ((size_t)0);

        case FHEAP_TEST_FILL_N:
        default:
            assert(0 && "Unknown bulk fill type?!?");
    } /* end switch */

    return (0);
} /* get_fill_size() */

/*-------------------------------------------------------------------------
 * Function:  begin_test
 *
 * Purpose:   Perform common "test being" operations
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
begin_test(fheap_test_param_t *tparam, const char *base_desc, fheap_heap_ids_t *keep_ids, size_t *fill_size)
{
    char       *test_desc; /* Test description */
    const char *del_str = get_del_string(tparam);

    /*
     * Test filling & removing all (small) objects from root direct block of absolute heap
     */
    size_t test_desc_len = strlen(base_desc) + sizeof(" ") + strlen(del_str);
    test_desc            = H5MM_malloc(test_desc_len);
    (void)snprintf(test_desc, test_desc_len, "%s %s", base_desc, del_str);

    TESTING(test_desc);
    H5MM_xfree(test_desc);

    /* Initialize the heap ID structure */
    memset(keep_ids, 0, sizeof(fheap_heap_ids_t));

    /* Retrieve "bulk" filling object size */
    if (fill_size)
        *fill_size = get_fill_size(tparam);

    /* Success */
    return (0);
} /* end begin_test() */

/*-------------------------------------------------------------------------
 * Function:  reopen_file
 *
 * Purpose:   Perform common "re-open" operations on file & heap for testing
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
reopen_file(hid_t *file, H5F_t **f, const char *filename, hid_t fapl, H5HF_t **fh, haddr_t fh_addr,
            const fheap_test_param_t *tparam)
{
    /* Check for closing & re-opening the heap */
    /* (actually will close & re-open the file as well) */
    if (tparam->reopen_heap) {
        /* Close heap */
        if (H5HF_close(*fh) < 0)
            FAIL_STACK_ERROR;
        *fh = NULL;

        /* Close file */
        if (H5Fclose(*file) < 0)
            FAIL_STACK_ERROR;
        *file = (-1);
        *f    = NULL;

        /* Re-open the file */
        if ((*file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
            FAIL_STACK_ERROR;

        /* Get a pointer to the internal file object */
        if (NULL == (*f = (H5F_t *)H5VL_object(*file)))
            FAIL_STACK_ERROR;

        /* Ignore metadata tags in the file's cache */
        if (H5AC_ignore_tags(*f) < 0)
            FAIL_STACK_ERROR;

        /* Re-open heap */
        if (NULL == (*fh = H5HF_open(*f, fh_addr)))
            FAIL_STACK_ERROR;
    } /* end if */

    /* Success */
    return (0);

error:
    return (-1);
} /* end reopen_file() */

/*-------------------------------------------------------------------------
 * Function:  open_heap
 *
 * Purpose:   Perform common "open" operations on file & heap for testing
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
open_heap(char *filename, hid_t fapl, const H5HF_create_t *cparam, const fheap_test_param_t *tparam,
          hid_t *file, H5F_t **f, H5HF_t **fh, haddr_t *fh_addr, fheap_heap_state_t *state,
          h5_stat_size_t *empty_size)
{
    size_t id_len; /* Size of fractal heap IDs */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, (size_t)FHEAP_FILENAME_LEN);

    /* Create the file to work on */
    if ((*file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Check for deleting the entire heap */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        /* Get a pointer to the internal file object */
        if (NULL == (*f = (H5F_t *)H5VL_object(*file)))
            FAIL_STACK_ERROR;

        /* Ignore metadata tags in the file's cache */
        if (H5AC_ignore_tags(*f) < 0)
            FAIL_STACK_ERROR;

        /* Create absolute heap */
        if (NULL == (*fh = H5HF_create(*f, cparam)))
            FAIL_STACK_ERROR;
        if (H5HF_get_id_len(*fh, &id_len) < 0)
            FAIL_STACK_ERROR;
        if (id_len > tparam->actual_id_len)
            TEST_ERROR;
        if (H5HF_get_heap_addr(*fh, fh_addr) < 0)
            FAIL_STACK_ERROR;
        if (!H5_addr_defined(*fh_addr))
            TEST_ERROR;
        memset(state, 0, sizeof(fheap_heap_state_t));
        if (check_stats(*fh, state))
            TEST_ERROR;

        /* Prepare for querying the size of a file with an empty heap */

        /* Close (empty) heap */
        if (H5HF_close(*fh) < 0)
            FAIL_STACK_ERROR;
        *fh = NULL;
    } /* end if */

    /* Close file */
    if (H5Fclose(*file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of a file w/empty heap*/
    if ((*empty_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((*file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (*f = (H5F_t *)H5VL_object(*file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(*f) < 0)
        FAIL_STACK_ERROR;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Create absolute heap */
        if (NULL == (*fh = H5HF_create(*f, cparam)))
            FAIL_STACK_ERROR;
        if (H5HF_get_id_len(*fh, &id_len) < 0)
            FAIL_STACK_ERROR;
        if (id_len > tparam->actual_id_len)
            TEST_ERROR;
        if (H5HF_get_heap_addr(*fh, fh_addr) < 0)
            FAIL_STACK_ERROR;
        if (!H5_addr_defined(*fh_addr))
            TEST_ERROR;
        memset(state, 0, sizeof(fheap_heap_state_t));
        if (check_stats(*fh, state))
            TEST_ERROR;
    } /* end if */
    else {
        /* Re-open heap */
        if (NULL == (*fh = H5HF_open(*f, *fh_addr)))
            FAIL_STACK_ERROR;
    } /* end else */

    /* Success */
    return (0);

error:
    return (-1);
} /* end open_heap() */

/*-------------------------------------------------------------------------
 * Function:  reopen_heap
 *
 * Purpose:   Perform common "re-open" operations on heap for testing
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
reopen_heap(H5F_t *f, H5HF_t **fh, haddr_t fh_addr, const fheap_test_param_t *tparam)
{
    /* Check for closing & re-opening the heap */
    if (tparam->reopen_heap) {
        /* Close (empty) heap */
        if (H5HF_close(*fh) < 0)
            FAIL_STACK_ERROR;
        *fh = NULL;

        /* Re-open heap */
        if (NULL == (*fh = H5HF_open(f, fh_addr)))
            FAIL_STACK_ERROR;
    } /* end if */

    /* Success */
    return 0;

error:
    return -1;
} /* end reopen_heap() */

/*-------------------------------------------------------------------------
 * Function:  close_heap
 *
 * Purpose:   Perform common "close" operations on file & heap for testing
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
close_heap(char *filename, hid_t fapl, fheap_test_param_t *tparam, hid_t file, H5F_t *f, H5HF_t **fh,
           haddr_t fh_addr, fheap_heap_state_t *state, fheap_heap_ids_t *keep_ids, h5_stat_size_t empty_size)
{
    h5_stat_size_t file_size; /* Size of file currently */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    if (check_stats(*fh, state))
        TEST_ERROR;

    /* Check for deleting the objects in the heap */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        /* Delete objects inserted (either forward or reverse order) */
        if (del_objs(f, fh, tparam, state, keep_ids))
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the fractal heap */
    if (H5HF_close(*fh) < 0)
        FAIL_STACK_ERROR;
    *fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Success */
    return (0);

error:
    return (-1);
} /* end close_heap() */

/*-------------------------------------------------------------------------
 * Function:  del_objs_half_refill
 *
 * Purpose:   Remove half of objects from heap and refill
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
del_objs_half_refill(H5F_t *f, H5HF_t **fh, fheap_test_param_t *tparam, fheap_heap_ids_t *keep_ids)
{
    unsigned char *wobj;                  /* Buffer for object to insert */
    haddr_t        fh_addr = HADDR_UNDEF; /* Address of fractal heap */
    size_t         id_len;                /* Size of fractal heap IDs */
    size_t         half_nobjs;            /* Half of total # of objects */
    size_t         obj_idx;               /* Index of the object to remove */
    size_t         u;                     /* Local index variable */

    /* Sanity check */
    assert(fh);
    assert(*fh);
    assert(keep_ids);

    /* Check for closing & re-opening the heap */
    if (tparam->reopen_heap) {
        if (H5HF_get_heap_addr(*fh, &fh_addr) < 0)
            FAIL_STACK_ERROR;
        if (!H5_addr_defined(fh_addr))
            TEST_ERROR;
    } /* end if */

    /* Get information about heap ID lengths */
    if (H5HF_get_id_len(*fh, &id_len) < 0)
        FAIL_STACK_ERROR;

    /* Remove half of total objects from heap */
    if (tparam->del_dir == FHEAP_DEL_FORWARD)
        obj_idx = 0;
    else
        obj_idx = keep_ids->num_ids - 1;
    half_nobjs = keep_ids->num_ids / 2;
    for (u = 0; u < half_nobjs; u++) {
        /* Remove object from heap */
        if (H5HF_remove(*fh, &keep_ids->ids[id_len * obj_idx]) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Adjust index of object to delete next */
        if (tparam->del_dir == FHEAP_DEL_FORWARD)
            obj_idx++;
        else
            obj_idx--;
    } /* end for */

    /* Re-insert half of total objects back into heap */
    if (tparam->del_dir == FHEAP_DEL_FORWARD)
        obj_idx = 0;
    else
        obj_idx = keep_ids->num_ids - 1;
    for (u = 0; u < half_nobjs; u++) {
        /* Re-insert object */
        wobj = &shared_wobj_g[keep_ids->offs[obj_idx]];
        if (H5HF_insert(*fh, keep_ids->lens[obj_idx], wobj, &keep_ids->ids[id_len * obj_idx]) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Adjust index of object to delete next */
        if (tparam->del_dir == FHEAP_DEL_FORWARD)
            obj_idx++;
        else
            obj_idx--;
    } /* end for */

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* del_objs_half_refill() */

/*-------------------------------------------------------------------------
 * Function:  del_objs
 *
 * Purpose:   Remove objects from heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
del_objs(H5F_t *f, H5HF_t **fh, fheap_test_param_t *tparam, fheap_heap_state_t *state,
         fheap_heap_ids_t *keep_ids)
{
    haddr_t fh_addr = HADDR_UNDEF; /* Address of fractal heap */
    size_t  id_len;                /* Size of fractal heap IDs */
    size_t  obj_idx;               /* Index of the object to remove */
    size_t  u;                     /* Local index variable */

    /* Sanity check */
    assert(fh);
    assert(*fh);
    assert(state);
    assert(keep_ids);

    /* Check for first deleting half of objects & then re-inserting them */
    if (tparam->drain_half == FHEAP_DEL_DRAIN_HALF)
        if (del_objs_half_refill(f, fh, tparam, keep_ids))
            TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (tparam->reopen_heap) {
        if (H5HF_get_heap_addr(*fh, &fh_addr) < 0)
            FAIL_STACK_ERROR;
        if (!H5_addr_defined(fh_addr))
            TEST_ERROR;
    } /* end if */

    /* Get information about heap ID lengths */
    if (H5HF_get_id_len(*fh, &id_len) < 0)
        FAIL_STACK_ERROR;

    /* Remove all objects from heap */
    if (tparam->del_dir == FHEAP_DEL_FORWARD)
        obj_idx = 0;
    else
        obj_idx = keep_ids->num_ids - 1;
    for (u = 0; u < keep_ids->num_ids; u++) {
        /* Remove object from heap */
        if (H5HF_remove(*fh, &keep_ids->ids[id_len * obj_idx]) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Adjust index of object to delete next */
        if (tparam->del_dir == FHEAP_DEL_FORWARD)
            obj_idx++;
        else
            obj_idx--;
    } /* end for */

    /* Heap should be completely empty now, reset our state */
    memset(state, 0, sizeof(fheap_heap_state_t));

    /* Check up on heap... */
    if (check_stats(*fh, state))
        TEST_ERROR;

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* del_objs() */

/*-------------------------------------------------------------------------
 * Function:  fill_heap
 *
 * Purpose:   Insert (small) objects to fill up the free space in a heap block
 *
 * Note:        The following fields in the 'state' structure are set to
 *              the values expected _after_ the block has been created:
 *                      man_size
 *                      man_alloc_size
 *                      man_free_space
 *
 *              The following fields in the 'state' structure are set to
 *              the current state, before the block has been created:
 *                      nobjs
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_heap(H5HF_t *fh, unsigned block_row, size_t obj_size, fheap_heap_state_t *state,
          fheap_heap_ids_t *keep_ids)
{
    unsigned char *wobj;         /* Buffer for object to insert */
    unsigned char *curr_id_ptr;  /* Pointer into shared ID array */
    size_t        *curr_len_ptr; /* Pointer into shared length array */
    size_t        *curr_off_ptr; /* Pointer into shared offset array */
    size_t         num_ids = 0;  /* # of heap IDs in array */
    size_t         data_size;    /* Size of data portion of heap block */
    size_t         last_obj_len; /* Size of last object inserted into heap */
    size_t         obj_off;      /* Offset of object in shared write buffer */
    size_t         id_len;       /* Size of fractal heap IDs */
    unsigned       u;            /* Local index variable */

    /* Sanity check */
    assert(fh);
    assert(state);
    assert(obj_size + 256 < shared_obj_size_g);

    /* Initialize starting information */
    data_size    = (size_t)DBLOCK_FREE(fh, block_row);
    wobj         = shared_wobj_g;
    curr_id_ptr  = shared_ids_g;
    curr_len_ptr = shared_lens_g;
    curr_off_ptr = shared_offs_g;
    obj_off      = 0;

    /* Get information about heap ID lengths */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;

    /* Check for some "magic" object sizes */
    if (obj_size == 0)
        obj_size = data_size;
    else if (obj_size == (size_t)(-1))
        obj_size = (data_size / NUM_FILL_OBJS) + 1;

    /* Loop over inserting objects into the root direct block, until there's no more space */
    while (data_size >= obj_size) {
        /* Increment object count */
        num_ids++;

        /* Check for needing to increase size of heap ID array */
        if (num_ids > shared_alloc_ids_g) {
            shared_alloc_ids_g = MAX(1024, (shared_alloc_ids_g * 2));
            if (NULL ==
                (shared_ids_g = (unsigned char *)H5MM_realloc(shared_ids_g, id_len * shared_alloc_ids_g)))
                TEST_ERROR;
            if (NULL ==
                (shared_lens_g = (size_t *)H5MM_realloc(shared_lens_g, sizeof(size_t) * shared_alloc_ids_g)))
                TEST_ERROR;
            if (NULL ==
                (shared_offs_g = (size_t *)H5MM_realloc(shared_offs_g, sizeof(size_t) * shared_alloc_ids_g)))
                TEST_ERROR;
            curr_id_ptr  = &shared_ids_g[(num_ids - 1) * id_len];
            curr_len_ptr = &shared_lens_g[(num_ids - 1)];
            curr_off_ptr = &shared_offs_g[(num_ids - 1)];
        } /* end if */

        /* Insert object */
        if (H5HF_insert(fh, obj_size, wobj, curr_id_ptr) < 0)
            FAIL_STACK_ERROR;
        *curr_len_ptr = obj_size;
        *curr_off_ptr = obj_off;

        /* Adjust state of heap */
        state->man_nobjs++;
        state->man_free_space -= obj_size;

        /* Check stats for heap */
        if (check_stats(fh, state))
            TEST_ERROR;

        /* Adjust object & ID pointers */
        wobj++;
        obj_off++;
        if (obj_off > 255) {
            wobj    = shared_wobj_g;
            obj_off = 0;
        } /* end if */
        curr_id_ptr += id_len;
        curr_len_ptr++;
        curr_off_ptr++;

        /* Decrement space left in block */
        data_size -= obj_size;
    } /* end while */

    /* Check for adding smaller last object to heap block */
    if (data_size > 0) {
        /* Set size of last object in block */
        last_obj_len = data_size;

        /* Increment object count */
        num_ids++;

        /* Check for needing to increase size of heap ID array */
        if (num_ids > shared_alloc_ids_g) {
            shared_alloc_ids_g = MAX(1024, (shared_alloc_ids_g * 2));
            if (NULL ==
                (shared_ids_g = (unsigned char *)H5MM_realloc(shared_ids_g, id_len * shared_alloc_ids_g)))
                TEST_ERROR;
            if (NULL ==
                (shared_lens_g = (size_t *)H5MM_realloc(shared_lens_g, sizeof(size_t) * shared_alloc_ids_g)))
                TEST_ERROR;
            if (NULL ==
                (shared_offs_g = (size_t *)H5MM_realloc(shared_offs_g, sizeof(size_t) * shared_alloc_ids_g)))
                TEST_ERROR;
            curr_id_ptr  = &shared_ids_g[(num_ids - 1) * id_len];
            curr_len_ptr = &shared_lens_g[(num_ids - 1)];
            curr_off_ptr = &shared_offs_g[(num_ids - 1)];
        } /* end if */

        /* Insert last object into the heap, using the remaining free space */
        if (H5HF_insert(fh, last_obj_len, wobj, curr_id_ptr) < 0)
            FAIL_STACK_ERROR;
        *curr_len_ptr = last_obj_len;
        *curr_off_ptr = obj_off;

        /* Adjust state of heap */
        state->man_nobjs++;
        state->man_free_space -= last_obj_len;

        /* Verify that the heap is full */
        if (check_stats(fh, state))
            TEST_ERROR;
    } /* end if */
    else
        last_obj_len = obj_size; /* Normal sized last object */

    /* Verify reading the objects written out */

    /* Verify all the objects */
    wobj         = shared_wobj_g;
    curr_id_ptr  = shared_ids_g;
    curr_len_ptr = shared_lens_g;
    curr_off_ptr = shared_offs_g;
    for (u = 0; u < num_ids; u++) {
        /* Read in object */
        if (H5HF_read(fh, curr_id_ptr, shared_robj_g) < 0)
            FAIL_STACK_ERROR;

        /* Check that object is correct */
        wobj = &shared_wobj_g[*curr_off_ptr];
        if (memcmp(wobj, shared_robj_g, *curr_len_ptr) != 0)
            TEST_ERROR;

        /* Adjust object & ID pointers */
        curr_id_ptr += id_len;
        curr_len_ptr++;
        curr_off_ptr++;
    } /* end for */

    /* If the heap IDs are to be retained, append them to the list */
    if (keep_ids) {
        /* Check for needing to increase size of heap ID array */
        if (keep_ids->num_ids + num_ids > keep_ids->alloc_ids) {
            keep_ids->alloc_ids = MAX(1024, (keep_ids->alloc_ids * 2));
            if (NULL ==
                (keep_ids->ids = (unsigned char *)H5MM_realloc(keep_ids->ids, id_len * keep_ids->alloc_ids)))
                TEST_ERROR;
            if (NULL == (keep_ids->lens =
                             (size_t *)H5MM_realloc(keep_ids->lens, sizeof(size_t) * keep_ids->alloc_ids)))
                TEST_ERROR;
            if (NULL == (keep_ids->offs =
                             (size_t *)H5MM_realloc(keep_ids->offs, sizeof(size_t) * keep_ids->alloc_ids)))
                TEST_ERROR;
        } /* end if */

        /* Append the IDs onto the array */
        memcpy(&keep_ids->ids[keep_ids->num_ids * id_len], shared_ids_g, (num_ids * id_len));
        memcpy(&keep_ids->lens[keep_ids->num_ids], shared_lens_g, (num_ids * sizeof(size_t)));
        memcpy(&keep_ids->offs[keep_ids->num_ids], shared_offs_g, (num_ids * sizeof(size_t)));

        /* Increment the number of IDs kept */
        keep_ids->num_ids += num_ids;
    } /* end if */

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_heap() */

/*-------------------------------------------------------------------------
 * Function:  fill_root_row
 *
 * Purpose:   Fill up a row of direct blocks in the root indirect block
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_root_row(H5HF_t *fh, unsigned row, size_t obj_size, fheap_heap_state_t *state,
              fheap_heap_ids_t *keep_ids)
{
    hsize_t  first_free_space; /* Size of free space in heap after the first block */
    hsize_t  all_free_space;   /* Size of free space in heap after all blocks */
    hsize_t  first_heap_size;  /* Total size of the heap after the first block */
    hsize_t  all_heap_size;    /* Total size of the heap after all blocks */
    size_t   block_size;       /* Block size for row */
    size_t   block_free;       /* Free space in empty block of this row */
    unsigned width;            /* Width of heap's doubling table */
    unsigned expand_rows;      /* # of rows to expand heap by */
    unsigned u;                /* Local index variable */

    /* Sanity check */
    assert(fh);
    assert(state);

    /* Get some information for the heap */
    block_size = (size_t)DBLOCK_SIZE(fh, row);
    block_free = (size_t)DBLOCK_FREE(fh, row);
    width      = DTABLE_WIDTH(fh);

    /* Compute the number of rows to expand heap by */
    if (row < 2)
        expand_rows = 1;
    else if (POWER_OF_TWO(row))
        expand_rows = row;
    else
        expand_rows = 0;

    /* Compute first block & all blocks heap size & free space */
    if (state->man_size == 0) {
        first_heap_size  = block_size;
        first_free_space = block_free;
        all_heap_size    = width * block_size;
        all_free_space   = (width - 1) * block_free;
    } /* end if */
    else if (expand_rows == 0) {
        all_heap_size    = state->man_size;
        all_free_space   = state->man_free_space;
        first_heap_size  = all_heap_size;
        first_free_space = all_free_space;
        all_free_space -= block_free; /* Account for shift from first free space */
    }                                 /* end if */
    else {
        all_heap_size  = state->man_size;
        all_free_space = 0;
        for (u = 0; u < expand_rows; u++) {
            all_heap_size += width * DBLOCK_SIZE(fh, row + u);
            all_free_space += width * DBLOCK_FREE(fh, row + u);
        } /* end for */
        first_heap_size  = all_heap_size;
        first_free_space = all_free_space;
        all_free_space -= block_free; /* Account for shift from first free space */
    }                                 /* end else */

    /* Loop over filling direct blocks, until root indirect row is full */
    state->man_size       = first_heap_size;
    state->man_free_space = first_free_space;
    for (u = 0; u < width; u++) {
        /* Set heap's size & free space correctly */
        if (u == 1) {
            state->man_size       = all_heap_size;
            state->man_free_space = all_free_space;
        } /* end if */

        /* Account for new block added */
        state->man_alloc_size += block_size;

        /* Fill a direct heap block up */
        if (fill_heap(fh, row, obj_size, state, keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_root_row() */

/*-------------------------------------------------------------------------
 * Function:  fill_partial row
 *
 * Purpose:   Fill up part of a row of direct blocks in an non-root indirect block
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_partial_row(H5HF_t *fh, unsigned row, unsigned width, size_t obj_size, fheap_heap_state_t *state,
                 fheap_heap_ids_t *keep_ids)
{
    size_t   block_size; /* Size of direct block in this row */
    unsigned u;          /* Local index variable */

    /* Sanity check */
    assert(fh);
    assert(state);

    /* Get some information for the heap */
    block_size = (size_t)DBLOCK_SIZE(fh, row);

    /* Loop over filling direct blocks, until indirect row is full */
    for (u = 0; u < width; u++) {
        /* Adjust stats for new block */
        state->man_alloc_size += block_size;

        /* Fill a direct heap block up */
        if (fill_heap(fh, row, obj_size, state, keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_partial_row() */

/*-------------------------------------------------------------------------
 * Function:  fill_row
 *
 * Purpose:   Fill up entire row of direct blocks in an non-root indirect block
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_row(H5HF_t *fh, unsigned row, size_t obj_size, fheap_heap_state_t *state, fheap_heap_ids_t *keep_ids)
{
    /* Sanity check */
    assert(fh);
    assert(state);

    /* Fill the entire row (with the partial row fill routine) */
    if (fill_partial_row(fh, row, DTABLE_WIDTH(fh), obj_size, state, keep_ids))
        TEST_ERROR;

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_row() */

/*-------------------------------------------------------------------------
 * Function:  fill_root_direct
 *
 * Purpose:   Insert (small) objects to fill up the free space in all direct
 *              heap blocks in the root indirect block
 *              (Generally used to create & fill up direct blocks in a new
 *              indirect block)
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_root_direct(H5HF_t *fh, size_t obj_size, fheap_heap_state_t *state, fheap_heap_ids_t *keep_ids)
{
    unsigned max_dblock_rows; /* Max. # of direct block rows in indirect block */
    unsigned row;             /* Row being created */

    /* Get heap info */
    max_dblock_rows = DTABLE_MAX_DROWS(fh);
    assert(max_dblock_rows);

    /* Loop over rows */
    for (row = 0; row < max_dblock_rows; row++)
        if (fill_root_row(fh, row, obj_size, state, keep_ids))
            TEST_ERROR;

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_root_direct() */

/*-------------------------------------------------------------------------
 * Function:  fill_2nd_indirect
 *
 * Purpose:   Insert (small) objects to fill up the free space in all direct
 *              heap blocks in a second-level indirect block (which only has
 *              direct blocks)
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_2nd_indirect(H5HF_t *fh, unsigned pos, size_t obj_size, fheap_heap_state_t *state,
                  fheap_heap_ids_t *keep_ids)
{
    unsigned max_dblock_rows; /* Max. # of direct block rows in indirect block */
    unsigned row;             /* Current row to create */

    /* Get some information for the heap */
    max_dblock_rows = IBLOCK_MAX_DROWS(fh, pos);
    assert(max_dblock_rows);

    /* Loop over rows */
    for (row = 0; row < max_dblock_rows; row++)
        if (fill_row(fh, row, obj_size, state, keep_ids))
            TEST_ERROR;

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_2nd_direct() */

/*-------------------------------------------------------------------------
 * Function:  fill_all_direct
 *
 * Purpose:   Insert (small) objects to fill up the free space in all direct
 *              heap blocks up to the maximum direct block size
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_all_direct(H5HF_t *fh, size_t obj_size, fheap_heap_state_t *state, fheap_heap_ids_t *keep_ids)
{
    unsigned max_dblock_rows; /* Max. # of direct block rows in indirect block */
    unsigned row;             /* Row being created */

    /* Get heap info */
    max_dblock_rows = DTABLE_MAX_DROWS(fh);
    assert(max_dblock_rows);

    /* Loop over rows */
    for (row = 0; row < max_dblock_rows; row++)
        if (fill_row(fh, row, obj_size, state, keep_ids))
            TEST_ERROR;

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_all_direct() */

/*-------------------------------------------------------------------------
 * Function:  fill_2nd_indirect_row
 *
 * Purpose:   Insert (small) objects to fill up the free space in all direct
 *              heap blocks in a row of second-level indirect block (which only
 *              have direct blocks)
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_2nd_indirect_row(H5HF_t *fh, unsigned pos, size_t obj_size, fheap_heap_state_t *state,
                      fheap_heap_ids_t *keep_ids)
{
    unsigned width; /* Width of heap's doubling table */
    unsigned u;     /* Local index variable */

    /* Get some information for the heap */
    width = DTABLE_WIDTH(fh);

    /* Loop over row of indirect blocks */
    for (u = 0; u < width; u++)
        if (fill_2nd_indirect(fh, pos, obj_size, state, keep_ids))
            TEST_ERROR;

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_2nd_direct_row() */

/*-------------------------------------------------------------------------
 * Function:  fill_all_2nd_indirect_rows
 *
 * Purpose:   Insert (small) objects to fill up the free space in all direct
 *              heap blocks in all rows of second-level indirect blocks (which only
 *              have direct blocks)
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_all_2nd_indirect_rows(H5HF_t *fh, size_t obj_size, fheap_heap_state_t *state, fheap_heap_ids_t *keep_ids)
{
    unsigned width; /* Width of heap's doubling table */
    unsigned u;     /* Local index variable */

    /* Get some information for the heap */
    width = DTABLE_WIDTH(fh);

    /* Loop over rows of 2nd level deep indirect blocks */
    for (u = 0; u < (H5VM_log2_of2(width) + 1); u++)
        if (fill_2nd_indirect_row(fh, (u + 1), obj_size, state, keep_ids))
            TEST_ERROR;

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_2nd_direct_row() */

/*-------------------------------------------------------------------------
 * Function:  fill_3rd_indirect
 *
 * Purpose:   Insert (small) objects to fill up the free space in all direct
 *              heap blocks in a third-level indirect block (which
 *              has one more level of indirect blocks)
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_3rd_indirect(H5HF_t *fh, unsigned pos, size_t obj_size, fheap_heap_state_t *state,
                  fheap_heap_ids_t *keep_ids)
{
    unsigned u; /* Local index variable */

    /* Fill all direct block rows in third level indirect block */
    if (fill_all_direct(fh, obj_size, state, keep_ids))
        TEST_ERROR;

    /* Fill rows of recursive indirect blocks in third level indirect block */
    for (u = 0; u < pos; u++)
        if (fill_2nd_indirect_row(fh, (u + 1), obj_size, state, keep_ids))
            TEST_ERROR;

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_3rd_indirect() */

/*-------------------------------------------------------------------------
 * Function:  fill_3rd_indirect_row
 *
 * Purpose:   Insert (small) objects to fill up the free space in all direct
 *              heap blocks in a row of third-level indirect block (which
 *              have one more level of indirect blocks)
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_3rd_indirect_row(H5HF_t *fh, unsigned pos, size_t obj_size, fheap_heap_state_t *state,
                      fheap_heap_ids_t *keep_ids)
{
    unsigned width; /* Width of heap's doubling table */
    unsigned u;     /* Local index variable */

    /* Get some information for the heap */
    width = DTABLE_WIDTH(fh);

    /* Loop over row of 3rd level indirect blocks */
    for (u = 0; u < width; u++)
        /* Fill third level indirect block */
        if (fill_3rd_indirect(fh, pos, obj_size, state, keep_ids))
            TEST_ERROR;

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_3rd_direct_row() */

/*-------------------------------------------------------------------------
 * Function:  fill_all_3rd_indirect_rows
 *
 * Purpose:   Insert (small) objects to fill up the free space in all direct
 *              heap blocks in all rows of third-level indirect blocks (which
 *              have one more level of indirect blocks)
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_all_3rd_indirect_rows(H5HF_t *fh, size_t obj_size, fheap_heap_state_t *state, fheap_heap_ids_t *keep_ids)
{
    unsigned width; /* Width of heap's doubling table */
    unsigned u;     /* Local index variable */

    /* Get some information for the heap */
    width = DTABLE_WIDTH(fh);

    /* Loop over rows of 3rd level deep indirect blocks */
    for (u = 0; u < (H5VM_log2_of2(width) + 1); u++)
        /* Fill row of 3rd level indirect blocks */
        if (fill_3rd_indirect_row(fh, (u + 1), obj_size, state, keep_ids))
            TEST_ERROR;

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_all_3rd_direct_rows() */

/*-------------------------------------------------------------------------
 * Function:  fill_4th_indirect_row
 *
 * Purpose:   Insert (small) objects to fill up the free space in all direct
 *              heap blocks in a row of fourth-level indirect blocks (which
 *              have two more levels of indirect blocks)
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_4th_indirect_row(H5HF_t *fh, unsigned pos, size_t obj_size, fheap_heap_state_t *state,
                      fheap_heap_ids_t *keep_ids)
{
    unsigned width; /* Width of heap's doubling table */
    unsigned u, v;  /* Local index variables */

    /* Get some information for the heap */
    width = DTABLE_WIDTH(fh);

    /* Loop over row of 4th level indirect blocks */
    for (u = 0; u < width; u++) {
        /* Fill all direct block rows in fourth level indirect block */
        if (fill_all_direct(fh, obj_size, state, keep_ids))
            TEST_ERROR;

        /* Fill all rows of 2nd level deep indirect blocks in fourth level indirect block */
        if (fill_all_2nd_indirect_rows(fh, obj_size, state, keep_ids))
            TEST_ERROR;

        /* Fill rows of third level indirect blocks in fourth level indirect block */
        for (v = 0; v < pos; v++)
            if (fill_3rd_indirect_row(fh, (v + 1), obj_size, state, keep_ids))
                TEST_ERROR;
    } /* end for */

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_4th_direct_row() */

/*-------------------------------------------------------------------------
 * Function:  fill_all_4th_indirect_rows
 *
 * Purpose:   Insert (small) objects to fill up the free space in all direct
 *              heap blocks in all rows of fourth-level indirect blocks (which
 *              have two more levels of indirect blocks)
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static int
fill_all_4th_indirect_rows(H5HF_t *fh, size_t obj_size, fheap_heap_state_t *state, fheap_heap_ids_t *keep_ids)
{
    unsigned width; /* Width of heap's doubling table */
    unsigned u;     /* Local index variable */

    /* Get some information for the heap */
    width = DTABLE_WIDTH(fh);

    /* Loop over rows of 4th level deep indirect blocks */
    for (u = 0; u < (H5VM_log2_of2(width) + 1); u++) {
        /* Fill row of 4th level indirect blocks */
        if (fill_4th_indirect_row(fh, (u + 1), obj_size, state, keep_ids))
            TEST_ERROR;

        /* Account for root indirect block doubling # of rows again */
        /* (From 16 rows to the max. # of rows: 22) */
        /* (Note: this is tied to the particular doubling table/heap creation parameters) */
        if (u == 0) {
            unsigned max_root_rows; /* Maximum # of rows in root indirect block */
            unsigned row;           /* Row in heap */

            /* Get some information for the heap */
            max_root_rows = HEAP_MAX_ROOT_ROWS(fh);

            /* Increase heap size & free space */
            for (row = 16; row < max_root_rows; row++) {
                state->man_size += width * DBLOCK_SIZE(fh, row);
                state->man_free_space += width * DBLOCK_FREE(fh, row);
            } /* end for */
        }     /* end if */
    }         /* end for */

    /* Operations succeeded */
    return (0);

error:
    return (1);
} /* fill_all_4th_direct_rows() */

/*-------------------------------------------------------------------------
 * Function:  test_create
 *
 * Purpose:   Create fractal heap
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_create(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f = NULL;                     /* Internal file object pointer */
    H5HF_create_t      test_cparam;                  /* Creation parameters for heap */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Heap address in file */
    h5_stat_size_t     empty_size;                   /* File size, w/o heap */
    h5_stat_size_t     file_size;                    /* File size, after deleting heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Close file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of a file w/empty heap*/
    if ((empty_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /*
     * Test fractal heap creation
     */
    TESTING("fractal heap creation");

    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        TEST_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        TEST_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        TEST_ERROR;
    PASSED();

    /* Query the type of address mapping */
    TESTING("query heap creation parameters");
    memset(&test_cparam, 0, sizeof(H5HF_create_t));
    if (H5HF_get_cparam_test(fh, &test_cparam) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_cmp_cparam_test(cparam, &test_cparam))
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Delete heap */
    if (H5HF_delete(f, fh_addr) < 0)
        FAIL_STACK_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return 0;

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return 1;
} /* test_create() */

/*-------------------------------------------------------------------------
 * Function:  test_reopen
 *
 * Purpose:   Create & reopen a fractal heap
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_reopen(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f = NULL;                     /* Internal file object pointer */
    H5HF_create_t      test_cparam;                  /* Creation parameters for heap */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    h5_stat_size_t     empty_size;                   /* File size, w/o heap */
    h5_stat_size_t     file_size;                    /* File size, after deleting heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    fheap_heap_state_t state;                        /* State of fractal heap */
    bool               page = false;                 /* Paged aggregation strategy or not */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Close file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of a file w/empty heap*/
    if ((empty_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    if (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE)
        page = true;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /*
     * Display testing message
     */

    TESTING("create, close & reopen fractal heap");

    /* Create heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        TEST_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        TEST_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for closing & re-opening the file */
    if (tparam->reopen_heap) {
        /* Close file */
        if (H5Fclose(file) < 0)
            FAIL_STACK_ERROR;

        /* Re-open the file */
        if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
            FAIL_STACK_ERROR;

        /* Get a pointer to the internal file object */
        if (NULL == (f = (H5F_t *)H5VL_object(file)))
            FAIL_STACK_ERROR;

        /* Ignore metadata tags in the file's cache */
        if (H5AC_ignore_tags(f) < 0)
            FAIL_STACK_ERROR;

    } /* end if */

    /* Re-open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Query the creation parameters */
    memset(&test_cparam, 0, sizeof(H5HF_create_t));
    if (H5HF_get_cparam_test(fh, &test_cparam) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_cmp_cparam_test(cparam, &test_cparam))
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Delete heap */
    if (H5HF_delete(f, fh_addr) < 0)
        FAIL_STACK_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (!page || (page && !tparam->reopen_heap))
        if (file_size != empty_size)
            TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_reopen() */

/*-------------------------------------------------------------------------
 * Function:  test_open_twice
 *
 * Purpose:   Open a fractal heap twice
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_open_twice(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file  = H5I_INVALID_HID;      /* File ID */
    hid_t              file2 = H5I_INVALID_HID;      /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5F_t             *f2 = NULL;                    /* Internal file object pointer */
    H5HF_create_t      test_cparam;                  /* Creation parameters for heap */
    H5HF_t            *fh  = NULL;                   /* Fractal heap wrapper */
    H5HF_t            *fh2 = NULL;                   /* 2nd fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    h5_stat_size_t     empty_size;                   /* File size, w/o heap */
    h5_stat_size_t     file_size;                    /* File size, after deleting heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    fheap_heap_state_t state;                        /* State of fractal heap */
    bool               page = false;                 /* Paged aggregation strategy or not */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Close file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of a file w/empty heap*/
    if ((empty_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    if (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE)
        page = true;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /*
     * Display testing message
     */
    TESTING("open fractal heap twice");

    /* Create heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        TEST_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        TEST_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Open the heap again, through the first file handle */
    if (NULL == (fh2 = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Verify the creation parameters */
    memset(&test_cparam, 0, sizeof(H5HF_create_t));
    if (H5HF_get_cparam_test(fh2, &test_cparam) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_cmp_cparam_test(cparam, &test_cparam))
        TEST_ERROR;

    /* Close the second fractal heap wrapper */
    if (H5HF_close(fh2) < 0)
        FAIL_STACK_ERROR;
    fh2 = NULL;

    /* Check for closing & re-opening the heap & file */
    if (reopen_file(&file, &f, filename, fapl, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((file2 = H5Freopen(file)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f2 = (H5F_t *)H5VL_object(file2)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f2) < 0)
        FAIL_STACK_ERROR;

    /* Open the fractal heap through the second file handle */
    if (NULL == (fh2 = H5HF_open(f2, fh_addr)))
        FAIL_STACK_ERROR;

    /* Verify the creation parameters */
    memset(&test_cparam, 0, sizeof(H5HF_create_t));
    if (H5HF_get_cparam_test(fh2, &test_cparam) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_cmp_cparam_test(cparam, &test_cparam))
        TEST_ERROR;

    /* Close the first fractal heap wrapper */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the first file */
    /* (close before second file, to detect error on internal heap header's
     *  shared file information)
     */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Close the second fractal heap wrapper */
    if (H5HF_close(fh2) < 0)
        FAIL_STACK_ERROR;
    fh2 = NULL;

    /* Delete heap */
    if (H5HF_delete(f2, fh_addr) < 0)
        FAIL_STACK_ERROR;

    /* Close the second file */
    if (H5Fclose(file2) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (!page || (page && !tparam->reopen_heap))
        if (file_size != empty_size)
            TEST_ERROR;

    /* All tests passed */
    PASSED();

    return 0;

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        if (fh2)
            H5HF_close(fh2);
        H5Fclose(file);
        H5Fclose(file2);
    }
    H5E_END_TRY

    return 1;
} /* test_open_twice() */

/*-------------------------------------------------------------------------
 * Function:  test_delete_open
 *
 * Purpose:   Delete opened fractal heap (& open deleted heap)
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_delete_open(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f = NULL;                     /* Internal file object pointer */
    H5HF_create_t      test_cparam;                  /* Creation parameters for heap */
    H5HF_t            *fh  = NULL;                   /* Fractal heap wrapper */
    H5HF_t            *fh2 = NULL;                   /* 2nd fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Close file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of a file w/no heap*/
    if ((empty_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Display test banner */
    TESTING("deleting open fractal heap");

    /* Create heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        TEST_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        TEST_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Open the heap again */
    if (NULL == (fh2 = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Request that the heap be deleted */
    if (H5HF_delete(f, fh_addr) < 0)
        FAIL_STACK_ERROR;

    /* Verify the creation parameters */
    memset(&test_cparam, 0, sizeof(H5HF_create_t));
    if (H5HF_get_cparam_test(fh2, &test_cparam) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_cmp_cparam_test(cparam, &test_cparam))
        TEST_ERROR;

    /* Close the second fractal heap wrapper */
    if (H5HF_close(fh2) < 0)
        FAIL_STACK_ERROR;
    fh2 = NULL;

    /* Try re-opening the heap again (should fail, as heap will be deleted) */
    H5E_BEGIN_TRY
    {
        fh2 = H5HF_open(f, fh_addr);
    }
    H5E_END_TRY
    if (fh2) {
        /* Close opened heap */
        H5HF_close(fh2);
        fh2 = NULL;

        /* Indicate error */
        TEST_ERROR;
    } /* end if */

    /* Close the first fractal heap wrapper */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for closing & re-opening the file */
    if (tparam->reopen_heap) {
        /* Close file */
        if (H5Fclose(file) < 0)
            FAIL_STACK_ERROR;

        /* Re-open the file */
        if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
            FAIL_STACK_ERROR;

        /* Get a pointer to the internal file object */
        if (NULL == (f = (H5F_t *)H5VL_object(file)))
            FAIL_STACK_ERROR;

        /* Ignore metadata tags in the file's cache */
        if (H5AC_ignore_tags(f) < 0)
            FAIL_STACK_ERROR;

    } /* end if */

    /* Try re-opening the heap again (should fail, as heap is now deleted) */
    H5E_BEGIN_TRY
    {
        fh = H5HF_open(f, fh_addr);
    }
    H5E_END_TRY
    if (fh) {
        /* Close opened heap */
        H5HF_close(fh);
        fh = NULL;

        /* Indicate error */
        TEST_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return 0;

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        if (fh2)
            H5HF_close(fh2);
        H5Fclose(file);
    }
    H5E_END_TRY
    return 1;
} /* test_delete_open() */

/*-------------------------------------------------------------------------
 * Function:  test_id_limits
 *
 * Purpose:   Test limits for heap ID lengths
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_id_limits(hid_t fapl, H5HF_create_t *cparam, hid_t fcpl)
{
    hid_t         file = H5I_INVALID_HID;       /* File ID */
    char          filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t        *f  = NULL;                    /* Internal file object pointer */
    H5HF_t       *fh = NULL;                    /* Fractal heap wrapper */
    H5HF_create_t tmp_cparam;                   /* Local heap creation parameters */
    unsigned      deflate_level;                /* Deflation level */
    size_t        id_len;                       /* Size of fractal heap IDs */
    size_t        tiny_max_len;                 /* Max. length of tiny objects */
    bool          tiny_len_extended;            /* Do tiny objects use two bytes for the length? */
    bool          huge_ids_direct;              /* Are 'huge' objects directly accessed? */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Display testing message */
    TESTING("limits of heap ID lengths");

    /* Copy heap creation properties */
    memcpy(&tmp_cparam, cparam, sizeof(H5HF_create_t));

    /* Set the 'default' heap ID length */
    tmp_cparam.id_len = 0;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, &tmp_cparam)))
        FAIL_STACK_ERROR;

    /* Test ID length information for heap */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_tiny_info_test(fh, &tiny_max_len, &tiny_len_extended) < 0)
        FAIL_STACK_ERROR;
    if (tiny_max_len != (HEAP_ID_LEN - 1))
        TEST_ERROR;
    if (tiny_len_extended != false)
        TEST_ERROR;
    if (H5HF_get_huge_info_test(fh, NULL, &huge_ids_direct) < 0)
        FAIL_STACK_ERROR;
    if (huge_ids_direct != false)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Set the heap ID length to the size needed for directly accessing 'huge' objects */
    /* (with no I/O pipeline filters) */
    tmp_cparam.id_len = 1;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, &tmp_cparam)))
        FAIL_STACK_ERROR;

    /* Test ID length information for heap */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != 17)
        FAIL_STACK_ERROR;
    if (H5HF_get_tiny_info_test(fh, &tiny_max_len, &tiny_len_extended) < 0)
        FAIL_STACK_ERROR;
    if (tiny_max_len != 16)
        TEST_ERROR;
    if (tiny_len_extended != false)
        TEST_ERROR;
    if (H5HF_get_huge_info_test(fh, NULL, &huge_ids_direct) < 0)
        FAIL_STACK_ERROR;
    if (huge_ids_direct != true)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Set the heap ID length to the size needed for directly accessing 'huge' objects */
    /* (with I/O pipeline filters) */
    tmp_cparam.id_len = 1;

    /* Set an I/O filter for heap data */
    deflate_level = 6;
    if (H5Z_append(&tmp_cparam.pline, H5Z_FILTER_DEFLATE, H5Z_FLAG_OPTIONAL, (size_t)1, &deflate_level) < 0)
        FAIL_STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, &tmp_cparam)))
        FAIL_STACK_ERROR;

    /* Test ID length information for heap */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != 29)
        FAIL_STACK_ERROR;
    if (H5HF_get_tiny_info_test(fh, &tiny_max_len, &tiny_len_extended) < 0)
        FAIL_STACK_ERROR;
    if (tiny_max_len != 27)
        TEST_ERROR;
    if (tiny_len_extended != true)
        TEST_ERROR;
    if (H5HF_get_huge_info_test(fh, NULL, &huge_ids_direct) < 0)
        FAIL_STACK_ERROR;
    if (huge_ids_direct != true)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Release the I/O pipeline filter information */
    H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline);

    /* Set the heap ID length to a size that's too small for 'managed' heap IDs */
    tmp_cparam.id_len = 3;

    /* Create absolute heap */
    H5E_BEGIN_TRY
    {
        fh = H5HF_create(f, &tmp_cparam);
    }
    H5E_END_TRY
    if (NULL != fh)
        FAIL_STACK_ERROR;

    /* Set the heap ID length a size that's large enough for 'tiny' & 'managed'
     *  objects, but too small for directly accessing 'huge' objects
     */
    tmp_cparam.id_len = 8;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, &tmp_cparam)))
        FAIL_STACK_ERROR;

    /* Test ID length information for heap */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != 8)
        FAIL_STACK_ERROR;
    if (H5HF_get_tiny_info_test(fh, &tiny_max_len, &tiny_len_extended) < 0)
        FAIL_STACK_ERROR;
    if (tiny_max_len != 7)
        TEST_ERROR;
    if (tiny_len_extended != false)
        TEST_ERROR;
    if (H5HF_get_huge_info_test(fh, NULL, &huge_ids_direct) < 0)
        FAIL_STACK_ERROR;
    if (huge_ids_direct != false)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Set the heap ID length a size that's large enough for directly
     *  directly accessing 'huge' objects
     */
    tmp_cparam.id_len = 17;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, &tmp_cparam)))
        FAIL_STACK_ERROR;

    /* Test ID length information for heap */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != 17)
        FAIL_STACK_ERROR;
    if (H5HF_get_tiny_info_test(fh, &tiny_max_len, &tiny_len_extended) < 0)
        FAIL_STACK_ERROR;
    if (tiny_max_len != 16)
        TEST_ERROR;
    if (tiny_len_extended != false)
        TEST_ERROR;
    if (H5HF_get_huge_info_test(fh, NULL, &huge_ids_direct) < 0)
        FAIL_STACK_ERROR;
    if (huge_ids_direct != true)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Set the heap ID length to the low side of the boundary condition for
     *  encoding 'tiny' objects in one byte
     */
    tmp_cparam.id_len = 18;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, &tmp_cparam)))
        FAIL_STACK_ERROR;

    /* Test ID length information for heap */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != 18)
        FAIL_STACK_ERROR;
    if (H5HF_get_tiny_info_test(fh, &tiny_max_len, &tiny_len_extended) < 0)
        FAIL_STACK_ERROR;
    if (tiny_max_len != 16)
        TEST_ERROR;
    if (tiny_len_extended != false)
        TEST_ERROR;
    if (H5HF_get_huge_info_test(fh, NULL, &huge_ids_direct) < 0)
        FAIL_STACK_ERROR;
    if (huge_ids_direct != true)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Set the heap ID length to the high side of the boundary condition for
     *  encoding 'tiny' objects in one byte
     */
    tmp_cparam.id_len = 19;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, &tmp_cparam)))
        FAIL_STACK_ERROR;

    /* Test ID length information for heap */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != 19)
        FAIL_STACK_ERROR;
    if (H5HF_get_tiny_info_test(fh, &tiny_max_len, &tiny_len_extended) < 0)
        FAIL_STACK_ERROR;
    if (tiny_max_len != 17)
        TEST_ERROR;
    if (tiny_len_extended != true)
        TEST_ERROR;
    if (H5HF_get_huge_info_test(fh, NULL, &huge_ids_direct) < 0)
        FAIL_STACK_ERROR;
    if (huge_ids_direct != true)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Set the heap ID length a size that's larger than what is needed for
     *  directly accessing 'huge' objects
     */
    tmp_cparam.id_len = 45;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, &tmp_cparam)))
        FAIL_STACK_ERROR;

    /* Test ID length information for heap */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != 45)
        FAIL_STACK_ERROR;
    if (H5HF_get_tiny_info_test(fh, &tiny_max_len, &tiny_len_extended) < 0)
        FAIL_STACK_ERROR;
    if (tiny_max_len != 43)
        TEST_ERROR;
    if (tiny_len_extended != true)
        TEST_ERROR;
    if (H5HF_get_huge_info_test(fh, NULL, &huge_ids_direct) < 0)
        FAIL_STACK_ERROR;
    if (huge_ids_direct != true)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Set the heap ID length to a size that's too large to encode the length
     *  of 'tiny' objects
     */
    tmp_cparam.id_len = H5HF_MAX_ID_LEN + 1;

    /* Create absolute heap */
    H5E_BEGIN_TRY
    {
        fh = H5HF_create(f, &tmp_cparam);
    }
    H5E_END_TRY
    if (NULL != fh)
        FAIL_STACK_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* All tests passed */
    PASSED();

    return 0;

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return 1;
} /* test_id_limits() */

/*-------------------------------------------------------------------------
 * Function:  test_filtered_create
 *
 * Purpose:   Test creating a heap with I/O filters
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_filtered_create(hid_t fapl, H5HF_create_t *cparam, hid_t fcpl)
{
    hid_t         file = H5I_INVALID_HID;       /* File ID */
    char          filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t        *f  = NULL;                    /* Internal file object pointer */
    H5HF_t       *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t       fh_addr;                      /* Address of fractal heap */
    H5HF_create_t tmp_cparam;                   /* Local heap creation parameters */
    H5HF_create_t test_cparam;                  /* Temporary local heap creation parameters */
    unsigned      deflate_level;                /* Deflation level */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Display testing message */
    TESTING("creating heaps with I/O filters");

    /* Copy heap creation properties */
    memcpy(&tmp_cparam, cparam, sizeof(H5HF_create_t));

    /* Set an I/O filter for heap data */
    deflate_level = 6;
    if (H5Z_append(&tmp_cparam.pline, H5Z_FILTER_DEFLATE, H5Z_FLAG_OPTIONAL, (size_t)1, &deflate_level) < 0)
        FAIL_STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, &tmp_cparam)))
        FAIL_STACK_ERROR;

    /* Get heap's address */
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDONLY, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Query the heap creation parameters */
    memset(&test_cparam, 0, sizeof(H5HF_create_t));
    if (H5HF_get_cparam_test(fh, &test_cparam) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_cmp_cparam_test(&tmp_cparam, &test_cparam))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Release the I/O pipeline filter information */
    H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline);
    H5O_msg_reset(H5O_PLINE_ID, &test_cparam.pline);

    /* All tests passed */
    PASSED();

    return 0;

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return 1;
} /* test_filtered_create() */

/*-------------------------------------------------------------------------
 * Function:  test_size
 *
 * Purpose:   Test querying heap size
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_size(hid_t fapl, H5HF_create_t *cparam, hid_t fcpl)
{
    hid_t   file = H5I_INVALID_HID;       /* File ID */
    char    filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t  *f  = NULL;                    /* Internal file object pointer */
    H5HF_t *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t fh_addr;                      /* Address of fractal heap */
    hsize_t empty_heap_size;              /* Total size of empty heap on disk */
    hsize_t one_heap_size;                /* Total size of heap on disk after inserting one object */
    hsize_t heap_size;                    /* Total size of heap on disk */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Display testing message */
    TESTING("querying heap statistics");

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;

    /* Get heap's address */
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        TEST_ERROR;

    /* Get an empty heap's size */
    empty_heap_size = 0;
    if (H5HF_size(fh, &empty_heap_size) < 0)
        FAIL_STACK_ERROR;
    if (empty_heap_size == 0)
        TEST_ERROR;

    /* Insert an object */
    if (add_obj(fh, (size_t)0, (size_t)10, NULL, NULL) < 0)
        TEST_ERROR;

    /* Get the heap's size after inserting one object */
    one_heap_size = 0;
    if (H5HF_size(fh, &one_heap_size) < 0)
        FAIL_STACK_ERROR;
    if (one_heap_size <= empty_heap_size)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Check the heap's size */
    heap_size = 0;
    if (H5HF_size(fh, &heap_size) < 0)
        FAIL_STACK_ERROR;
    if (heap_size != one_heap_size)
        TEST_ERROR;

    /* Insert another object */
    if (add_obj(fh, (size_t)1, (size_t)10, NULL, NULL) < 0)
        TEST_ERROR;

    /* Check the heap's size */
    heap_size = 0;
    if (H5HF_size(fh, &heap_size) < 0)
        FAIL_STACK_ERROR;
    if (heap_size != one_heap_size)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* All tests passed */
    PASSED();

    return 0;

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return 1;
} /* test_size() */

/*-------------------------------------------------------------------------
 * Function:    test_reopen_hdr
 *
 * Purpose:     Test opening a header through one file handle, closing
 *              that file handle, then reopening through a different file
 *              handle that was open the whole time.  The header should
 *              stay in cache between the two opens.
 *
 * Return:      Success:        0
 *              Failure:        1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_reopen_hdr(hid_t fapl, H5HF_create_t *cparam, hid_t fcpl)
{
    hid_t   file1 = H5I_INVALID_HID;      /* File ID */
    hid_t   file2 = -2;                   /* File ID */
    char    filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t  *f  = NULL;                    /* Internal file object pointer */
    H5HF_t *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t fh_addr;                      /* Address of fractal heap */
    hsize_t heap_size;                    /* Total size of heap on disk */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file1 = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file1)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Display testing message */
    TESTING("reopening header through different file");

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;

    /* Get heap's address */
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        TEST_ERROR;

    /* Insert an object */
    if (add_obj(fh, (size_t)0, (size_t)10, NULL, NULL) < 0)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file1) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the file */
    if ((file1 = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the file again */
    if ((file2 = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object (file1) */
    if (NULL == (f = (H5F_t *)H5VL_object(file1)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Close the heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file (file1) */
    if (H5Fclose(file1) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object (file2) */
    if (NULL == (f = (H5F_t *)H5VL_object(file2)))
        FAIL_STACK_ERROR;

    /* Reopen the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Check the heap's size */
    heap_size = 0;
    if (H5HF_size(fh, &heap_size) < 0)
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;

    /* Close the file (file2) */
    if (H5Fclose(file2) < 0)
        FAIL_STACK_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file1);
        H5Fclose(file2);
    }
    H5E_END_TRY
    return (1);
} /* test_reopen_hdr() */

/*-------------------------------------------------------------------------
 * Function:  test_man_insert_weird
 *
 * Purpose:   Test inserting "weird" sized objects into absolute heap
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_insert_weird(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    unsigned char      heap_id[HEAP_ID_LEN];         /* Heap ID for object */
    size_t             id_len;                       /* Size of fractal heap IDs */
    fheap_heap_state_t state;                        /* State of fractal heap */
    herr_t             ret;                          /* Generic return value */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        TEST_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        TEST_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /*
     * Test inserting "weird" sized objects into heap
     */
    TESTING("inserting 'weird' sized objects into absolute heap");

    /* Attempt to insert 0-sized object into heap */
    H5E_BEGIN_TRY
    {
        ret = H5HF_insert(fh, (size_t)0, shared_wobj_g, heap_id);
    }
    H5E_END_TRY
    if (ret >= 0)
        TEST_ERROR;
    H5Eclear2(H5E_DEFAULT);

    /* Insert a 1-sized object into heap (should be a 'tiny' object) */
    if (add_obj(fh, (size_t)10, (size_t)1, &state, NULL))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check for correctly sized heap */
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_insert_weird() */

#ifdef ALL_INSERT_TESTS

/*-------------------------------------------------------------------------
 * Function:  test_man_insert_first
 *
 * Purpose:   Test inserting first object into absolute heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_insert_first(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        TEST_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        TEST_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /*
     * Test inserting first (small) object into absolute heap
     */
    TESTING("inserting first (small) object into absolute heap");
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check for correctly sized heap */
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_insert_first() */

/*-------------------------------------------------------------------------
 * Function:  test_man_insert_second
 *
 * Purpose:   Test inserting two objects into absolute heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_insert_second(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting first (small) object into absolute heap
     */
    TESTING("inserting two (small) objects into absolute heap");
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert second object */
    if (add_obj(fh, (size_t)20, SMALL_OBJ_SIZE2, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_insert_second() */

/*-------------------------------------------------------------------------
 * Function:  test_man_insert_root_mult
 *
 * Purpose:   Test inserting mult. objects into absolute heap, up to the
 *              limit of a root direct block
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_insert_root_mult(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) object into absolute heap
     */
    TESTING("inserting objects to fill absolute heap's root direct block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill the heap up */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_insert_root_mult() */

/*-------------------------------------------------------------------------
 * Function:  test_man_insert_force_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, filling the
 *              root direct block and forcing the root block to be converted
 *              into an indirect block
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_insert_force_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test forcing creation of indirect root block & second direct block
     */
    TESTING("inserting objects to create root indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill the heap up */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force root indirect block creation */
    state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    state.man_free_space = (cparam->managed.width - 1) * DBLOCK_FREE(fh, 0);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_insert_force_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_insert_fill_second
 *
 * Purpose:   Test inserting mult. objects into absolute heap, filling the
 *              root direct block, forcing the root block to be converted
 *              into an indirect block and filling the secnod indirect block
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_insert_fill_second(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill second direct block
     */
    TESTING("inserting objects to fill second direct block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill the first direct block heap up */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill the second direct block heap up (also creates initial root indirect block) */
    state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    state.man_free_space = (cparam->managed.width - 1) * DBLOCK_FREE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_insert_fill_second() */

/*-------------------------------------------------------------------------
 * Function:  test_man_insert_third_direct
 *
 * Purpose:   Test inserting mult. objects into absolute heap, filling the
 *              root direct block, forcing the root block to be converted
 *              into an indirect block, filling the secnod indirect block and
 *              creating a third direct block
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_insert_third_direct(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to create third direct block
     */
    TESTING("inserting objects to create third direct block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill the first direct block up */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill the second direct block heap up (also creates initial root indirect block) */
    state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    state.man_free_space = (cparam->managed.width - 1) * DBLOCK_FREE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force creation of third direct block */
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_insert_third_direct() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_first_row
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill first row of root indirect
 *              block.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_first_row(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill first row in root indirect block
     */
    TESTING("inserting objects to fill first row of root indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill first row of [root] indirect block */
    if (fill_root_row(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_first_row() */

/*-------------------------------------------------------------------------
 * Function:  test_man_start_second_row
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill first row of root indirect
 *              block, then add another object to start second row.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_start_second_row(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to start second row in root indirect block
     */
    TESTING("inserting objects to start second row of root indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill first root indirect row */
    if (fill_root_row(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force expanding root indirect block to two rows */
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 1);
    state.man_alloc_size += DBLOCK_SIZE(fh, 1);
    state.man_free_space = cparam->managed.width * DBLOCK_FREE(fh, 1);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_start_second_row() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_second_row
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill first row of root indirect
 *              block, then fill the second row also.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_second_row(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to start second row in root indirect block
     */
    TESTING("inserting objects to fill second row of root indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill first root indirect row */
    if (fill_root_row(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill second root indirect row */
    if (fill_root_row(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_second_row() */

/*-------------------------------------------------------------------------
 * Function:  test_man_start_third_row
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill first row of root indirect
 *              block, fill the second row also, then add another object to
 *              start the third row.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_start_third_row(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to start third row in root indirect block
     */
    TESTING("inserting objects to start third row of root indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill first root indirect row */
    if (fill_root_row(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill second root indirect row */
    if (fill_root_row(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force expanding root indirect block to four rows */
    /* (Goes to four rows because it's doubling) */
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 2);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 3);
    state.man_alloc_size += DBLOCK_SIZE(fh, 2);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 2);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 3);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_start_third_row() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_fourth_row
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill first four rows of root indirect
 *              block.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_fourth_row(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u;                            /* Local index variables */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill four rows in root indirect block
     */
    TESTING("inserting objects to fill four rows of root indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Loop over rows */
    for (u = 0; u < 4; u++)
        if (fill_root_row(fh, u, fill_size, &state, NULL))
            FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_fourth_row() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_all_root_direct
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_all_root_direct(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct  rows in root indirect block
     */
    TESTING("inserting objects to fill all direct rows of root indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill all direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_all_root_direct() */

/*-------------------------------------------------------------------------
 * Function:  test_man_first_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block and create first recursive indirect block.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_first_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to force creation of first recursive indirect block
     */
    TESTING("inserting objects to create first recursive indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force creation of first recursive indirect block */
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_first_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_second_direct_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, create first recursive indirect block and start second
 *              direct block in that indirect block.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_second_direct_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to force creation of second direct
     *  block in first recursive indirect block
     */
    TESTING("inserting objects to create second direct block in first recursive indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill the first direct block in the recursive indirect block up */
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force creation of second direct block in
     * first recursive indirect block
     */
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_second_direct_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_first_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, create first recursive indirect block and filling all
 *              direct blocks in that indirect block.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_first_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to fill all direct blocks in first recursive indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill first recursive indirect block */
    if (fill_2nd_indirect(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_first_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_second_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, create first recursive indirect block, filling all
 *              direct blocks in that indirect block and adding another
 *              object to force creation of second recursive indirect block.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_second_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to start second recursive indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill first recursive indirect block */
    if (fill_2nd_indirect(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force creation of second
     * recursive indirect block
     */
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_second_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_second_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, create first recursive indirect block, filling all
 *              direct blocks in that indirect block and then create second
 *              recursive indirect block and fill all direct blocks in that
 *              indirect block.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_second_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to fill all direct blocks in second recursive indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill first recursive indirect block */
    if (fill_2nd_indirect(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill 2nd recursive indirect block */
    if (fill_2nd_indirect(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_second_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_recursive_indirect_row
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, create first recursive indirect block, filling all
 *              direct blocks in that indirect block and then create second
 *              recursive indirect block and fill all direct blocks in that
 *              indirect block.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_recursive_indirect_row(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to fill all direct blocks in first row of recursive indirect block");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks in root indirect block up */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill row of recursive indirect blocks */
    if (fill_2nd_indirect_row(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_recursive_indirect_row() */

/*-------------------------------------------------------------------------
 * Function:  test_man_start_2nd_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the first row of indirect
 *              blocks and start on first block in second row of indirect blocks
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_start_2nd_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to start second row of recursive indirect blocks");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks in root indirect block up */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill row of recursive indirect blocks */
    if (fill_2nd_indirect_row(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force creation of second
     * recursive indirect block
     */
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_start_2nd_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_recursive_indirect_two_deep
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the row of indirect
 *              blocks that are 2 levels deep
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_recursive_indirect_two_deep(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to fill recursive indirect blocks two levels deep");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_recursive_indirect_two_deep() */

/*-------------------------------------------------------------------------
 * Function:  test_man_start_3rd_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the row of indirect
 *              blocks that are 2 levels deep and start first direct block
 *              in 3rd level of indirect blocks
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_start_3rd_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to start recursive indirect blocks three levels deep");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force creation of third level deep
     * recursive indirect block
     */
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_start_3rd_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_first_3rd_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the row of indirect
 *              blocks that are 2 levels deep and fill first indirect block
 *              in 3rd level of indirect blocks
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_first_3rd_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to fill first indirect block of recursive indirect blocks three levels deep");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all direct block rows in third level indirect block */
    if (fill_all_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill row of recursive indirect blocks in third level indirect block */
    if (fill_2nd_indirect_row(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_first_3rd_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_3rd_recursive_indirect_row
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the row of indirect
 *              blocks that are 2 levels deep and fill all indirect blocks
 *              first row of 3rd level of indirect blocks
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_3rd_recursive_indirect_row(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING(
        "inserting objects to fill row of indirect blocks in recursive indirect blocks three levels deep");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill 1st row of 3rd level indirect blocks */
    if (fill_3rd_indirect_row(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_3rd_recursive_indirect_row() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_all_3rd_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the row of indirect
 *              blocks that are 2 levels deep and fill all indirect blocks
 *              that are three levels deep
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_all_3rd_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING(
        "inserting objects to fill row of indirect blocks in recursive indirect blocks three levels deep");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_all_3rd_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_start_4th_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the row of indirect
 *              blocks that are 2 levels deep, fill all indirect blocks
 *              that are three levels deep and start first direct block that
 *              is four levels deep
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_start_4th_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to start first direct block in recursive indirect blocks four levels deep");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force creation of four level deep
     * recursive indirect block
     */
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    if (add_obj(fh, (size_t)10, SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_start_4th_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_first_4th_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the row of indirect
 *              blocks that are 2 levels deep, fill all indirect blocks
 *              that are three levels deep and fill the first (3rd level)
 *              indirect block that is four levels deep
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_first_4th_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to fill first (3rd level) indirect block in recursive indirect block four "
            "levels deep");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill direct block rows in fourth level indirect block */
    if (fill_all_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 2nd level deep indirect blocks in fourth level indirect block */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill first row of 3rd level deep indirect blocks in fourth level indirect block */
    if (fill_3rd_indirect_row(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_first_4th_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_4th_recursive_indirect_row
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the row of indirect
 *              blocks that are 2 levels deep, fill all indirect blocks
 *              that are three levels deep and fill the first row of
 *              indirect block that is four levels deep
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_4th_recursive_indirect_row(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in first recursive indirect block
     */
    TESTING("inserting objects to fill first row of recursive indirect blocks four levels deep");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill 1st row of 4th level indirect blocks */
    if (fill_4th_indirect_row(fh, 1, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_4th_recursive_indirect_row() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_all_4th_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the row of indirect
 *              blocks that are 2 levels deep, fill all indirect blocks
 *              that are three levels deep and fill all rows of
 *              indirect blocks that are four levels deep
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_all_4th_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in recursive indirect blocks four levels deep
     */
    TESTING("inserting objects to fill all rows of recursive indirect blocks four levels deep");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 4th level indirect blocks */
    if (fill_all_4th_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_all_4th_recursive_indirect() */
#endif /* ALL_INSERT_TESTS */

/*-------------------------------------------------------------------------
 * Function:  test_man_start_5th_recursive_indirect
 *
 * Purpose:   Test inserting mult. objects into absolute heap, creating
 *              enough direct blocks to fill all direct rows of root indirect
 *              block, fill all direct blocks in the row of indirect
 *              blocks that are 2 levels deep, fill all indirect blocks
 *              that are three levels deep, fill all rows of indirect blocks
 *              that are four levels deep and start first direct block in
 *              indirect blocks five levels deep
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_start_5th_recursive_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));

    /*
     * Test inserting mult. (small) objects to fill all direct
     *  blocks in recursive indirect blocks four levels deep and add one more
     *  block, to make a five level deep structure
     */
    TESTING("inserting objects to create first direct block in recursive indirect blocks five levels deep");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Fill direct blocks up in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap & file */
    if (reopen_file(&file, &f, filename, fapl, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap & file */
    if (reopen_file(&file, &f, filename, fapl, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap & file */
    if (reopen_file(&file, &f, filename, fapl, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 4th level indirect blocks */
    if (fill_all_4th_indirect_rows(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap & file */
    if (reopen_file(&file, &f, filename, fapl, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to force creation of five level deep
     * recursive indirect block
     */
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    if (add_obj(fh, (size_t)10, (size_t)SMALL_OBJ_SIZE1, &state, NULL))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_start_5th_recursive_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_bogus
 *
 * Purpose:   Test removing bogus heap IDs
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_bogus(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    unsigned char      heap_id[HEAP_ID_LEN];         /* Heap ID for object */
    unsigned long      seed = 0;                     /* Random # seed */
    size_t             id_len;                       /* Size of fractal heap IDs */
    hsize_t            obj_off;                      /* Offset of object in heap */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u;                            /* Local index variable */
    herr_t             ret;                          /* Generic return value */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /*
     * Test removing bogus IDs from heap
     */
    TESTING("removing bad heap IDs from absolute heap");

    /* Retrieve "bulk" filling object size */
    fill_size = get_fill_size(tparam);

    /* Choose random # seed */
    seed = (unsigned long)time(NULL);
#if 0
/* seed = (unsigned long)1155438845; */
fprintf(stderr, "Random # seed was: %lu\n", seed);
#endif
    HDsrandom((unsigned)seed);

    /* Set heap ID to random (non-null) value */
    heap_id[0] = H5HF_ID_VERS_CURR | H5HF_ID_TYPE_MAN;
    for (u = 1; u < HEAP_ID_LEN; u++)
        heap_id[u] = (unsigned char)(HDrandom() + 1);

    /* Try removing bogus heap ID from empty heap */
    H5E_BEGIN_TRY
    {
        ret = H5HF_remove(fh, heap_id);
    }
    H5E_END_TRY
    if (ret >= 0)
        FAIL_STACK_ERROR;

    /* Fill root direct blocks */
    if (fill_root_direct(fh, fill_size, &state, NULL))
        FAIL_STACK_ERROR;

    /* Get offset of random heap ID */
    if (H5HF_get_id_off_test(fh, heap_id, &obj_off) < 0)
        FAIL_STACK_ERROR;

    /* Make certain we can't accidentally use a valid heap ID */
    while (obj_off < state.man_size) {
        /* Set heap ID to random (non-null) value */
        heap_id[0] = H5HF_ID_VERS_CURR | H5HF_ID_TYPE_MAN;
        for (u = 1; u < HEAP_ID_LEN; u++)
            heap_id[u] = (unsigned char)(HDrandom() + 1);

        /* Get offset of random heap ID */
        if (H5HF_get_id_off_test(fh, heap_id, &obj_off) < 0)
            FAIL_STACK_ERROR;
    } /* end while */

    /* Try removing bogus heap ID from heap w/objects */
    H5E_BEGIN_TRY
    {
        ret = H5HF_remove(fh, heap_id);
    }
    H5E_END_TRY
    if (ret >= 0)
        TEST_ERROR;
    H5Eclear2(H5E_DEFAULT);

    /* Try reading bogus heap ID from heap w/objects */
    H5E_BEGIN_TRY
    {
        ret = H5HF_read(fh, heap_id, shared_robj_g);
    }
    H5E_END_TRY
    if (ret >= 0)
        TEST_ERROR;
    H5Eclear2(H5E_DEFAULT);

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    fprintf(stderr, "Random # seed was: %lu\n", seed);
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_bogus() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_one
 *
 * Purpose:   Test removing single object from heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_one(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    unsigned char      heap_id[HEAP_ID_LEN];         /* Heap ID for object */
    unsigned char      obj[SMALL_OBJ_SIZE1];         /* Buffer for object to insert */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u;                            /* Local index variable */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Prepare for querying the size of a file with an empty heap */

    /* Close (empty) heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;

    /* Close file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of a file w/empty heap*/
    if ((empty_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Re-open heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /*
     * Test removing first (small) object from absolute heap
     */
    TESTING("removing single object from absolute heap");

    /* Initialize the buffer for objects to insert */
    for (u = 0; u < sizeof(obj); u++)
        obj[u] = (unsigned char)u;

    /* Insert object into heap */
    if (H5HF_insert(fh, sizeof(obj), obj, &heap_id) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0) - sizeof(obj);
    state.man_nobjs      = 1;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Remove object from heap */
    if (H5HF_remove(fh, heap_id) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_size       = 0;
    state.man_alloc_size = 0;
    state.man_free_space = 0;
    state.man_nobjs      = 0;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_one() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_two
 *
 * Purpose:   Test removing two objects from heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_two(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    unsigned char      heap_id1[HEAP_ID_LEN];        /* Heap ID for first object */
    unsigned char      heap_id2[HEAP_ID_LEN];        /* Heap ID for second object */
    unsigned char      obj[SMALL_OBJ_SIZE1];         /* Buffer for object to insert */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u;                            /* Local index variable */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Prepare for querying the size of a file with an empty heap */

    /* Close (empty) heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;

    /* Close file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of a file w/empty heap*/
    if ((empty_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Re-open heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /*
     * Test removing two (small) objects from absolute heap
     */
    TESTING("removing two objects from absolute heap");

    /* Initialize the buffer for objects to insert */
    for (u = 0; u < sizeof(obj); u++)
        obj[u] = (unsigned char)u;

    /* Insert first object into heap */
    if (H5HF_insert(fh, sizeof(obj), obj, &heap_id1) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0) - sizeof(obj);
    state.man_nobjs      = 1;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Insert second object into heap */
    if (H5HF_insert(fh, sizeof(obj), obj, &heap_id2) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_free_space -= sizeof(obj);
    state.man_nobjs++;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Remove first object from heap */
    if (H5HF_remove(fh, heap_id1) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_free_space += sizeof(obj);
    state.man_nobjs--;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Remove second object from heap */
    if (H5HF_remove(fh, heap_id2) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_size       = 0;
    state.man_alloc_size = 0;
    state.man_free_space = 0;
    state.man_nobjs      = 0;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_two() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_one_larger
 *
 * Purpose:   Test removing single larger (but < standalone size) object
 *              from heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_one_larger(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    unsigned char      heap_id[HEAP_ID_LEN];         /* Heap ID for object */
    unsigned char     *obj;                          /* Buffer for object to insert */
    size_t             obj_len;                      /* Length of object to insert */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u;                            /* Local index variable */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Prepare for querying the size of a file with an empty heap */

    /* Close (empty) heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;

    /* Close file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of a file w/empty heap*/
    if ((empty_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Re-open heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /*
     * Test removing one larger object from absolute heap
     */
    TESTING("removing single larger object from absolute heap");

    /* Set up object to insert */
    obj_len = (size_t)DBLOCK_SIZE(fh, 2) + 1;
    obj     = shared_wobj_g;

    /* Insert object into heap */
    if (H5HF_insert(fh, obj_len, obj, &heap_id) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    for (u = 0; u < 4; u++) {
        state.man_size += DBLOCK_SIZE(fh, u) * cparam->managed.width;
        state.man_free_space += DBLOCK_FREE(fh, u) * cparam->managed.width;
    } /* end for */
    state.man_alloc_size = DBLOCK_SIZE(fh, 3);
    state.man_free_space -= obj_len;
    state.man_nobjs = 1;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Remove object from heap */
    if (H5HF_remove(fh, heap_id) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_size       = 0;
    state.man_alloc_size = 0;
    state.man_free_space = 0;
    state.man_nobjs      = 0;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_one_larger() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_two_larger
 *
 * Purpose:   Test removing two larger (but < standalone size) objects
 *              from heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_two_larger(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    unsigned char      heap_id1[HEAP_ID_LEN];        /* Heap ID for first object */
    unsigned char      heap_id2[HEAP_ID_LEN];        /* Heap ID for second object */
    unsigned char     *obj;                          /* Buffer for object to insert */
    size_t             obj_len;                      /* Length of object to insert */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u;                            /* Local index variable */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Prepare for querying the size of a file with an empty heap */

    /* Close (empty) heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;

    /* Close file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of a file w/empty heap*/
    if ((empty_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Re-open heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /*
     * Test removing two larger objects from absolute heap
     */
    if (tparam->del_dir == FHEAP_DEL_FORWARD)
        TESTING("removing two larger objects from absolute heap (forward)");
    else
        TESTING("removing two larger objects from absolute heap (reverse)");

    /* Set up first object to insert */
    obj_len = (size_t)DBLOCK_SIZE(fh, 2) + 1;
    obj     = shared_wobj_g;

    /* Insert object into heap */
    if (H5HF_insert(fh, obj_len, obj, &heap_id1) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    for (u = 0; u < 4; u++) {
        state.man_size += DBLOCK_SIZE(fh, u) * cparam->managed.width;
        state.man_free_space += DBLOCK_FREE(fh, u) * cparam->managed.width;
    } /* end for */
    state.man_alloc_size = DBLOCK_SIZE(fh, 3);
    state.man_free_space -= obj_len;
    state.man_nobjs = 1;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Set up second object to insert */
    obj_len = (size_t)DBLOCK_SIZE(fh, 4) + 1;
    obj     = shared_wobj_g;

    /* Insert object into heap */
    if (H5HF_insert(fh, obj_len, obj, &heap_id2) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    /* (Goes to 8 rows because of doubling) */
    for (u = 4; u < 8; u++) {
        state.man_size += DBLOCK_SIZE(fh, u) * cparam->managed.width;
        state.man_free_space += DBLOCK_FREE(fh, u) * cparam->managed.width;
    } /* end for */
    state.man_alloc_size += DBLOCK_SIZE(fh, 5);
    state.man_free_space -= obj_len;
    state.man_nobjs = 2;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Remove objects in different orders */
    if (tparam->del_dir == FHEAP_DEL_FORWARD) {
        /* Remove first object from heap */
        if (H5HF_remove(fh, heap_id1) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Check up on heap... */
        state.man_alloc_size -= DBLOCK_SIZE(fh, 3);
        state.man_free_space += DBLOCK_SIZE(fh, 2) + 1;
        state.man_nobjs = 1;
        if (check_stats(fh, &state))
            FAIL_STACK_ERROR;

        /* Remove second object from heap */
        if (H5HF_remove(fh, heap_id2) < 0)
            FAIL_STACK_ERROR;
    } /* end if */
    else {
        /* Remove second object from heap */
        if (H5HF_remove(fh, heap_id2) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Check up on heap... */
        /* (Goes to 4 rows because of halving) */
        for (u = 4; u < 8; u++) {
            state.man_size -= DBLOCK_SIZE(fh, u) * cparam->managed.width;
            state.man_free_space -= DBLOCK_FREE(fh, u) * cparam->managed.width;
        } /* end for */
        state.man_alloc_size -= DBLOCK_SIZE(fh, 5);
        state.man_free_space += DBLOCK_SIZE(fh, 4) + 1;
        state.man_nobjs = 1;
        if (check_stats(fh, &state))
            FAIL_STACK_ERROR;

        /* Remove first object from heap */
        if (H5HF_remove(fh, heap_id1) < 0)
            FAIL_STACK_ERROR;
    } /* end else */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_size       = 0;
    state.man_alloc_size = 0;
    state.man_free_space = 0;
    state.man_nobjs      = 0;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_two_larger() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_three_larger
 *
 * Purpose:   Test removing three larger (but < standalone size) objects
 *              from heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_three_larger(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    unsigned char      heap_id1[HEAP_ID_LEN];        /* Heap ID for first object */
    unsigned char      heap_id2[HEAP_ID_LEN];        /* Heap ID for second object */
    unsigned char      heap_id3[HEAP_ID_LEN];        /* Heap ID for third object */
    unsigned char     *obj;                          /* Buffer for object to insert */
    size_t             obj_len;                      /* Length of object to insert */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u;                            /* Local index variable */

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        TEST_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Prepare for querying the size of a file with an empty heap */

    /* Close (empty) heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;

    /* Close file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of a file w/empty heap*/
    if ((empty_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Re-open heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /*
     * Test removing three larger objects from absolute heap
     */
    if (tparam->del_dir == FHEAP_DEL_FORWARD)
        TESTING("removing three larger objects from absolute heap (forward)");
    else
        TESTING("removing three larger objects from absolute heap (reverse)");

    /* Set up first object to insert */
    obj_len = (size_t)DBLOCK_SIZE(fh, 2) + 1;
    obj     = shared_wobj_g;

    /* Insert object into heap */
    if (H5HF_insert(fh, obj_len, obj, &heap_id1) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    for (u = 0; u < 4; u++) {
        state.man_size += DBLOCK_SIZE(fh, u) * cparam->managed.width;
        state.man_free_space += DBLOCK_FREE(fh, u) * cparam->managed.width;
    } /* end for */
    state.man_alloc_size = DBLOCK_SIZE(fh, 3);
    state.man_free_space -= obj_len;
    state.man_nobjs = 1;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Set up second object to insert */
    obj_len = (size_t)DBLOCK_SIZE(fh, 4) + 1;
    obj     = shared_wobj_g;

    /* Insert object into heap */
    if (H5HF_insert(fh, obj_len, obj, &heap_id2) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    /* (Goes to 8 rows because of doubling) */
    for (u = 4; u < 8; u++) {
        state.man_size += DBLOCK_SIZE(fh, u) * cparam->managed.width;
        state.man_free_space += DBLOCK_FREE(fh, u) * cparam->managed.width;
    } /* end for */
    state.man_alloc_size += DBLOCK_SIZE(fh, 5);
    state.man_free_space -= obj_len;
    state.man_nobjs = 2;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Set up third object to insert */
    obj_len = (size_t)DBLOCK_SIZE(fh, 7) + 1;
    obj     = shared_wobj_g;

    /* Insert object into heap */
    if (H5HF_insert(fh, obj_len, obj, &heap_id3) < 0)
        FAIL_STACK_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    /* (Goes to 16 rows because of doubling) */
    for (u = 8; u < 16; u++) {
        state.man_size += DBLOCK_SIZE(fh, u) * cparam->managed.width;
        state.man_free_space += DBLOCK_FREE(fh, u) * cparam->managed.width;
    } /* end for */
    state.man_alloc_size += DBLOCK_SIZE(fh, 8);
    state.man_free_space -= obj_len;
    state.man_nobjs = 3;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Remove objects in different orders */
    if (tparam->del_dir == FHEAP_DEL_FORWARD) {
        /* Remove first object from heap */
        if (H5HF_remove(fh, heap_id1) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Check up on heap... */
        state.man_alloc_size -= DBLOCK_SIZE(fh, 3);
        state.man_free_space += DBLOCK_SIZE(fh, 2) + 1;
        state.man_nobjs = 2;
        if (check_stats(fh, &state))
            FAIL_STACK_ERROR;

        /* Remove second object from heap */
        if (H5HF_remove(fh, heap_id2) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Check up on heap... */
        state.man_alloc_size -= DBLOCK_SIZE(fh, 5);
        state.man_free_space += DBLOCK_SIZE(fh, 4) + 1;
        state.man_nobjs = 1;
        if (check_stats(fh, &state))
            FAIL_STACK_ERROR;

        /* Remove third object from heap */
        if (H5HF_remove(fh, heap_id3) < 0)
            FAIL_STACK_ERROR;
    } /* end if */
    else {
        /* Remove third object from heap */
        if (H5HF_remove(fh, heap_id3) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Check up on heap... */
        /* (Goes to 8 rows because of halving) */
        for (u = 8; u < 16; u++) {
            state.man_size -= DBLOCK_SIZE(fh, u) * cparam->managed.width;
            state.man_free_space -= DBLOCK_FREE(fh, u) * cparam->managed.width;
        } /* end for */
        state.man_alloc_size -= DBLOCK_SIZE(fh, 8);
        state.man_free_space += DBLOCK_SIZE(fh, 7) + 1;
        state.man_nobjs = 2;
        if (check_stats(fh, &state))
            FAIL_STACK_ERROR;

        /* Remove second object from heap */
        if (H5HF_remove(fh, heap_id2) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Check up on heap... */
        /* (Goes to 4 rows because of halving) */
        for (u = 4; u < 8; u++) {
            state.man_size -= DBLOCK_SIZE(fh, u) * cparam->managed.width;
            state.man_free_space -= DBLOCK_FREE(fh, u) * cparam->managed.width;
        } /* end for */
        state.man_alloc_size -= DBLOCK_SIZE(fh, 5);
        state.man_free_space += DBLOCK_SIZE(fh, 4) + 1;
        state.man_nobjs = 1;
        if (check_stats(fh, &state))
            FAIL_STACK_ERROR;

        /* Remove first object from heap */
        if (H5HF_remove(fh, heap_id1) < 0)
            FAIL_STACK_ERROR;
    } /* end else */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_size       = 0;
    state.man_alloc_size = 0;
    state.man_free_space = 0;
    state.man_nobjs      = 0;
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_three_larger() */

/*-------------------------------------------------------------------------
 * Function:  test_man_incr_insert_remove
 *
 * Purpose:   Test incremental insert & removal of objects in heap
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_incr_insert_remove(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t           file = H5I_INVALID_HID;       /* File ID */
    char            filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t          *f  = NULL;                    /* Internal file object pointer */
    H5HF_t         *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t         fh_addr;                      /* Address of fractal heap */
    unsigned char **heap_id      = NULL;
    unsigned char  *heap_id_data = NULL;
    struct a_type_t1 {
        char a[10];
        char b[40];
    } obj1, obj2;              /* Objects to insert/remove */
    size_t             id_len; /* Size of fractal heap IDs */
    fheap_heap_state_t state;  /* State of fractal heap */
    int                i, j;

    /* Set the filename to use for this test (dependent on fapl) */
    h5_fixname(FILENAME[0], fapl, filename, sizeof(filename));

    /* Set up data array */
    if (NULL == (heap_id_data = (unsigned char *)calloc(100 * MAX_HEAP_ID_LEN, sizeof(unsigned char))))
        TEST_ERROR;
    if (NULL == (heap_id = (unsigned char **)calloc(100, sizeof(heap_id_data))))
        TEST_ERROR;
    for (i = 0; i < 100; i++)
        heap_id[i] = heap_id_data + (i * MAX_HEAP_ID_LEN);

    /* Create the file to work on */
    if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, tparam->my_fcpl, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Create absolute heap */
    if (NULL == (fh = H5HF_create(f, cparam)))
        FAIL_STACK_ERROR;
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > HEAP_ID_LEN)
        FAIL_STACK_ERROR;
    if (H5HF_get_heap_addr(fh, &fh_addr) < 0)
        FAIL_STACK_ERROR;
    if (!H5_addr_defined(fh_addr))
        FAIL_STACK_ERROR;
    memset(&state, 0, sizeof(fheap_heap_state_t));
    if (check_stats(fh, &state))
        FAIL_STACK_ERROR;

    /*
     * Test incremental insert and removal
     */
    TESTING("incremental object insertion and removal");

    memset(&obj1, 0, sizeof(obj1));
    memset(&obj2, 0, sizeof(obj2));
    for (i = 0; i < 100; i++) {
        for (j = 0; j < i; j++) {
            if (H5HF_remove(fh, heap_id[j]) < 0)
                FAIL_STACK_ERROR;

            snprintf(obj2.b, sizeof(obj2.b), "%s%2d", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", j);
            if (H5HF_insert(fh, (sizeof(obj2)), &obj2, heap_id[j]) < 0)
                FAIL_STACK_ERROR;
        } /* end for */

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Insert object */
        memset(heap_id[i], 0, id_len);
        snprintf(obj1.b, sizeof(obj1.b), "%s%2d", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", i);
        if (H5HF_insert(fh, (sizeof(obj1)), &obj1, heap_id[i]) < 0)
            FAIL_STACK_ERROR;
    } /* end for */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        TEST_ERROR;

    /* Close the file */
    if (H5Fclose(file) < 0)
        TEST_ERROR;

    /* All tests passed */
    PASSED();

    free(heap_id);
    free(heap_id_data);

    return 0;

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY

    free(heap_id);
    free(heap_id_data);

    return 1;
} /* test_man_incr_insert_remove() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_root_direct
 *
 * Purpose:   Test filling and removing all objects from root direct block in
 *              heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_root_direct(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "removing all objects from root direct block of absolute heap";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill the heap up */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_root_direct() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_two_direct
 *
 * Purpose:   Test filling and removing all objects from (first) two direct
 *              blocks in heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_two_direct(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "removing all objects from two direct blocks of absolute heap";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill the first block in heap */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Fill the second block in heap */
    state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    state.man_free_space = (cparam->managed.width - 1) * DBLOCK_FREE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_two_direct() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_first_row
 *
 * Purpose:   Test filling and removing all objects from first row of direct
 *              blocks in heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_first_row(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "removing all objects from first row of direct blocks of absolute heap";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill first row of direct blocks */
    if (fill_root_row(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_first_row() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_first_two_rows
 *
 * Purpose:   Test filling and removing all objects from first two rows of
 *              direct blocks in heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_first_two_rows(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "removing all objects from first two rows of direct blocks of absolute heap";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill first two rows of direct blocks */
    if (fill_root_row(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;
    if (fill_root_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_first_two_rows() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_first_four_rows
 *
 * Purpose:   Test filling and removing all objects from first four rows of
 *              direct blocks in heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_first_four_rows(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "removing all objects from first four rows of direct blocks of absolute heap";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill first two rows of direct blocks */
    if (fill_root_row(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;
    if (fill_root_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;
    if (fill_root_row(fh, 2, fill_size, &state, &keep_ids))
        TEST_ERROR;
    if (fill_root_row(fh, 3, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_first_four_rows() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_all_root_direct
 *
 * Purpose:   Test filling and removing all objects from all direct blocks
 *              in root indirect block of heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_all_root_direct(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "removing all objects from all direct blocks of root group in absolute heap";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_all_root_direct() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_2nd_indirect
 *
 * Purpose:   Test filling and removing all objects up to 2nd level indirect
 *              blocks of heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_2nd_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "removing all objects from 2nd level indirect blocks of absolute heap";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_2nd_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_remove_3rd_indirect
 *
 * Purpose:   Test filling and removing all objects up to 3rd level indirect
 *              blocks of heap
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_remove_3rd_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "removing all objects from 3rd level indirect blocks of absolute heap";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_remove_3rd_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_man_skip_start_block
 *
 * Purpose:   Test inserting object into absolute heap which is too large
 *              for starting block size, which forces root indirect block
 *              creation
 *
 *              Then, remove all the objects, in various ways
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_skip_start_block(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "inserting object that is too large for starting block, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    obj_size       = (size_t)DBLOCK_SIZE(fh, 0) + 1;
    state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 1);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 2);
    state.man_alloc_size = DBLOCK_SIZE(fh, 2);
    state.man_free_space = cparam->managed.width * DBLOCK_FREE(fh, 0);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 1);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 2);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_skip_start_block() */

/*-------------------------------------------------------------------------
 * Function:  test_man_skip_start_block_add_back
 *
 * Purpose:   Test inserting object into absolute heap which is too large
 *              for starting block size, which forces root indirect block
 *              creation, then add object which fits in skipped direct block
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_skip_start_block_add_back(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc =
        "skipping starting block, then adding object back to first block, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Insert object too large for starting block size */
    obj_size       = (size_t)DBLOCK_SIZE(fh, 0) + 1;
    state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 1);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 2);
    state.man_alloc_size = DBLOCK_SIZE(fh, 2);
    state.man_free_space = cparam->managed.width * DBLOCK_FREE(fh, 0);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 1);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 2);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert an object to fill up the heap block just created */
    obj_size = (size_t)DBLOCK_FREE(fh, 2) - obj_size;
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert second "real" object, which should go in earlier direct block */
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    if (add_obj(fh, (size_t)20, (size_t)SMALL_OBJ_SIZE2, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_skip_start_block_add_back() */

/*-------------------------------------------------------------------------
 * Function:  test_man_skip_start_block_add_skipped
 *
 * Purpose:   Test inserting object into absolute heap which is too large
 *              for starting block size, which forces root indirect block
 *              creation, then add objects to fill skipped direct blocks
 *              and add another object to start on next "normal" block
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_skip_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc =
        "skipping starting block, then adding objects to backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Insert object too large for starting block size */
    obj_size       = (size_t)DBLOCK_SIZE(fh, 0) + 1;
    state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 1);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 2);
    state.man_alloc_size = DBLOCK_SIZE(fh, 2);
    state.man_free_space = cparam->managed.width * DBLOCK_FREE(fh, 0);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 1);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 2);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert an object to fill up the heap block just created */
    obj_size = (size_t)DBLOCK_FREE(fh, 2) - obj_size;
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add rows of blocks to "backfill" direct blocks that were skipped */
    if (fill_row(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;
    if (fill_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert another object, which should extend direct blocks, instead of backfill */
    state.man_alloc_size += DBLOCK_SIZE(fh, 2);
    if (add_obj(fh, (size_t)20, (size_t)SMALL_OBJ_SIZE2, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_skip_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_skip_2nd_block
 *
 * Purpose:   Test inserting object into absolute heap which is small
 *              enough for starting block size, then add object too large
 *              for any blocks in first row of direct blocks, to force
 *              early creation of indirect block (and range of skipped blocks)
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_skip_2nd_block(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "insert object to initial block, then add object too large for starting direct "
                            "blocks, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Insert small object, to create root direct block */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (add_obj(fh, (size_t)10, (size_t)SMALL_OBJ_SIZE1, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped blocks that are too small to hold the second object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, 0) + 1;
    state.man_size += (cparam->managed.width - 1) * DBLOCK_SIZE(fh, 0);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 1);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 2);
    state.man_alloc_size += DBLOCK_SIZE(fh, 2);
    state.man_free_space += (cparam->managed.width - 1) * DBLOCK_FREE(fh, 0);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 1);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 2);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_skip_2nd_block() */

/*-------------------------------------------------------------------------
 * Function:  test_man_skip_2nd_block_add_skipped
 *
 * Purpose:   Test inserting object into absolute heap which is small
 *              enough for starting block size, then add object too large
 *              for any blocks in first row of direct blocks, to force
 *              early creation of indirect block (and range of skipped blocks).
 *              Then add more objects to fill up remainder of initial direct
 *              block and all the skipped blocks, and one more object (to
 *              start next "normal" block).
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_skip_2nd_block_add_skipped(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           v;                            /* Local index variables */
    /* Test description */
    const char *base_desc = "insert object to initial block, then add object too large for starting direct "
                            "blocks, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Insert small object, to create root direct block */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (add_obj(fh, (size_t)10, (size_t)SMALL_OBJ_SIZE1, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped blocks that are too small to hold the second object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, 0) + 1;
    state.man_size += (cparam->managed.width - 1) * DBLOCK_SIZE(fh, 0);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 1);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 2);
    state.man_alloc_size += DBLOCK_SIZE(fh, 2);
    state.man_free_space += (cparam->managed.width - 1) * DBLOCK_FREE(fh, 0);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 1);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 2);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert an object to fill up the (smaller) heap block just created */
    obj_size = (size_t)DBLOCK_FREE(fh, 0) - SMALL_OBJ_SIZE1;
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill remainder of 2 * start size block */
    obj_size = (size_t)DBLOCK_FREE(fh, 2) - ((size_t)DBLOCK_SIZE(fh, 0) + 1);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert objects to fill remaining rows of the starting block size */

    /* Fill remainder of first row of direct heap blocks up */
    for (v = 0; v < (cparam->managed.width - 1); v++) {
        state.man_alloc_size += DBLOCK_SIZE(fh, 0);
        if (fill_heap(fh, 0, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Fill second row of direct blocks */
    if (fill_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to create new 2 * start size direct block */
    state.man_alloc_size += DBLOCK_SIZE(fh, 2);
    if (add_obj(fh, (size_t)10, (size_t)SMALL_OBJ_SIZE1, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_skip_2nd_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_one_partial_skip_2nd_block_add_skipped
 *
 * Purpose:   Test filling initial direct block, then add object small enough
 *              for initial block size (to create root indirect block), then
 *              add object too large for any blocks in first three rows of
 *              direct blocks, to force extension of indirect block (and range
 *              of skipped blocks).
 *
 *              Then add more objects to fill up remainder of partial direct
 *              block and all the skipped blocks, and one more object (to
 *              start next "normal" block).
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_one_partial_skip_2nd_block_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                     fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u;                            /* Local index variable */
    /* Test description */
    const char *base_desc =
        "skipping blocks with indirect root, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill initial direct block */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    if (fill_heap(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert small object, to create root indirect block */
    state.man_size += (cparam->managed.width - 1) * DBLOCK_SIZE(fh, 0);
    state.man_alloc_size += DBLOCK_SIZE(fh, 0);
    state.man_free_space += (cparam->managed.width - 1) * DBLOCK_FREE(fh, 0);
    if (add_obj(fh, (size_t)10, (size_t)SMALL_OBJ_SIZE1, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped blocks that are too small to hold the large object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, 2) + 1;
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 1);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 2);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 3);
    state.man_alloc_size += DBLOCK_SIZE(fh, 3);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 1);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 2);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 3);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert an object to fill up the (smaller) heap block just created */
    obj_size = (size_t)DBLOCK_FREE(fh, 0) - SMALL_OBJ_SIZE1;
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill remainder of 4 * start size block */
    obj_size = (size_t)DBLOCK_FREE(fh, 3) - ((size_t)DBLOCK_SIZE(fh, 2) + 1);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert objects to fill remaining heaps in first row */
    for (u = 0; u < (cparam->managed.width - 2); u++) {
        /* Fill a direct heap block up */
        state.man_alloc_size += DBLOCK_SIZE(fh, 0);
        if (fill_heap(fh, 0, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert objects to fill remaining heaps in second row */
    if (fill_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert objects to fill remaining heaps in third row */
    if (fill_row(fh, 2, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to create new 4 * start size direct block */
    state.man_alloc_size += DBLOCK_SIZE(fh, 3);
    if (add_obj(fh, (size_t)10, (size_t)SMALL_OBJ_SIZE1, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_one_partial_skip_2nd_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_row_skip_add_skipped
 *
 * Purpose:   Test filling first row of direct blocks, then
 *              add object too large for any blocks in first three rows of
 *              direct blocks, to force extension of indirect block (and range
 *              of skipped blocks).
 *
 *              Then add more objects to fill up remainder of partial direct
 *              block and all the skipped blocks, and one more object (to
 *              start next "normal" block).
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_row_skip_add_skipped(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc =
        "filling first row, then skipping rows, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill first row of direct blocks */
    if (fill_root_row(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped blocks that are too small to hold the large object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, 2) + 1;
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 1);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 2);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 3);
    state.man_alloc_size += DBLOCK_SIZE(fh, 3);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 1);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 2);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 3);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill remainder of 4 * start size block */
    obj_size = (size_t)DBLOCK_FREE(fh, 3) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert objects to fill remaining heaps in second row */
    if (fill_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert objects to fill remaining heaps in third row */
    if (fill_row(fh, 2, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to create new 4 * start size direct block */
    state.man_alloc_size += DBLOCK_SIZE(fh, 3);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_row_skip_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_skip_direct_skip_indirect_two_rows_add_skipped
 *
 * Purpose:   Test adding object too large for all but the last row in the
 *              direct blocks in root indirect block, then
 *              add object too large for initial block in first two rows of
 *              indirect blocks, to force extension of non-root
 *              indirect block (and range of skipped blocks).
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_skip_direct_skip_indirect_two_rows_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                        fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    unsigned           num_direct_rows; /* Number of rows (of direct blocks) in root indirect block */
    unsigned           row;             /* Current row */
    h5_stat_size_t     empty_size;      /* Size of a file with an empty heap */
    size_t             obj_size;        /* Size of object */
    fheap_heap_state_t state;           /* State of fractal heap */
    unsigned           v;               /* Local index variables */
    /* Test description */
    const char *base_desc = "skipping direct blocks to last row and skipping two rows of root indirect "
                            "block, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Compute # direct block rows in root indirect block */
    num_direct_rows = DTABLE_MAX_DROWS(fh);

    /* Compute heap size & free space when half direct blocks allocated */
    row = 0;
    do {
        state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, row);
        state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, row);
        row++;
    } while (row < (num_direct_rows / 2));

    /* Insert object to extend root block to middle of root direct blocks
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, row - 2) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, row - 1);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Compute heap size & free space when all direct blocks allocated */
    do {
        state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, row);
        state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, row);
        row++;
    } while (row < num_direct_rows);

    /* Insert large objects into last row of direct blocks in root indirect
     * block, to force extension of root indirect block that covers the first
     * row of indirect blocks in root indirect block
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_direct_rows - 2) + 1;
    for (v = 0; v < cparam->managed.width; v++) {
        state.man_alloc_size += DBLOCK_SIZE(fh, num_direct_rows - 1);
        if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Compute heap size & free space when root indirect block doubles again */
    do {
        state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, row);
        state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, row);
        row++;
    } while (row < (2 * num_direct_rows));

    /* Insert large object, to force creation of indirect blocks with
     * range of skipped blocks that are too small to hold the large object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_direct_rows - 2) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_direct_rows - 1);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_skip_direct_skip_indirect_two_rows_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_direct_skip_indirect_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block, then
 *              add object too large for initial block in first row of direct
 *              blocks in indirect block, to force extension of non-root
 *              indirect block (and range of skipped blocks).
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_direct_skip_indirect_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                           fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "filling direct blocks and skipping blocks in non-root indirect block, then "
                            "backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped blocks that are too small to hold the large object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, 2) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, 3);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add rows of blocks to "backfill" direct blocks that were skipped */
    if (fill_row(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;
    if (fill_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert an object to fill up the (biggest) heap block created */
    obj_size = (size_t)DBLOCK_FREE(fh, 3) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill direct block heaps with 2 * initial block size in nested indirect block */
    if (fill_row(fh, 2, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert one more object, to create new 4 * start size direct block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, 3);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_direct_skip_indirect_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_direct_skip_2nd_indirect_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block, then
 *              add object too large for all direct blocks in first row of
 *              indirect blocks, to force skipping a row of indirect blocks
 *              (and range of skipped blocks), then backfill all direct blocks
 *              skipped and extend to next "normal" direct block.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_direct_skip_2nd_indirect_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                               fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned         num_first_indirect_rows;      /* Number of rows (of direct blocks) in each of the */
                                                   /* first indirect blocks */
    unsigned           row;                        /* Current row in indirect block */
    h5_stat_size_t     empty_size;                 /* Size of a file with an empty heap */
    size_t             obj_size;                   /* Size of object */
    size_t             fill_size;                  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                      /* State of fractal heap */
    unsigned           u;                          /* Local index variable */
    /* Test description */
    const char *base_desc = "filling direct blocks and skipping row of non-root indirect blocks, then "
                            "backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of direct blocks that are smaller than large object's block size */
    for (row = 0; row < num_first_indirect_rows; row++) {
        /* Fill rows of direct blocks in skipped indirect blocks */
        for (u = 0; u < cparam->managed.width; u++)
            if (fill_row(fh, row, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Fill row of direct blocks in largest (i.e. non-skipped) indirect block */
        if (fill_row(fh, row, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_direct_skip_2nd_indirect_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_2nd_direct_less_one_wrap_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, except the last
 *              one, then insert object insert object that is too large to
 *              hold in row of 2nd level indirect blocks (forcing the use of
 *              the next row of 2nd level blocks), then backfill all skipped
 *              direct blocks & extend.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_2nd_direct_less_one_wrap_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                               fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u;          /* Local index variables */
    /* Test description */
    const char *base_desc =
        "filling direct blocks, filling 2nd level indirect blocks, except last one, and insert object too "
        "large for 2nd level indirect blocks, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill first row (except one) of 2nd level indirect blocks */
    for (u = 0; u < cparam->managed.width - 1; u++)
        /* Fill all rows of 2nd level indirect blocks in root block */
        if (fill_2nd_indirect(fh, 1, fill_size, &state, &keep_ids))
            TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in 2nd level indirect block's direct blocks
     * (and rows of next 2nd level indirect block's direct blocks)
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in skipped 2nd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;

        /* Direct block row in current 2nd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_2nd_direct_less_one_wrap_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_direct_skip_2nd_indirect_skip_2nd_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block, then
 *              add object too large for all direct blocks in first row of
 *              indirect blocks, to force skipping a row of indirect blocks
 *              (and range of skipped blocks), then add object that is too
 *              large for initial block size in skipped indirect blocks, then
 *              backfill all direct blocks and extend to next "normal" direct
 *              block (but insert first block of backfilling with object
 *              too large for initial block size in skipped indirect block
 *              row's direct blocks).
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_direct_skip_2nd_indirect_skip_2nd_block_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                                  fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    unsigned           row;      /* Current row in indirect block */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u;          /* Local index variable */
    /* Test description */
    const char *base_desc = "filling direct blocks and skipping row of non-root indirect blocks, then skip "
                            "row of direct blocks, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object too large for initial block size in skipped indirect blocks */
    obj_size = (size_t)DBLOCK_SIZE(fh, 3) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, 4);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (medium) block just created */
    obj_size = (size_t)DBLOCK_FREE(fh, 4) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Finish off blocks in row of medium block size (just to make row filling easier below) */
    obj_size = (size_t)DBLOCK_FREE(fh, 4);
    for (u = 1; u < cparam->managed.width; u++) {
        state.man_alloc_size += DBLOCK_SIZE(fh, 4);
        if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of direct blocks that are smaller than large object's block size */
    for (row = 0; row < num_first_indirect_rows; row++) {
        /* Fill rows of direct blocks in skipped indirect blocks */
        for (u = 0; u < cparam->managed.width; u++)
            if (fill_row(fh, row, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Fill row of direct blocks in largest (i.e. non-skipped) indirect block */
        /* (Skip the row of blocks filled above) */
        if (row != 4)
            if (fill_row(fh, row, fill_size, &state, &keep_ids))
                TEST_ERROR;
    } /* end while */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_direct_skip_2nd_indirect_skip_2nd_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_direct_skip_indirect_two_rows_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block, then
 *              add object too large for initial block in first two rows of
 *              indirect blocks, to force extension of non-root
 *              indirect block (and range of skipped blocks).
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_direct_skip_indirect_two_rows_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                        fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    unsigned           max_dblock_rows; /* Max. # of rows (of direct blocks) in the root indirect block */
    h5_stat_size_t     empty_size;      /* Size of a file with an empty heap */
    size_t             obj_size;        /* Size of object */
    size_t             fill_size;       /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;           /* State of fractal heap */
    unsigned           u, v;            /* Local index variables */
    /* Test description */
    const char *base_desc = "filling direct blocks and skipping two rows of root indirect block, then "
                            "backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);
    max_dblock_rows         = DTABLE_MAX_DROWS(fh);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped blocks that are too small to hold the large object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, max_dblock_rows - 2) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, max_dblock_rows - 1);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert an object to fill up the (biggest) heap block created */
    obj_size = (size_t)DBLOCK_FREE(fh, max_dblock_rows - 1) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in indirect block's direct blocks */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in first row of skipped 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block rows in second row of skipped 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block row in used 2nd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows in second row of skipped 2nd level indirect blocks (and used 2nd level block) */

    /* Direct block rows in skipped 2nd level indirect blocks */
    for (v = 0; v < cparam->managed.width; v++)
        if (fill_row(fh, num_first_indirect_rows, fill_size, &state, &keep_ids))
            TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Direct block row in used 2nd level indirect block */
    if (fill_row(fh, num_first_indirect_rows, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, max_dblock_rows - 1);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_direct_skip_indirect_two_rows_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_direct_skip_indirect_two_rows_skip_indirect_row_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block, then
 *              add object too large for initial block in first two rows of
 *              indirect blocks, to force extension of non-root
 *              indirect block, then add object too large for first row of
 *              indirect blocks, (and ranges of skipped blocks), then backfill
 *              and extend.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_direct_skip_indirect_two_rows_skip_indirect_row_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                                          fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    unsigned           max_dblock_rows; /* Max. # of rows (of direct blocks) in the root indirect block */
    h5_stat_size_t     empty_size;      /* Size of a file with an empty heap */
    size_t             obj_size;        /* Size of object */
    size_t             fill_size;       /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;           /* State of fractal heap */
    unsigned           u, v;            /* Local index variables */
    /* Test description */
    const char *base_desc =
        "filling direct blocks and skipping two rows of root indirect block, skip one row of root indirect "
        "block, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);
    max_dblock_rows         = DTABLE_MAX_DROWS(fh);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of two rows of indirect blocks and
     * range of skipped blocks that are too small to hold the large object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, max_dblock_rows - 2) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, max_dblock_rows - 1);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert an object to fill up the (biggest) heap block created */
    obj_size = (size_t)DBLOCK_FREE(fh, max_dblock_rows - 1) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object that can't fit in first row of indirect blocks
     * previously skipped, but is small enough to fit into second row of
     * skipped blocks.
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, max_dblock_rows - 3) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, max_dblock_rows - 2);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert an object to fill up the (2nd biggest) heap block created */
    obj_size = (size_t)DBLOCK_FREE(fh, max_dblock_rows - 2) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in indirect block's direct blocks */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in first row of skipped 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block rows in second row of skipped 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block row in used 2nd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows in second row of skipped 2nd level indirect blocks (and used 2nd level block) */

    /* Finish blocks in partially used 2nd level indirect block */
    if (fill_partial_row(fh, num_first_indirect_rows, cparam->managed.width - 1, fill_size, &state,
                         &keep_ids))
        TEST_ERROR;

    /* Direct block rows in skipped 2nd level indirect blocks */
    /* (less the one indirect block already used) */
    for (v = 0; v < cparam->managed.width - 1; v++)
        if (fill_row(fh, num_first_indirect_rows, fill_size, &state, &keep_ids))
            TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Direct block row in used 3rd row 2nd level indirect block */
    if (fill_row(fh, num_first_indirect_rows, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, max_dblock_rows - 1);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_direct_skip_indirect_two_rows_skip_indirect_row_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_2nd_direct_skip_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, the insert object
 *              that is too large to hold in first row of direct blocks of
 *              3rd level indirect block, then backfill & extend all skipped
 *              3rd level indirect block's direct blocks.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_2nd_direct_skip_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                      fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc =
        "filling direct blocks, filling 2nd level indirect blocks, and skip first rows of direct blocks of "
        "3rd level indirect block, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, 2) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, 3);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, 3) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in 3rd level indirect block's direct blocks */
    if (fill_row(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;
    if (fill_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;
    if (fill_row(fh, 2, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, 3);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_2nd_direct_skip_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_2nd_direct_skip_2nd_indirect_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, fill all direct
 *              blocks in 3rd level indirect block, then insert object
 *              that is too large to hold in first row of direct blocks of
 *              3rd level indirect block's first 2nd level indirect block, then
 *              backfill & extend all skipped 2nd level indirect block's direct
 *              blocks.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_2nd_direct_skip_2nd_indirect_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                                   fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
                                                     /* Test description */
    const char *base_desc =
        "filling direct blocks, filling 2nd level indirect blocks, filling 3rd level indirect block's direct "
        "blocks, and skip first rows of direct blocks of 3rd level indirect block's 2nd level indirect "
        "block, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in third level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, 2) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, 3);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, 3) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in (3rd level indirect block's) 2nd level
     *  indirect block's direct blocks
     */
    if (fill_row(fh, 0, fill_size, &state, &keep_ids))
        TEST_ERROR;
    if (fill_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;
    if (fill_row(fh, 2, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, 3);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_2nd_direct_skip_2nd_indirect_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_2nd_direct_fill_direct_skip_3rd_indirect_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, fill all direct
 *              blocks in 3rd level indirect block, then insert object
 *              that is too large to hold in first row of 2nd level indirect
 *              blocks of 3rd level indirect block, then backfill & extend all
 *              skipped direct blocks.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_2nd_direct_fill_direct_skip_3rd_indirect_start_block_add_skipped(hid_t               fapl,
                                                                               H5HF_create_t      *cparam,
                                                                               fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u, v;       /* Local index variables */
    /* Test description */
    const char *base_desc = "filling direct blocks, filling 2nd level indirect blocks, filling 3rd level "
                            "indirect block's direct blocks, and skip first row of indirect blocks of 3rd "
                            "level indirect block, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in third level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in (first 3rd level indirect block's) 2nd level
     *  indirect block's direct blocks
     *  (and second 3rd level indirect block's direct blocks)
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block row in 3rd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_2nd_direct_fill_direct_skip_3rd_indirect_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_2nd_direct_fill_direct_skip2_3rd_indirect_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, fill all direct
 *              blocks in 3rd level indirect block, then insert object
 *              that is too large to hold in first & second rows of 2nd level
 *              indirect blocks (although this 3rd level indirect block only
 *              has one row of 2nd level indirect blocks) of 3rd level indirect
 *              block, then backfill & extend all skipped direct blocks.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_2nd_direct_fill_direct_skip2_3rd_indirect_start_block_add_skipped(hid_t               fapl,
                                                                                H5HF_create_t      *cparam,
                                                                                fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u, v;       /* Local index variables */
    /* Test description */
    const char *base_desc = "filling direct blocks, filling 2nd level indirect blocks, filling 3rd level "
                            "indirect block's direct blocks, and skip first two rows of indirect blocks of "
                            "3rd level indirect block, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in third level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows + 1);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows + 1) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in (first 3rd level indirect block's) 2nd level
     *  indirect block's direct blocks
     *  (and second 3rd level indirect block's direct blocks)
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block row in 3rd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Fill row of direct blocks in second 3rd level indirect block */
    if (fill_row(fh, num_first_indirect_rows, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows + 1);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_2nd_direct_fill_direct_skip2_3rd_indirect_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, all 3rd level
 *              indirect blocks in first row except the last one, fill direct
 *              blocks in last 3rd level indirect block, then insert object
 *              insert object that is too large to hold in last 3rd level
 *              indirect block's row of 2nd level indirect blocks (forcing the
 *              use of the next row of 3rd level blocks), then backfill all
 *              skipped direct blocks & extend.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                                           fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u, v;       /* Local index variables */
    /* Test description */
    const char *base_desc =
        "filling direct blocks, filling 2nd level indirect blocks, filling first row of 3rd level indirect "
        "blocks, except last one, fill all direct blocks in last 3rd level indirect block, and insert object "
        "too large for it's 2nd level indirect blocks, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks in root indirect block */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill first row (except one) of 3rd level indirect blocks */
    for (u = 0; u < cparam->managed.width - 1; u++)
        /* Fill 3rd level indirect block */
        if (fill_3rd_indirect(fh, 1, fill_size, &state, &keep_ids))
            TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in last third level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in 2nd level indirect block's direct blocks
     * (and rows of next 3rd level indirect block's direct blocks)
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block row in current 3rd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_1st_row_3rd_direct_fill_2nd_direct_less_one_wrap_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, all 3rd level
 *              indirect blocks in first row, fill direct blocks in 2nd row 3rd
 *              level indirect block, fill all direct blocks in 1st row of
 *              2nd level indirect blocks except the last one, then insert
 *              object that is too large to hold in 3rd level indirect block's
 *              first row of 2nd level indirect blocks (forcing the use of the
 *              next row of 2nd level blocks), then backfill all skipped direct
 *              blocks & extend.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_1st_row_3rd_direct_fill_2nd_direct_less_one_wrap_start_block_add_skipped(
    hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size;                    /* Size of a file with an empty heap */
    size_t             obj_size;                      /* Size of object */
    size_t             fill_size;                     /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                         /* State of fractal heap */
    unsigned           u; /* Local index variables */ /* Test description */
    const char        *base_desc =
        "filling direct blocks, filling 2nd level indirect blocks, filling first row of 3rd level indirect "
        "blocks, fill all direct blocks in next 3rd level indirect block, fill all 1st row of 2nd level "
        "indirect blocks, except last one, and insert object too large for 2nd level indirect block, then "
        "backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks in 4th level indirect block */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill first row of 3rd level indirect blocks */
    if (fill_3rd_indirect_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in 2nd row third level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill first row (except one) of 2nd level indirect blocks */
    for (u = 0; u < cparam->managed.width - 1; u++)
        if (fill_2nd_indirect(fh, 1, fill_size, &state, &keep_ids))
            TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in 2nd level indirect block's direct blocks
     * (and rows of next 2nd level indirect block's direct blocks)
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in skipped 2nd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;

        /* Direct block row in current 2nd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_1st_row_3rd_direct_fill_2nd_direct_less_one_wrap_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_3rd_direct_fill_direct_skip_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, fill all direct
 *              blocks and indirect blocks in 3rd level indirect block, then
 *              fill all direct blocks in 4th level indirect block, then
 *              insert object that is too large to hold in first row of 2nd
 *              level indirect blocks of 4th level indirect block, then
 *              backfill all skipped direct blocks & extend.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_3rd_direct_fill_direct_skip_start_block_add_skipped(hid_t fapl, H5HF_create_t *cparam,
                                                                  fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u, v;       /* Local index variables */
    /* Test description */
    const char *base_desc =
        "filling direct blocks, filling 2nd level indirect blocks, filling 3rd level indirect blocks, fill "
        "4th level indirect block's direct blocks, and skip first row of 2nd indirect blocks of 4th level "
        "indirect block, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in fourth level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in (first 4th level indirect block's) 2nd level
     *  indirect block's direct blocks
     *  (and second row of 2nd level indirect block's direct blocks)
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block row in 2nd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_3rd_direct_fill_direct_skip_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:  test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, fill all direct
 *              blocks and indirect blocks in 3rd level indirect block, then
 *              fill all direct blocks and 2nd level indirect blocks in 4th
 *              level indirect block, then
 *              insert object that is too large to hold in first row of 2nd
 *              level indirect blocks of 4th level indirect block's first
 *              3rd level indirect block, then
 *              backfill all skipped direct blocks & extend.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_start_block_add_skipped(
    hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u, v;       /* Local index variables */
    /* Test description */
    const char *base_desc =
        "filling direct blocks, filling 2nd level indirect blocks, filling 3rd level indirect blocks, fill "
        "4th level indirect block's direct, 2nd level indirect blocks and 3rd level direct block, and skip "
        "first row of 2nd indirect blocks of 4th level indirect block's 3rd level indirect block, then "
        "backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in fourth level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks in fourth level indirect block */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in fourth level indirect block's 3rd level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in (first 4th level indirect block's first 3rd
     *  level block's) 2nd level indirect block's direct blocks
     *  (and rows of 2nd 3rd level indirect block's direct blocks)
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block row in 3rd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:
 *test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_two_rows_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, fill all direct
 *              blocks and indirect blocks in 3rd level indirect block, fill all
 *              direct & indirect blocks in first row of 4th level indirect
 *              blocks, then fill all direct blocks in first row of 3rd level
 *              indirect blocks in 4th level indirect block, fill direct blocks
 *              in first block of 2nd row of 3rd level indirect blocks in 4th
 *              level indirect block, then insert object insert object that is
 *              too large to hold in first row of 2nd level indirect blocks of
 *              3rd level indirect block (in 4th level indirect block), then
 *              backfill all skipped direct blocks & extend.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_two_rows_start_block_add_skipped(
    hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u, v;       /* Local index variables */
    /* Test description */
    const char *base_desc =
        "filling direct blocks, filling 2nd level indirect blocks, filling 3rd level indirect blocks, fill "
        "first row of 4th level indirect blocks, fill 2nd row 4th level indirect block's direct, 2nd level "
        "indirect blocks, first row of 3rd level indirect blocks, 3rd level direct block in 2nd row, and "
        "skip first row of 2nd indirect blocks of 4th level indirect block's 3rd level indirect block, then "
        "backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill first row of 4th level indirect blocks */
    if (fill_4th_indirect_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Account for root indirect block doubling # of rows again */
    /* (From 16 rows to the max. # of rows: 22) */
    /* (Note: this is tied to the particular doubling table/heap creation parameters) */
    {
        unsigned max_root_rows; /* Maximum # of rows in root indirect block */
        unsigned row;           /* Row in heap */

        /* Get some information for the heap */
        max_root_rows = HEAP_MAX_ROOT_ROWS(fh);

        /* Increase heap size & free space */
        for (row = 16; row < max_root_rows; row++) {
            state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, row);
            state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, row);
        } /* end for */
    }     /* end if */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in 2nd row 4th level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks in 2nd row 4th level indirect block */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill first row of 3rd level indirect blocks in 2nd row 4th level indirect block */
    if (fill_3rd_indirect_row(fh, 1, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in 4th level indirect block's 2nd row of 3rd level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in (first block in 2nd row  4th level indirect
     *  block's first 3rd level block's) 2nd level indirect block's direct
     * blocks (and rows of 2nd 3rd level indirect block's direct blocks)
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block row in 3rd level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_two_rows_start_block_add_skipped()
   */

/*-------------------------------------------------------------------------
 * Function:
 *test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_wrap_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, fill all direct
 *              blocks and indirect blocks in 3rd level indirect block, fill all
 *              direct & indirect blocks in 4th level indirect
 *              block, then fill all direct blocks in first row of 3rd
 *              level indirect blocks in 4th level indirect block except
 *              the last (3rd level indirect block) in 4th level indirect block,
 *              fill direct blocks in last 3rd level indirect block, then
 *              insert object insert object that is too large to hold in first
 *              row of 2nd level indirect blocks of 3rd level indirect block
 *              (in 4th level indirect block) (forcing the use of the next
 *              4th level block), then backfill all skipped direct blocks &
 *              extend.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_wrap_start_block_add_skipped(
    hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u, v;       /* Local index variables */
    /* Test description */
    const char *base_desc =
        "filling direct blocks, filling 2nd level indirect blocks, filling 3rd level indirect blocks, fill "
        "first row of 3rd level indirect blocks in 4th level indirect block except last 3rd level block, "
        "fill direct blocks in 3rd level block, and skip row of 2nd indirect blocks of 4th level indirect "
        "block's 3rd level indirect block, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in 4th level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks in 4th level indirect block */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill first row (except one) of 3rd level indirect blocks in 4th level indirect block */
    for (u = 0; u < cparam->managed.width - 1; u++) {
        /* Fill all direct block rows in 3rd level indirect block */
        if (fill_all_direct(fh, fill_size, &state, &keep_ids))
            TEST_ERROR;

        /* Fill row of 2nd level indirect blocks in 3rd level indirect block */
        if (fill_2nd_indirect_row(fh, 1, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in 4th level indirect block's last 3rd level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in (4th level indirect block's first 3rd level
     * block's) 2nd level indirect block's direct blocks (and rows of next 4th
     * level indirect block's direct blocks)
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block row in 4th level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_wrap_start_block_add_skipped() */

/*-------------------------------------------------------------------------
 * Function:
 *test_man_fill_4th_direct_less_one_fill_2nd_direct_fill_direct_skip_3rd_indirect_wrap_start_block_add_skipped
 *
 * Purpose:   Test filling all direct blocks in root indirect block and all
 *              direct blocks in 2nd level indirect blocks, fill all direct
 *              blocks and indirect blocks in 3rd level indirect block, fill all
 *              direct & indirect blocks in first row of 4th level indirect
 *              blocks, except last one, then fill all direct blocks in first
 *              row of 3rd level indirect blocks in 4th level indirect block
 *              except the last (3rd level indirect block) in 4th level
 *              indirect block, fill direct blocks in last 3rd level indirect
 *              block, then insert object insert object that is too large to
 *              hold in row of 2nd level indirect blocks in 3rd level indirect
 *              block (in 4th level indirect block) (forcing the use of the
 *              next row of 4th level blocks), then backfill all skipped direct
 *              blocks & extend.
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_fill_4th_direct_less_one_fill_2nd_direct_fill_direct_skip_3rd_indirect_wrap_start_block_add_skipped(
    hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u, v;       /* Local index variables */
    /* Test description */
    const char *base_desc =
        "filling direct blocks, filling 2nd level indirect blocks, filling 3rd level indirect blocks, fill "
        "first row of 4th level indirect blocks, except last one, fill first row of 3rd level indirect "
        "blocks in last 4th level indirect block except last 3rd level block, fill direct blocks in 3rd "
        "level block, and skip row of 2nd indirect blocks of 4th level indirect block's 3rd level indirect "
        "block, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve info about heap */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 3rd level indirect blocks */
    if (fill_all_3rd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill first row (except one) of 4th level indirect blocks */
    for (u = 0; u < cparam->managed.width - 1; u++) {
        /* Fill all direct block rows in 4th level indirect block */
        if (fill_all_direct(fh, fill_size, &state, &keep_ids))
            TEST_ERROR;

        /* Fill all rows of 2nd level indirect blocks in 4th level indirect block */
        if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
            TEST_ERROR;

        /* Fill row of 3rd level indirect blocks in 4th level indirect block */
        if (fill_3rd_indirect_row(fh, 1, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in 4th level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks in 4th level indirect block */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill row (except one) of 3rd level indirect blocks in 4th level indirect block */
    for (u = 0; u < cparam->managed.width - 1; u++) {
        /* Fill all direct block rows in 3rd level indirect block */
        if (fill_all_direct(fh, fill_size, &state, &keep_ids))
            TEST_ERROR;

        /* Fill row of 2nd level indirect blocks in 3rd level indirect block */
        if (fill_2nd_indirect_row(fh, 1, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all direct block rows in 4th level indirect block's last 3rd level indirect block */
    if (fill_all_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Account for root indirect block doubling # of rows again */
    /* (From 16 rows to the max. # of rows: 22) */
    /* (Note: this is tied to the particular doubling table/heap creation parameters) */
    {
        unsigned max_root_rows; /* Maximum # of rows in root indirect block */
        unsigned row;           /* Row in heap */

        /* Get some information for the heap */
        max_root_rows = HEAP_MAX_ROOT_ROWS(fh);

        /* Increase heap size & free space */
        for (row = 16; row < max_root_rows; row++) {
            state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, row);
            state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, row);
        } /* end for */
    }     /* end if */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert large object, to force creation of indirect block and
     * range of skipped (indirect) blocks that are too small to hold the large
     * object
     */
    obj_size = (size_t)DBLOCK_SIZE(fh, num_first_indirect_rows - 1) + 1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object to fill space in (large) block created */
    obj_size = (size_t)DBLOCK_FREE(fh, num_first_indirect_rows) - obj_size;
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill rows skipped over in (4th level indirect block's first 3rd level
     * block's) 2nd level indirect block's direct blocks (and rows of next 4th
     * level indirect block's direct blocks)
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        /* Direct block rows in 2nd level indirect blocks */
        for (v = 0; v < cparam->managed.width; v++)
            if (fill_row(fh, u, fill_size, &state, &keep_ids))
                TEST_ERROR;

        /* Direct block row in 4th level indirect block */
        if (fill_row(fh, u, fill_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Add one more object, to create another "large" block */
    obj_size = SMALL_OBJ_SIZE1;
    state.man_alloc_size += DBLOCK_SIZE(fh, num_first_indirect_rows);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_fill_4th_direct_less_one_fill_2nd_direct_fill_direct_skip_3rd_indirect_wrap_start_block_add_skipped()
   */

/*-------------------------------------------------------------------------
 * Function:  test_man_frag_simple
 *
 * Purpose:   Test inserting objects small enough to fit into first row of
 *              direct blocks, but not to share a block with another object,
 *              until start-block-size * 2 blocks are reached.  Then, go back
 *              and fill in the space in the blocks skipped.
 *
 *              Then, remove all the objects, in various ways
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_frag_simple(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u;                            /* Local index variables */
    /* Test description */
    const char *base_desc = "fragmenting small blocks, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Insert objects small enough to fit into initial blocks, but not to
     * share them with other objects of the same size, until the next larger
     * block size is reached.
     */
    obj_size             = (size_t)DBLOCK_SIZE(fh, 0) / 2;
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    for (u = 0; u < cparam->managed.width; u++) {
        state.man_alloc_size += DBLOCK_SIZE(fh, 0);
        if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
            TEST_ERROR;
        if (u == 0) {
            state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
            state.man_free_space += (cparam->managed.width - 1) * DBLOCK_FREE(fh, 0);
        } /* end if */
    }     /* end for */
    state.man_size += DBLOCK_SIZE(fh, 1) * cparam->managed.width;
    state.man_free_space += DBLOCK_FREE(fh, 1) * cparam->managed.width;
    for (u = 0; u < cparam->managed.width; u++) {
        state.man_alloc_size += DBLOCK_SIZE(fh, 1);
        if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* (Account for doubling root indirect block for rows 3-4 */
    for (u = 0; u < 2; u++) {
        state.man_size += DBLOCK_SIZE(fh, u + 2) * cparam->managed.width;
        state.man_free_space += DBLOCK_FREE(fh, u + 2) * cparam->managed.width;
    } /* end for */

    /* Add one more object, to create a 2 * start_block_size block */
    state.man_alloc_size += DBLOCK_SIZE(fh, 2);
    if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Go back and fill in direct blocks of initial block size (which have large free space in them) */
    obj_size = (size_t)DBLOCK_FREE(fh, 0) - obj_size;
    for (u = 0; u < cparam->managed.width; u++)
        if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
            TEST_ERROR;
    for (u = 0; u < cparam->managed.width; u++)
        if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
            TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill in 2 * start_block_size block */
    obj_size = (size_t)DBLOCK_FREE(fh, 2) - ((size_t)DBLOCK_SIZE(fh, 0) / 2);
    if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
        TEST_ERROR;

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_frag_simple() */

/*-------------------------------------------------------------------------
 * Function:  test_man_frag_direct
 *
 * Purpose:   Test inserting small object to fit into each direct block
 *              in root block, but not to share a block with another object,
 *              Then, go back and fill in the space in the blocks skipped.
 *
 *              Then, go back and remove all objects
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_frag_direct(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    unsigned           root_direct_rows;             /* Number of rows in root indirect block */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u, v;                         /* Local index variables */
    /* Test description */
    const char *base_desc = "fragmenting direct blocks, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Retrieve # of direct rows in root indirect block */
    root_direct_rows = H5HF_get_dtable_max_drows_test(fh);

    /* Insert objects small enough to fit into each direct block, but not to
     * share them with other objects of the same size.
     */
    obj_size             = (size_t)DBLOCK_SIZE(fh, 0) / 2;
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0);
    /* First row */
    for (u = 0; u < cparam->managed.width; u++) {
        state.man_alloc_size += DBLOCK_SIZE(fh, 0);
        if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
            TEST_ERROR;
        if (u == 0) {
            state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
            state.man_free_space += (cparam->managed.width - 1) * DBLOCK_FREE(fh, 0);
        } /* end if */
    }     /* end for */
    state.man_size += DBLOCK_SIZE(fh, 1) * cparam->managed.width;
    state.man_free_space += DBLOCK_FREE(fh, 1) * cparam->managed.width;
    /* Second row */
    for (u = 0; u < cparam->managed.width; u++) {
        state.man_alloc_size += DBLOCK_SIZE(fh, 1);
        if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* (Account for doubling root indirect block for rows 3-4 */
    for (u = 0; u < 2; u++) {
        state.man_size += DBLOCK_SIZE(fh, u + 2) * cparam->managed.width;
        state.man_free_space += DBLOCK_FREE(fh, u + 2) * cparam->managed.width;
    } /* end for */

    /* Rows 3-4 */
    for (u = 0; u < 2; u++) {
        obj_size = (size_t)DBLOCK_SIZE(fh, u + 2) / 2;
        for (v = 0; v < cparam->managed.width; v++) {
            state.man_alloc_size += DBLOCK_SIZE(fh, u + 2);
            if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
                TEST_ERROR;
        } /* end for */
    }     /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* (Account for doubling root indirect block for rows 5-8 */
    for (u = 0; u < 4; u++) {
        state.man_size += DBLOCK_SIZE(fh, u + 4) * cparam->managed.width;
        state.man_free_space += DBLOCK_FREE(fh, u + 4) * cparam->managed.width;
    } /* end for */

    /* Rows 5-8 */
    for (u = 0; u < 4; u++) {
        obj_size = (size_t)DBLOCK_SIZE(fh, u + 4) / 2;
        for (v = 0; v < cparam->managed.width; v++) {
            state.man_alloc_size += DBLOCK_SIZE(fh, u + 4);
            if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
                TEST_ERROR;
        } /* end for */
    }     /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* (Account for doubling root indirect block for rows 9-16 */
    for (u = 0; u < 8; u++) {
        state.man_size += DBLOCK_SIZE(fh, u + 8) * cparam->managed.width;
        state.man_free_space += DBLOCK_FREE(fh, u + 8) * cparam->managed.width;
    } /* end for */

    /* Row 9 (last direct block row) */
    obj_size = (size_t)DBLOCK_SIZE(fh, 8) / 2;
    for (v = 0; v < cparam->managed.width; v++) {
        state.man_alloc_size += DBLOCK_SIZE(fh, 8);
        if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
            TEST_ERROR;
    } /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Go back and backfill all root block's direct blocks */
    for (u = 0; u < root_direct_rows; u++) {
        obj_size = (size_t)DBLOCK_FREE(fh, u) - ((size_t)DBLOCK_SIZE(fh, u) / 2);
        for (v = 0; v < cparam->managed.width; v++)
            if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
                TEST_ERROR;
    } /* end for */

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_frag_direct() */

/*-------------------------------------------------------------------------
 * Function:  test_man_frag_2nd_direct
 *
 * Purpose:   Test filling all direct blocks in root indirect block, then
 *              inserting small object to fit into each direct block
 *              in 2nd level indirect block, but not to share a block with
 *              another object.
 *              Then, go back and fill in the space in the blocks skipped.
 *
 *              Then, go back and remove all the objects
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_frag_2nd_direct(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    unsigned
        num_first_indirect_rows; /* Number of rows (of direct blocks) in each of the first indirect blocks */
    h5_stat_size_t     empty_size; /* Size of a file with an empty heap */
    size_t             obj_size;   /* Size of object */
    size_t             fill_size;  /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;      /* State of fractal heap */
    unsigned           u, v;       /* Local index variables */
    /* Test description */
    const char *base_desc = "fill root direct blocks, then fragment 2nd level indirect block's direct "
                            "blocks, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Compute # of bits used in first row */
    num_first_indirect_rows = IBLOCK_MAX_DROWS(fh, 1);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert objects small enough to fit into each direct block, but not to
     * share them with other objects of the same size.
     */
    for (u = 0; u < num_first_indirect_rows; u++) {
        obj_size = (size_t)DBLOCK_SIZE(fh, u) / 2;
        for (v = 0; v < cparam->managed.width; v++) {
            state.man_alloc_size += DBLOCK_SIZE(fh, u);
            if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
                TEST_ERROR;
        } /* end for */
    }     /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Go back and backfill all 2nd level indirect block's direct blocks */
    for (u = 0; u < num_first_indirect_rows; u++) {
        obj_size = (size_t)DBLOCK_FREE(fh, u) - ((size_t)DBLOCK_SIZE(fh, u) / 2);
        for (v = 0; v < cparam->managed.width; v++)
            if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
                TEST_ERROR;
    } /* end for */

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_frag_2nd_direct() */

/*-------------------------------------------------------------------------
 * Function:  test_man_frag_3rd_direct
 *
 * Purpose:   Test filling all direct blocks in root indirect block and
 *              all 2nd level indirect blocks, then
 *              inserting small object to fit into each direct block
 *              in 3rd level indirect block, but not to share a block with
 *              another object.
 *              Then, go back and fill in the space in the blocks skipped.
 *
 *              Then, go back and remove all objects
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_man_frag_3rd_direct(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    unsigned           root_direct_rows;             /* Number of rows in root indirect block */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    size_t             fill_size;                    /* Size of objects for "bulk" filled blocks */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u, v;                         /* Local index variables */
    /* Test description */
    const char *base_desc =
        "fill root direct blocks and 2nd level indirect blocks, then fragment 3rd level indirect block's "
        "direct blocks, then backfill and extend, then remove all objects";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, &fill_size) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Compute # of direct rows in root indirect block */
    root_direct_rows = DTABLE_MAX_DROWS(fh);

    /* Fill direct blocks in root indirect block */
    if (fill_root_direct(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Fill all rows of 2nd level indirect blocks in root indirect block */
    if (fill_all_2nd_indirect_rows(fh, fill_size, &state, &keep_ids))
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert objects small enough to fit into each direct block, but not to
     * share them with other objects of the same size.
     */
    for (u = 0; u < root_direct_rows; u++) {
        obj_size = (size_t)DBLOCK_SIZE(fh, u) / 2;
        for (v = 0; v < cparam->managed.width; v++) {
            state.man_alloc_size += DBLOCK_SIZE(fh, u);
            if (add_obj(fh, (size_t)10, obj_size, &state, &keep_ids))
                TEST_ERROR;
        } /* end for */
    }     /* end for */

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Go back and backfill all 3rd level indirect block's direct blocks */
    for (u = 0; u < root_direct_rows; u++) {
        obj_size = (size_t)DBLOCK_FREE(fh, u) - ((size_t)DBLOCK_SIZE(fh, u) / 2);
        for (v = 0; v < cparam->managed.width; v++)
            if (add_obj(fh, (size_t)20, obj_size, &state, &keep_ids))
                TEST_ERROR;
    } /* end for */

    /* Perform common file & heap close operations */
    if (close_heap(filename, fapl, tparam, file, f, &fh, fh_addr, &state, &keep_ids, empty_size) < 0)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_man_frag_3rd_direct() */

/*-------------------------------------------------------------------------
 * Function:  test_huge_insert_one
 *
 * Purpose:   Test inserting one huge object in the heap
 *
 *              Then, remove all the objects, in various ways
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_huge_insert_one(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    unsigned char     *heap_id = NULL;               /* Heap ID for object */
    size_t             obj_size;                     /* Size of object */
    size_t             robj_size;                    /* Size of object read */
    unsigned char      obj_type;                     /* Type of storage for object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "insert one huge object, then remove";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Allocate heap ID(s) */
    if (NULL == (heap_id = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;

    /* Make certain that 'huge' object's heap IDs are correct size */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != tparam->actual_id_len)
        TEST_ERROR;

    /* Insert object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size  = obj_size;
    state.huge_nobjs = 1;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in huge object */
    if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        /* Remove object from heap */
        if (H5HF_remove(fh, heap_id) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Check up on heap... */
        state.huge_size  = 0;
        state.huge_nobjs = 0;
        if (check_stats(fh, &state))
            TEST_ERROR;
    } /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(heap_id);
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(heap_id);
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_huge_insert_one() */

/*-------------------------------------------------------------------------
 * Function:  test_huge_insert_two
 *
 * Purpose:   Test inserting two huge objects in the heap
 *
 *              Then, remove all the objects, in various ways
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_huge_insert_two(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    unsigned char     *heap_id  = NULL;              /* Heap ID for first object */
    unsigned char     *heap_id2 = NULL;              /* Heap ID for second object */
    size_t             obj_size;                     /* Size of object */
    size_t             robj_size;                    /* Size of object read */
    unsigned char      obj_type;                     /* Type of storage for object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "insert two huge objects, then remove";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Allocate heap ID(s) */
    if (NULL == (heap_id = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id2 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;

    /* Make certain that 'huge' object's heap IDs are correct size */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != tparam->actual_id_len)
        TEST_ERROR;

    /* Insert object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size  = obj_size;
    state.huge_nobjs = 1;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in huge object */
    if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert second object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id2) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id2, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size += obj_size;
    state.huge_nobjs = 2;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in second huge object */
    if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id2, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        if (tparam->del_dir == FHEAP_DEL_FORWARD) {
            /* Remove first object from heap */
            if (H5HF_remove(fh, heap_id) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size  = obj_size;
            state.huge_nobjs = 1;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove second object from heap */
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size  = 0;
            state.huge_nobjs = 0;
            if (check_stats(fh, &state))
                TEST_ERROR;
        } /* end if */
        else {
            /* Remove second object from heap */
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size  = obj_size;
            state.huge_nobjs = 1;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove first object from heap */
            if (H5HF_remove(fh, heap_id) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size  = 0;
            state.huge_nobjs = 0;
            if (check_stats(fh, &state))
                TEST_ERROR;
        } /* end else */
    }     /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(heap_id);
    H5MM_xfree(heap_id2);
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(heap_id);
        H5MM_xfree(heap_id2);
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_huge_insert_two() */

/*-------------------------------------------------------------------------
 * Function:  test_huge_insert_three
 *
 * Purpose:   Test inserting three huge objects in the heap
 *
 *              Then, remove all the objects, in various ways
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_huge_insert_three(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    unsigned char     *heap_id  = NULL;              /* Heap ID for first object */
    unsigned char     *heap_id2 = NULL;              /* Heap ID for second object */
    unsigned char     *heap_id3 = NULL;              /* Heap ID for third object */
    size_t             obj_size;                     /* Size of object */
    size_t             robj_size;                    /* Size of object read */
    unsigned char      obj_type;                     /* Type of storage for object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "insert three huge objects, then remove";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Allocate heap ID(s) */
    if (NULL == (heap_id = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id2 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id3 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;

    /* Make certain that 'huge' object's heap IDs are correct size */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != tparam->actual_id_len)
        TEST_ERROR;

    /* Insert first object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size  = obj_size;
    state.huge_nobjs = 1;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in first huge object */
    if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert second object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id2) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id2, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size += obj_size;
    state.huge_nobjs = 2;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in second huge object */
    if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id2, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert third object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 3;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id3) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id3, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size += obj_size;
    state.huge_nobjs = 3;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in third huge object */
    if (H5HF_get_obj_len(fh, heap_id3, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id3, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        if (tparam->del_dir == FHEAP_DEL_FORWARD) {
            /* Remove first object from heap */
            if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove second object from heap */
            if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove third object from heap */
            if (H5HF_get_obj_len(fh, heap_id3, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id3) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;
        } /* end if */
        else {
            /* Remove third object from heap */
            if (H5HF_get_obj_len(fh, heap_id3, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id3) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove second object from heap */
            if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove first object from heap */
            if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;
        } /* end else */
    }     /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(heap_id);
    H5MM_xfree(heap_id2);
    H5MM_xfree(heap_id3);
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(heap_id);
        H5MM_xfree(heap_id2);
        H5MM_xfree(heap_id3);
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_huge_insert_three() */

/*-------------------------------------------------------------------------
 * Function:  test_huge_insert_mix
 *
 * Purpose:   Test inserting a mix of 'normal' & 'huge' objects in the heap
 *
 *              Then, remove all the objects, in various ways
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_huge_insert_mix(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    unsigned char     *heap_id  = NULL;              /* Heap ID for first object */
    unsigned char     *heap_id2 = NULL;              /* Heap ID for second object */
    unsigned char     *heap_id3 = NULL;              /* Heap ID for third object */
    unsigned char     *heap_id4 = NULL;              /* Heap ID for fourth object */
    unsigned char     *heap_id5 = NULL;              /* Heap ID for fifth object */
    size_t             obj_size;                     /* Size of object */
    size_t             robj_size;                    /* Size of object read */
    unsigned char      obj_type;                     /* Type of storage for object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "insert mix of normal & huge objects, then remove";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Allocate heap ID(s) */
    if (NULL == (heap_id = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id2 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id3 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id4 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id5 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;

    /* Make certain that 'huge' object's heap IDs are correct size */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != tparam->actual_id_len)
        TEST_ERROR;

    /* Insert first object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size += obj_size;
    state.huge_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in first huge object */
    if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert second object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id2) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id2, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size += obj_size;
    state.huge_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in second huge object */
    if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id2, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert third object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 3;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id3) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id3, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size += obj_size;
    state.huge_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in third huge object */
    if (H5HF_get_obj_len(fh, heap_id3, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id3, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert fourth object small enough to fit into 'normal' heap blocks */
    obj_size = (size_t)DBLOCK_SIZE(fh, 0) + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id4) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id4, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_MAN)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 1);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 2);
    state.man_alloc_size = DBLOCK_SIZE(fh, 2);
    state.man_free_space = cparam->managed.width * DBLOCK_FREE(fh, 0);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 1);
    state.man_free_space += DBLOCK_FREE(fh, 2) - obj_size;
    state.man_free_space += (cparam->managed.width - 1) * DBLOCK_FREE(fh, 2);
    state.man_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in fourth ('normal') object */
    if (H5HF_get_obj_len(fh, heap_id4, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id4, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert fifth object small enough to fit into 'normal' heap blocks */
    obj_size = (size_t)DBLOCK_SIZE(fh, 3) + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id5) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id5, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_MAN)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    /* (account for doubling of root indirect block) */
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 3);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 4);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 5);
    state.man_alloc_size += DBLOCK_SIZE(fh, 4);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 3);
    state.man_free_space += DBLOCK_FREE(fh, 4) - obj_size;
    state.man_free_space += (cparam->managed.width - 1) * DBLOCK_FREE(fh, 4);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 5);
    state.man_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in fifth ('normal') object */
    if (H5HF_get_obj_len(fh, heap_id5, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id5, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        if (tparam->del_dir == FHEAP_DEL_FORWARD) {
            /* Remove first object from heap */
            if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove second object from heap */
            if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove third object from heap */
            if (H5HF_get_obj_len(fh, heap_id3, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id3) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove fourth ('normal') object from heap */
            if (H5HF_remove(fh, heap_id4) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Remove fifth ('normal') object from heap */
            if (H5HF_remove(fh, heap_id5) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;
        } /* end if */
        else {
            /* Remove fifth ('normal') object from heap */
            if (H5HF_remove(fh, heap_id5) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Remove fourth ('normal') object from heap */
            if (H5HF_remove(fh, heap_id4) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Reset 'managed' object statistics after they are all removed  */
            state.man_nobjs      = 0;
            state.man_size       = 0;
            state.man_alloc_size = 0;
            state.man_free_space = 0;

            /* Remove third object from heap */
            if (H5HF_get_obj_len(fh, heap_id3, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id3) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove second object from heap */
            if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove first object from heap */
            if (H5HF_remove(fh, heap_id) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;
        } /* end else */

        /* Check up on heap... */
        memset(&state, 0, sizeof(fheap_heap_state_t));
        if (check_stats(fh, &state))
            TEST_ERROR;
    } /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(heap_id);
    H5MM_xfree(heap_id2);
    H5MM_xfree(heap_id3);
    H5MM_xfree(heap_id4);
    H5MM_xfree(heap_id5);
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(heap_id);
        H5MM_xfree(heap_id2);
        H5MM_xfree(heap_id3);
        H5MM_xfree(heap_id4);
        H5MM_xfree(heap_id5);
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_huge_insert_mix() */

/*-------------------------------------------------------------------------
 * Function:  test_filtered_huge
 *
 * Purpose:   Test storing 'huge' object in a heap with I/O filters
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_filtered_huge(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    H5HF_create_t      tmp_cparam;                   /* Local heap creation parameters */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    unsigned char     *heap_id = NULL;               /* Heap ID for object */
    size_t             obj_size;                     /* Size of object */
    size_t             robj_size;                    /* Size of object read */
    unsigned char      obj_type;                     /* Type of storage for object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           deflate_level;                /* Deflation level */
    size_t             old_actual_id_len = 0;        /* Old actual ID length */
    bool               huge_ids_direct;              /* Are 'huge' objects directly accessed? */
    bool               pline_init = false;           /* Whether the I/O pipeline has been initialized */
    /* Test description */
    const char *base_desc = "insert 'huge' object into heap with I/O filters, then remove";

    /* Copy heap creation properties */
    memcpy(&tmp_cparam, cparam, sizeof(H5HF_create_t));

    /* Set an I/O filter for heap data */
    deflate_level = 6;
    if (H5Z_append(&tmp_cparam.pline, H5Z_FILTER_DEFLATE, H5Z_FLAG_OPTIONAL, (size_t)1, &deflate_level) < 0)
        FAIL_STACK_ERROR;
    pline_init = true;

    /* Adjust actual ID length, if asking for IDs that can directly access 'huge' objects */
    if (cparam->id_len == 1) {
        old_actual_id_len     = tparam->actual_id_len;
        tparam->actual_id_len = 29; /* 1 + 8 (file address size) + 8 (file length size) + 4 (filter mask
                                       length) + 8 (object length size) */
    }                               /* end if */

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, &tmp_cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Allocate heap ID(s) */
    if (NULL == (heap_id = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;

    /* Make certain that 'huge' object's heap IDs are correct form */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != tparam->actual_id_len)
        TEST_ERROR;
    if (H5HF_get_huge_info_test(fh, NULL, &huge_ids_direct) < 0)
        FAIL_STACK_ERROR;
    if (cparam->id_len == 1) {
        if (huge_ids_direct != true)
            TEST_ERROR;
    } /* end if */
    else if (tparam->actual_id_len >= 29) {
        if (huge_ids_direct != true)
            TEST_ERROR;
    } /* end if */
    else {
        if (huge_ids_direct != false)
            TEST_ERROR;
    } /* end else */

    /* Insert object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

#ifdef QAK
    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDONLY, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        STACK_ERROR;

    /* Re-open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;
#endif /* QAK */

    /* Check up on heap... */
    state.huge_size  = obj_size;
    state.huge_nobjs = 1;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in huge object */
    if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        /* Remove object from heap */
        if (H5HF_remove(fh, heap_id) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Check up on heap... */
        state.huge_size  = 0;
        state.huge_nobjs = 0;
        if (check_stats(fh, &state))
            TEST_ERROR;
    } /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Reset actual ID length, if asking for IDs that can directly access 'huge' objects */
    if (cparam->id_len == 1)
        tparam->actual_id_len = old_actual_id_len;

    /* Free resources */
    H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline); /* Release the I/O pipeline filter information */
    H5MM_xfree(heap_id);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(heap_id);
        if (fh)
            H5HF_close(fh);
        if (pline_init)
            H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline); /* Release the I/O pipeline filter information */
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_filtered_huge() */

/*-------------------------------------------------------------------------
 * Function:  test_tiny_insert_one
 *
 * Purpose:   Test inserting one tiny object in the heap
 *
 *              Then, remove all the objects, in various ways
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_tiny_insert_one(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    unsigned char     *heap_id = NULL;               /* Heap ID for object */
    size_t             obj_size;                     /* Size of object */
    size_t             robj_size;                    /* Size of object read */
    unsigned char      obj_type;                     /* Type of storage for object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "insert one tiny object, then remove";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Allocate heap ID(s) */
    if (NULL == (heap_id = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;

    /* Make certain that 'tiny' object's heap IDs are correct size */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != tparam->actual_id_len)
        TEST_ERROR;

    /* Insert object small enough to encode in heap ID */
    obj_size = tparam->actual_id_len - 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_TINY)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.tiny_size  = obj_size;
    state.tiny_nobjs = 1;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in tiny object */
    if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        /* Remove object from heap */
        if (H5HF_remove(fh, heap_id) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Check up on heap... */
        state.tiny_size  = 0;
        state.tiny_nobjs = 0;
        if (check_stats(fh, &state))
            TEST_ERROR;
    } /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(heap_id);
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(heap_id);
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_tiny_insert_one() */

/*-------------------------------------------------------------------------
 * Function:  test_tiny_insert_two
 *
 * Purpose:   Test inserting two tiny objects in the heap
 *
 *              Then, remove all the objects, in various ways
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_tiny_insert_two(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    unsigned char     *heap_id  = NULL;              /* Heap ID for first object */
    unsigned char     *heap_id2 = NULL;              /* Heap ID for second object */
    size_t             obj_size;                     /* Size of object */
    size_t             robj_size;                    /* Size of object read */
    unsigned char      obj_type;                     /* Type of storage for object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "insert two tiny objects, then remove";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Allocate heap ID(s) */
    if (NULL == (heap_id = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id2 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;

    /* Make certain that 'tiny' object's heap IDs are correct size */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != tparam->actual_id_len)
        TEST_ERROR;

    /* Insert object small enough to encode in heap ID */
    obj_size = tparam->actual_id_len - 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_TINY)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.tiny_size  = obj_size;
    state.tiny_nobjs = 1;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in tiny object */
    if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert second object small enough to encode in heap ID */
    obj_size = tparam->actual_id_len - 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id2) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id2, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_TINY)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.tiny_size += obj_size;
    state.tiny_nobjs = 2;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in second tiny object */
    if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id2, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        if (tparam->del_dir == FHEAP_DEL_FORWARD) {
            /* Remove first object from heap */
            if (H5HF_remove(fh, heap_id) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.tiny_size  = obj_size;
            state.tiny_nobjs = 1;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove second object from heap */
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.tiny_size  = 0;
            state.tiny_nobjs = 0;
            if (check_stats(fh, &state))
                TEST_ERROR;
        } /* end if */
        else {
            /* Remove second object from heap */
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.tiny_size  = obj_size;
            state.tiny_nobjs = 1;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove first object from heap */
            if (H5HF_remove(fh, heap_id) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.tiny_size  = 0;
            state.tiny_nobjs = 0;
            if (check_stats(fh, &state))
                TEST_ERROR;
        } /* end else */
    }     /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(heap_id);
    H5MM_xfree(heap_id2);
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(heap_id);
        H5MM_xfree(heap_id2);
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_tiny_insert_two() */

/*-------------------------------------------------------------------------
 * Function:  test_tiny_insert_mix
 *
 * Purpose:   Test inserting a mix of 'normal', 'huge' & 'tiny' objects in
 *              the heap
 *
 *              Then, remove all the objects, in various ways
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_tiny_insert_mix(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    size_t             id_len;                       /* Size of fractal heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    unsigned char     *heap_id  = NULL;              /* Heap ID for first object */
    unsigned char     *heap_id2 = NULL;              /* Heap ID for second object */
    unsigned char     *heap_id3 = NULL;              /* Heap ID for third object */
    unsigned char     *heap_id4 = NULL;              /* Heap ID for fourth object */
    unsigned char     *heap_id5 = NULL;              /* Heap ID for fifth object */
    unsigned char     *heap_id6 = NULL;              /* Heap ID for sixth object */
    unsigned char     *heap_id7 = NULL;              /* Heap ID for seventh object */
    size_t             obj_size;                     /* Size of object */
    size_t             robj_size;                    /* Size of object read */
    unsigned char      obj_type;                     /* Type of storage for object */
    fheap_heap_state_t state;                        /* State of fractal heap */
    /* Test description */
    const char *base_desc = "insert mix of normal, huge & tiny objects, then remove";

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Allocate heap ID(s) */
    if (NULL == (heap_id = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id2 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id3 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id4 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id5 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id6 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;
    if (NULL == (heap_id7 = (unsigned char *)H5MM_malloc(tparam->actual_id_len)))
        TEST_ERROR;

    /* Make certain that 'tiny' object's heap IDs are correct size */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len != tparam->actual_id_len)
        TEST_ERROR;

    /* Insert first object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size += obj_size;
    state.huge_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in first huge object */
    if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Check 'op' functionality on first huge object */
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_op(fh, heap_id, op_memcpy, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert second object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id2) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id2, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size += obj_size;
    state.huge_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in second huge object */
    if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id2, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Check 'op' functionality on second huge object */
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_op(fh, heap_id2, op_memcpy, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert third object too large for managed heap blocks */
    obj_size = SMALL_STAND_SIZE + 3;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id3) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id3, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_HUGE)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.huge_size += obj_size;
    state.huge_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in third huge object */
    if (H5HF_get_obj_len(fh, heap_id3, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id3, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Check 'op' functionality on third huge object */
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_op(fh, heap_id3, op_memcpy, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert fourth object small enough to fit into 'normal' heap blocks */
    obj_size = (size_t)DBLOCK_SIZE(fh, 0) + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id4) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id4, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_MAN)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.man_size = cparam->managed.width * DBLOCK_SIZE(fh, 0);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 1);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 2);
    state.man_alloc_size = DBLOCK_SIZE(fh, 2);
    state.man_free_space = cparam->managed.width * DBLOCK_FREE(fh, 0);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 1);
    state.man_free_space += DBLOCK_FREE(fh, 2) - obj_size;
    state.man_free_space += (cparam->managed.width - 1) * DBLOCK_FREE(fh, 2);
    state.man_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in fourth ('normal') object */
    if (H5HF_get_obj_len(fh, heap_id4, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id4, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Check 'op' functionality on fourth ('normal') object */
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_op(fh, heap_id4, op_memcpy, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert fifth object small enough to fit into 'normal' heap blocks */
    obj_size = (size_t)DBLOCK_SIZE(fh, 3) + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id5) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id5, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_MAN)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    /* (account for doubling of root indirect block) */
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 3);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 4);
    state.man_size += cparam->managed.width * DBLOCK_SIZE(fh, 5);
    state.man_alloc_size += DBLOCK_SIZE(fh, 4);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 3);
    state.man_free_space += DBLOCK_FREE(fh, 4) - obj_size;
    state.man_free_space += (cparam->managed.width - 1) * DBLOCK_FREE(fh, 4);
    state.man_free_space += cparam->managed.width * DBLOCK_FREE(fh, 5);
    state.man_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in fifth ('normal') object */
    if (H5HF_get_obj_len(fh, heap_id5, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id5, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Check 'op' functionality on fifth ('normal') object */
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_op(fh, heap_id5, op_memcpy, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert sixth object small enough to encode in heap ID */
    obj_size = tparam->actual_id_len - 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id6) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id6, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_TINY)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.tiny_size  = obj_size;
    state.tiny_nobjs = 1;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in tiny object */
    if (H5HF_get_obj_len(fh, heap_id6, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id6, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Check 'op' functionality on sixth ('tiny') object */
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_op(fh, heap_id6, op_memcpy, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Insert seventh object small enough to encode in heap ID */
    obj_size = tparam->actual_id_len - 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id7) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id7, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_TINY)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Check up on heap... */
    state.tiny_size += obj_size;
    state.tiny_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in tiny object */
    if (H5HF_get_obj_len(fh, heap_id7, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id7, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Check 'op' functionality on seventh ('tiny') object */
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_op(fh, heap_id7, op_memcpy, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        if (tparam->del_dir == FHEAP_DEL_FORWARD) {
            /* Remove first object from heap */
            if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove second object from heap */
            if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove third object from heap */
            if (H5HF_get_obj_len(fh, heap_id3, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id3) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove fourth ('normal') object from heap */
            if (H5HF_remove(fh, heap_id4) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Remove fifth ('normal') object from heap */
            if (H5HF_remove(fh, heap_id5) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Reset 'managed' object statistics after they are all removed  */
            state.man_nobjs      = 0;
            state.man_size       = 0;
            state.man_alloc_size = 0;
            state.man_free_space = 0;

            /* Remove sixth object from heap */
            if (H5HF_get_obj_len(fh, heap_id6, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id6) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.tiny_size -= robj_size;
            state.tiny_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove seventh object from heap */
            if (H5HF_remove(fh, heap_id7) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;
        } /* end if */
        else {
            /* Remove seventh object from heap */
            if (H5HF_get_obj_len(fh, heap_id7, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id7) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.tiny_size -= robj_size;
            state.tiny_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove sixth object from heap */
            if (H5HF_get_obj_len(fh, heap_id6, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id6) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.tiny_size -= robj_size;
            state.tiny_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove fifth ('normal') object from heap */
            if (H5HF_remove(fh, heap_id5) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Remove fourth ('normal') object from heap */
            if (H5HF_remove(fh, heap_id4) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Reset 'managed' object statistics after they are all removed  */
            state.man_nobjs      = 0;
            state.man_size       = 0;
            state.man_alloc_size = 0;
            state.man_free_space = 0;

            /* Remove third object from heap */
            if (H5HF_get_obj_len(fh, heap_id3, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id3) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove second object from heap */
            if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;

            /* Check up on heap... */
            state.huge_size -= robj_size;
            state.huge_nobjs--;
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Remove first object from heap */
            if (H5HF_remove(fh, heap_id) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;
        } /* end else */

        /* Check up on heap... */
        memset(&state, 0, sizeof(fheap_heap_state_t));
        if (check_stats(fh, &state))
            TEST_ERROR;
    } /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Free resources */
    H5MM_xfree(heap_id);
    H5MM_xfree(heap_id2);
    H5MM_xfree(heap_id3);
    H5MM_xfree(heap_id4);
    H5MM_xfree(heap_id5);
    H5MM_xfree(heap_id6);
    H5MM_xfree(heap_id7);
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(heap_id);
        H5MM_xfree(heap_id2);
        H5MM_xfree(heap_id3);
        H5MM_xfree(heap_id4);
        H5MM_xfree(heap_id5);
        H5MM_xfree(heap_id6);
        H5MM_xfree(heap_id7);
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_tiny_insert_mix() */

/*-------------------------------------------------------------------------
 * Function:  test_filtered_man_root_direct
 *
 * Purpose:   Test storing one 'managed' object in a heap with I/O filters
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_filtered_man_root_direct(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    H5HF_create_t    tmp_cparam;                   /* Local heap creation parameters */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t   empty_size;                   /* Size of a file with an empty heap */
#ifdef NOT_YET
    h5_stat_size_t file_size;                /* Size of file currently */
#endif                                       /* NOT_YET */
    unsigned char      heap_id[HEAP_ID_LEN]; /* Heap ID for object */
    size_t             obj_size;             /* Size of object */
    size_t             robj_size;            /* Size of object read */
    unsigned char      obj_type;             /* Type of storage for object */
    fheap_heap_state_t state;                /* State of fractal heap */
    unsigned           deflate_level;        /* Deflation level */
    /* Test description */
    const char *base_desc = "insert one 'managed' object into heap with I/O filters, then remove";

    /* Copy heap creation properties */
    memcpy(&tmp_cparam, cparam, sizeof(H5HF_create_t));

    /* Set an I/O filter for heap data */
    deflate_level = 6;
    if (H5Z_append(&tmp_cparam.pline, H5Z_FILTER_DEFLATE, H5Z_FLAG_OPTIONAL, (size_t)1, &deflate_level) < 0)
        FAIL_STACK_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, &tmp_cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Insert object small enough to fit into direct heap block */
    obj_size = (size_t)DBLOCK_SIZE(fh, 0) / 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_MAN)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Check up on heap... */
    state.man_size       = DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = DBLOCK_SIZE(fh, 0);
    state.man_free_space = DBLOCK_FREE(fh, 0) - obj_size;
    state.man_nobjs++;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in ('normal') object */
    if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        /* Remove object from heap */
        if (H5HF_get_obj_len(fh, heap_id, &robj_size) < 0)
            FAIL_STACK_ERROR;
        if (H5HF_remove(fh, heap_id) < 0)
            FAIL_STACK_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Check up on heap... */
        memset(&state, 0, sizeof(fheap_heap_state_t));
        if (check_stats(fh, &state))
            TEST_ERROR;
    } /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

/* Needs file free space to be persistent */
#ifdef NOT_YET
    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;
#endif /* NOT_YET */

    /* Free resources */
    H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline); /* Release the I/O pipeline filter information */

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_filtered_man_root_direct() */

/*-------------------------------------------------------------------------
 * Function:  test_filtered_man_root_indirect
 *
 * Purpose:   Test storing several objects in a 'managed heap with I/O filters
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_filtered_man_root_indirect(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t            file = H5I_INVALID_HID;       /* File ID */
    char             filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t           *f  = NULL;                    /* Internal file object pointer */
    H5HF_t          *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t          fh_addr;                      /* Address of fractal heap */
    H5HF_create_t    tmp_cparam;                   /* Local heap creation parameters */
    fheap_heap_ids_t keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t   empty_size;                   /* Size of a file with an empty heap */
#ifdef NOT_YET
    h5_stat_size_t file_size;                 /* Size of file currently */
#endif                                        /* NOT_YET */
    unsigned char      heap_id1[HEAP_ID_LEN]; /* Heap ID for object #1 */
    unsigned char      heap_id2[HEAP_ID_LEN]; /* Heap ID for object #2 */
    size_t             obj_size;              /* Size of object */
    size_t             robj_size;             /* Size of object read */
    unsigned char      obj_type;              /* Type of storage for object */
    fheap_heap_state_t state;                 /* State of fractal heap */
    unsigned           deflate_level;         /* Deflation level */
    /* Test description */
    const char *base_desc = "insert two 'managed' objects into heap with I/O filters, then remove";

    /* Copy heap creation properties */
    memcpy(&tmp_cparam, cparam, sizeof(H5HF_create_t));

    /* Set an I/O filter for heap data */
    deflate_level = 6;
    if (H5Z_append(&tmp_cparam.pline, H5Z_FILTER_DEFLATE, H5Z_FLAG_OPTIONAL, (size_t)1, &deflate_level) < 0)
        FAIL_STACK_ERROR;

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, &tmp_cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Perform common test initialization operations */
    if (begin_test(tparam, base_desc, &keep_ids, NULL) < 0)
        TEST_ERROR;

    /* Insert object #1, small enough to fit into direct heap block */
    obj_size = (size_t)DBLOCK_SIZE(fh, 0) / 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id1) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id1, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_MAN)
        TEST_ERROR;

    /* Check for closing & re-opening the heap */
    if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
        TEST_ERROR;

    /* Insert object #2, small enough to fit into direct heap block */
    obj_size = (size_t)DBLOCK_SIZE(fh, 0) / 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, heap_id2) < 0)
        FAIL_STACK_ERROR;
    if (H5HF_get_id_type_test(heap_id2, &obj_type) < 0)
        FAIL_STACK_ERROR;
    if (obj_type != H5HF_ID_TYPE_MAN)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Check up on heap... */
    state.man_size       = cparam->managed.width * DBLOCK_SIZE(fh, 0);
    state.man_alloc_size = 2 * DBLOCK_SIZE(fh, 0);
    state.man_free_space = (cparam->managed.width * DBLOCK_FREE(fh, 0)) - (obj_size * 2);
    state.man_nobjs += 2;
    if (check_stats(fh, &state))
        TEST_ERROR;

    /* Read in ('normal') object #1 */
    if (H5HF_get_obj_len(fh, heap_id1, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id1, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Read in ('normal') object #2 */
    if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
        FAIL_STACK_ERROR;
    if (obj_size != robj_size)
        TEST_ERROR;
    memset(shared_robj_g, 0, obj_size);
    if (H5HF_read(fh, heap_id2, shared_robj_g) < 0)
        FAIL_STACK_ERROR;
    if (memcmp(shared_wobj_g, shared_robj_g, obj_size) != 0)
        TEST_ERROR;

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        if (tparam->del_dir == FHEAP_DEL_FORWARD) {
            /* Remove object #1 from heap */
            if (H5HF_get_obj_len(fh, heap_id1, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id1) < 0)
                FAIL_STACK_ERROR;

            /* Close the fractal heap */
            if (H5HF_close(fh) < 0)
                FAIL_STACK_ERROR;
            fh = NULL;

            /* Close the file */
            if (H5Fclose(file) < 0)
                FAIL_STACK_ERROR;

            /* Re-open the file */
            if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
                FAIL_STACK_ERROR;

            /* Get a pointer to the internal file object */
            if (NULL == (f = (H5F_t *)H5VL_object(file)))
                FAIL_STACK_ERROR;

            /* Ignore metadata tags in the file's cache */
            if (H5AC_ignore_tags(f) < 0)
                FAIL_STACK_ERROR;

            /* Re-open the heap */
            if (NULL == (fh = H5HF_open(f, fh_addr)))
                FAIL_STACK_ERROR;

            /* Remove object #2 from heap */
            if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Check up on heap... */
            memset(&state, 0, sizeof(fheap_heap_state_t));
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Close the fractal heap */
            if (H5HF_close(fh) < 0)
                FAIL_STACK_ERROR;
            fh = NULL;

            /* Close the file */
            if (H5Fclose(file) < 0)
                FAIL_STACK_ERROR;

            /* Re-open the file */
            if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
                FAIL_STACK_ERROR;

            /* Get a pointer to the internal file object */
            if (NULL == (f = (H5F_t *)H5VL_object(file)))
                FAIL_STACK_ERROR;

            /* Ignore metadata tags in the file's cache */
            if (H5AC_ignore_tags(f) < 0)
                FAIL_STACK_ERROR;

            /* Re-open the heap */
            if (NULL == (fh = H5HF_open(f, fh_addr)))
                FAIL_STACK_ERROR;

            /* Check up on heap... */
            memset(&state, 0, sizeof(fheap_heap_state_t));
            if (check_stats(fh, &state))
                TEST_ERROR;
        } /* end if */
        else {
            /* Remove object #2 from heap */
            if (H5HF_get_obj_len(fh, heap_id2, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id2) < 0)
                FAIL_STACK_ERROR;

            /* Close the fractal heap */
            if (H5HF_close(fh) < 0)
                FAIL_STACK_ERROR;
            fh = NULL;

            /* Close the file */
            if (H5Fclose(file) < 0)
                FAIL_STACK_ERROR;

            /* Re-open the file */
            if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
                FAIL_STACK_ERROR;

            /* Get a pointer to the internal file object */
            if (NULL == (f = (H5F_t *)H5VL_object(file)))
                FAIL_STACK_ERROR;

            /* Ignore metadata tags in the file's cache */
            if (H5AC_ignore_tags(f) < 0)
                FAIL_STACK_ERROR;

            /* Re-open the heap */
            if (NULL == (fh = H5HF_open(f, fh_addr)))
                FAIL_STACK_ERROR;

            /* Remove object #1 from heap */
            if (H5HF_get_obj_len(fh, heap_id1, &robj_size) < 0)
                FAIL_STACK_ERROR;
            if (H5HF_remove(fh, heap_id1) < 0)
                FAIL_STACK_ERROR;

            /* Check up on heap... */
            memset(&state, 0, sizeof(fheap_heap_state_t));
            if (check_stats(fh, &state))
                TEST_ERROR;

            /* Close the fractal heap */
            if (H5HF_close(fh) < 0)
                FAIL_STACK_ERROR;
            fh = NULL;

            /* Close the file */
            if (H5Fclose(file) < 0)
                FAIL_STACK_ERROR;

            /* Re-open the file */
            if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
                FAIL_STACK_ERROR;

            /* Get a pointer to the internal file object */
            if (NULL == (f = (H5F_t *)H5VL_object(file)))
                FAIL_STACK_ERROR;

            /* Ignore metadata tags in the file's cache */
            if (H5AC_ignore_tags(f) < 0)
                FAIL_STACK_ERROR;

            /* Re-open the heap */
            if (NULL == (fh = H5HF_open(f, fh_addr)))
                FAIL_STACK_ERROR;

            /* Check up on heap... */
            memset(&state, 0, sizeof(fheap_heap_state_t));
            if (check_stats(fh, &state))
                TEST_ERROR;
        } /* end else */
    }     /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

/* Needs file free space to be persistent */
#ifdef NOT_YET
    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;
#endif /* NOT_YET */

    /* Free resources */
    H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline); /* Release the I/O pipeline filter information */

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_filtered_man_root_indirect() */

/*-------------------------------------------------------------------------
 * Function:  test_random
 *
 * Purpose:   Test inserting random sized objects into a heap, and read
 *              them back.
 *
 *              Then, go back and remove all objects
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_random(hsize_t size_limit, hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    H5HF_create_t      tmp_cparam;                   /* Local heap creation parameters */
    size_t             id_len;                       /* Size of fractal heap IDs */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    unsigned long      seed = 0;                     /* Random # seed */
    hsize_t            total_obj_added;              /* Size of objects added */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    size_t             obj_size;                     /* Size of object */
    size_t             obj_loc;                      /* Location of object in buffer */
    fheap_heap_state_t state;                        /* State of fractal heap */
    size_t             u;                            /* Local index variable */

    /* Initialize the heap ID structure */
    memset(&keep_ids, 0, sizeof(fheap_heap_ids_t));

    /* Copy heap creation properties */
    memcpy(&tmp_cparam, cparam, sizeof(H5HF_create_t));

    /* Check if we are compressing the blocks */
    if (tparam->comp == FHEAP_TEST_COMPRESS) {
        unsigned deflate_level; /* Deflation level */

        /* Set an I/O filter for heap data */
        deflate_level = 6;
        if (H5Z_append(&tmp_cparam.pline, H5Z_FILTER_DEFLATE, H5Z_FLAG_OPTIONAL, (size_t)1, &deflate_level) <
            0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, &tmp_cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Get information about heap ID lengths */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > MAX_HEAP_ID_LEN)
        TEST_ERROR;

    /*
     * Display testing message
     */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        if (tparam->comp == FHEAP_TEST_COMPRESS)
            TESTING("inserting random-sized objects in heap with compressed blocks, then remove all objects "
                    "(all - deleting heap)");
        else
            TESTING("inserting random-sized objects, then remove all objects (all - deleting heap)");
    } /* end if */
    else {
        if (tparam->comp == FHEAP_TEST_COMPRESS)
            TESTING("inserting random-sized objects in heap with compressed blocks, then remove all objects "
                    "(all - random)");
        else
            TESTING("inserting random-sized objects, then remove all objects (all - random)");
    } /* end else */

    /* Choose random # seed */
    seed = (unsigned long)time(NULL);
#if 0
/* seed = (unsigned long)1156158635; */
fprintf(stderr, "Random # seed was: %lu\n", seed);
#endif
    HDsrandom((unsigned)seed);

    /* Loop over adding objects to the heap, until the size limit is reached */
    total_obj_added = 0;
    while (total_obj_added < size_limit) {
        /* Choose a random size of object (from 1 up to above standalone block size limit) */
        obj_size = (((uint32_t)HDrandom() % (tmp_cparam.max_man_size + 255)) + 1);
        obj_loc  = (tmp_cparam.max_man_size + 255) - obj_size;

        /* Insert object */
        if (add_obj(fh, obj_loc, obj_size, NULL, &keep_ids))
            TEST_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Increment the amount of objects added */
        total_obj_added += obj_size;
    } /* end while */

    /* Randomize the order of the IDs kept */
    for (u = 0; u < keep_ids.num_ids; u++) {
        size_t pos; /* Position to swap with */

        /* Choose a position to swap with */
        /* (0 is current position) */
        pos = ((size_t)HDrandom() % (keep_ids.num_ids - u));

        /* If we chose a different position, swap with it */
        if (pos > 0) {
            unsigned char temp_id[MAX_HEAP_ID_LEN]; /* Temp. heap ID holder */

            /* Swap current position with future position */
            /* (just swap the heap ID, the len & offset isn't used */
            memcpy(temp_id, &keep_ids.ids[u * id_len], id_len);
            memcpy(&keep_ids.ids[u * id_len], &keep_ids.ids[(u + pos) * id_len], id_len);
            memcpy(&keep_ids.ids[(u + pos) * id_len], temp_id, id_len);
        } /* end if */
    }     /* end for */

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        /* Delete objects inserted */
        for (u = 0; u < keep_ids.num_ids; u++) {
            /* Remove object from heap */
            if (H5HF_remove(fh, &keep_ids.ids[id_len * u]) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;
        } /* end for */

        /* Check up on heap... */
        if (check_stats(fh, &state))
            TEST_ERROR;
    } /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Free resources */
    if (tparam->comp == FHEAP_TEST_COMPRESS)
        H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline); /* Release the I/O pipeline filter information */

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    fprintf(stderr, "Random # seed was: %lu\n", seed);
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);

        if (tparam->comp == FHEAP_TEST_COMPRESS)
            H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline); /* Release the I/O pipeline filter information */
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_random() */

/*-------------------------------------------------------------------------
 * Function:  test_random_pow2
 *
 * Purpose:   Test inserting random sized objects with a "power of 2
 *              distribution" (which favors small objects) into a heap,
 *              and read them back.
 *
 *              Then, go back and remove all objects
 *
 * Return:    Success:    0
 *
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_random_pow2(hsize_t size_limit, hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    H5HF_create_t      tmp_cparam;                   /* Local heap creation parameters */
    size_t             id_len;                       /* Size of fractal heap IDs */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    unsigned long      seed = 0;                     /* Random # seed */
    hsize_t            total_obj_added;              /* Size of objects added */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    h5_stat_size_t     file_size;                    /* Size of file currently */
    size_t             obj_size;                     /* Size of object */
    size_t             obj_loc;                      /* Location of object in buffer */
    fheap_heap_state_t state;                        /* State of fractal heap */
    size_t             u;                            /* Local index variable */

    /* Initialize the heap ID structure */
    memset(&keep_ids, 0, sizeof(fheap_heap_ids_t));

    /* Copy heap creation properties */
    memcpy(&tmp_cparam, cparam, sizeof(H5HF_create_t));

    /* Check if we are compressing the blocks */
    if (tparam->comp == FHEAP_TEST_COMPRESS) {
        unsigned deflate_level; /* Deflation level */

        /* Set an I/O filter for heap data */
        deflate_level = 6;
        if (H5Z_append(&tmp_cparam.pline, H5Z_FILTER_DEFLATE, H5Z_FLAG_OPTIONAL, (size_t)1, &deflate_level) <
            0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, &tmp_cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Get information about heap ID lengths */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > MAX_HEAP_ID_LEN)
        TEST_ERROR;

    /*
     * Display testing message
     */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        if (tparam->comp == FHEAP_TEST_COMPRESS)
            TESTING("inserting random-sized objects with power of 2 distribution in heap with compressed "
                    "blocks, then remove all objects (all - deleting heap)");
        else
            TESTING("inserting random-sized objects with power of 2 distribution, then remove all objects "
                    "(all - deleting heap)");
    } /* end if */
    else {
        if (tparam->comp == FHEAP_TEST_COMPRESS)
            TESTING("inserting random-sized objects with power of 2 distribution in heap with compressed "
                    "blocks, then remove all objects (all - random)");
        else
            TESTING("inserting random-sized objects with power of 2 distribution, then remove all objects "
                    "(all - random)");
    } /* end else */

    /* Choose random # seed */
    seed = (unsigned long)time(NULL);
#if 0
/* seed = (unsigned long)1155181717; */
fprintf(stderr, "Random # seed was: %lu\n", seed);
#endif
    HDsrandom((unsigned)seed);

    /* Loop over adding objects to the heap, until the size limit is reached */
    total_obj_added = 0;
    while (total_obj_added < size_limit) {
        size_t size_range = (tmp_cparam.managed.start_block_size / 8); /* Object size range */

        /* Determine the size of the range for this object */
        /* (50% of the objects inserted will use the initial size range,
         *      25% of the objects will be twice as large, 12.5% will be
         *      four times larger, etc.)
         */
        while (HDrandom() < (RAND_MAX / 2) && size_range < tmp_cparam.max_man_size)
            size_range *= 2;
        if (size_range > (tmp_cparam.max_man_size + 255))
            size_range = tmp_cparam.max_man_size + 255;

        /* Choose a random size of object (from 1 up to stand alone block size) */
        obj_size = (((unsigned)HDrandom() % (size_range - 1)) + 1);
        obj_loc  = (tmp_cparam.max_man_size + 255) - obj_size;

        /* Insert object */
        if (add_obj(fh, obj_loc, obj_size, NULL, &keep_ids))
            TEST_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Increment the amount of objects added */
        total_obj_added += obj_size;
    } /* end while */

    /* Randomize the order of the IDs kept */
    for (u = 0; u < keep_ids.num_ids; u++) {
        size_t pos; /* Position to swap with */

        /* Choose a position to swap with */
        /* (0 is current position) */
        pos = ((size_t)HDrandom() % (keep_ids.num_ids - u));

        /* If we chose a different position, swap with it */
        if (pos > 0) {
            unsigned char temp_id[MAX_HEAP_ID_LEN]; /* Temp. heap ID holder */

            /* Swap current position with future position */
            /* (just swap the heap ID, the len & offset isn't used */
            memcpy(temp_id, &keep_ids.ids[u * id_len], id_len);
            memcpy(&keep_ids.ids[u * id_len], &keep_ids.ids[(u + pos) * id_len], id_len);
            memcpy(&keep_ids.ids[(u + pos) * id_len], temp_id, id_len);
        } /* end if */
    }     /* end for */

    /* Delete individual objects, if we won't be deleting the entire heap later */
    if (tparam->del_dir != FHEAP_DEL_HEAP) {
        /* Delete objects inserted */
        for (u = 0; u < keep_ids.num_ids; u++) {
            /* Remove object from heap */
            if (H5HF_remove(fh, &keep_ids.ids[id_len * u]) < 0)
                FAIL_STACK_ERROR;

            /* Check for closing & re-opening the heap */
            if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
                TEST_ERROR;
        } /* end for */

        /* Check up on heap... */
        if (check_stats(fh, &state))
            TEST_ERROR;
    } /* end if */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Check for deleting the entire heap */
    if (tparam->del_dir == FHEAP_DEL_HEAP) {
        /* Delete heap */
        if (H5HF_delete(f, fh_addr) < 0)
            FAIL_STACK_ERROR;
    } /* end if */

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Get the size of the file */
    if ((file_size = h5_get_file_size(filename, fapl)) < 0)
        TEST_ERROR;

    /* Verify the file is correct size */
    if (file_size != empty_size)
        TEST_ERROR;

    /* Free resources */
    if (tparam->comp == FHEAP_TEST_COMPRESS)
        H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline); /* Release the I/O pipeline filter information */

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    fprintf(stderr, "Random # seed was: %lu\n", seed);
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        if (tparam->comp == FHEAP_TEST_COMPRESS)
            H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline); /* Release the I/O pipeline filter information */
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_random_pow2() */

/*-------------------------------------------------------------------------
 * Function:  test_write
 *
 * Purpose:   Test inserting objects, then changing the value for them.
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
/* Custom filter used to verify that the filters are actually called and do not
 * just silently fail */
static bool test_write_filter_called;
static size_t
test_write_filter(unsigned int H5_ATTR_UNUSED flags, size_t H5_ATTR_UNUSED cd_nelmts,
                  const unsigned int H5_ATTR_UNUSED cd_values[], size_t nbytes,
                  size_t H5_ATTR_UNUSED *buf_size, void H5_ATTR_UNUSED **buf)
{
    test_write_filter_called = true;

    return nbytes;
} /* end link_filter_filter */

static unsigned
test_write(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    H5HF_create_t      tmp_cparam;                   /* Local heap creation parameters */
    size_t             id_len;                       /* Size of fractal heap IDs */
    unsigned char      tiny_heap_id[HEAP_ID_LEN];    /* Heap ID for 'tiny' object */
    unsigned char      huge_heap_id[HEAP_ID_LEN];    /* Heap ID for 'huge' object */
    bool               id_changed  = false;          /* Whether the heap ID changed */
    unsigned char     *rewrite_obj = NULL;           /* Pointer to re-write buffer for objects */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    size_t             obj_loc;                      /* Location of object in buffer */
    fheap_heap_state_t state;                        /* State of fractal heap */
    unsigned           u;                            /* Local index variable */
    herr_t             ret;                          /* Generic return value */

    /*
     * Display testing message
     */
    if (tparam->comp == FHEAP_TEST_COMPRESS)
        TESTING("writing objects in heap with compressed blocks");
    else
        TESTING("writing objects in heap");

    /* Initialize the heap ID structure */
    memset(&keep_ids, 0, sizeof(fheap_heap_ids_t));

    /* Copy heap creation properties */
    memcpy(&tmp_cparam, cparam, sizeof(H5HF_create_t));

    /* Check if we are compressing the blocks */
    if (tparam->comp == FHEAP_TEST_COMPRESS) {
        H5Z_class2_t filter_class;  /* Custom filter */
        unsigned     deflate_level; /* Deflation level */

        /* Set an I/O filter for heap data */
        deflate_level = 6;
        if (H5Z_append(&tmp_cparam.pline, H5Z_FILTER_DEFLATE, H5Z_FLAG_OPTIONAL, (size_t)1, &deflate_level) <
            0)
            FAIL_STACK_ERROR;

        /* Register and append custom filter */
        filter_class.version         = H5Z_CLASS_T_VERS;
        filter_class.id              = H5Z_FILTER_RESERVED + 43;
        filter_class.encoder_present = true;
        filter_class.decoder_present = true;
        filter_class.name            = "custom_fheap_filter";
        filter_class.can_apply       = NULL;
        filter_class.set_local       = NULL;
        filter_class.filter          = test_write_filter;
        if (H5Zregister(&filter_class) < 0)
            TEST_ERROR;
        if (H5Z_append(&tmp_cparam.pline, H5Z_FILTER_RESERVED + 43, 0, (size_t)0, NULL) < 0)
            FAIL_STACK_ERROR;
        test_write_filter_called = false;
    } /* end if */

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, &tmp_cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Get information about heap ID lengths */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > MAX_HEAP_ID_LEN)
        TEST_ERROR;

    /* Create 'tiny' and 'huge' objects */
    obj_size = id_len / 2;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, tiny_heap_id) < 0)
        FAIL_STACK_ERROR;

    obj_size = tmp_cparam.max_man_size + 1;
    if (H5HF_insert(fh, obj_size, shared_wobj_g, huge_heap_id) < 0)
        FAIL_STACK_ERROR;

    /* Verify that writing to 'huge' objects works for un-filtered heaps */
    H5E_BEGIN_TRY
    {
        ret = H5HF_write(fh, huge_heap_id, &id_changed, shared_wobj_g);
    }
    H5E_END_TRY
    assert(!id_changed);
    if (tparam->comp == FHEAP_TEST_COMPRESS) {
        if (ret >= 0)
            TEST_ERROR;
    } /* end if */
    else {
        if (ret < 0)
            FAIL_STACK_ERROR;
    } /* end else */

    /* Verify that writing to 'tiny' objects return failure (for now) */
    H5E_BEGIN_TRY
    {
        ret = H5HF_write(fh, tiny_heap_id, &id_changed, shared_wobj_g);
    }
    H5E_END_TRY
    assert(!id_changed);
    if (ret >= 0)
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Verify that the custom filter has been applied for the huge object (if
     * applicable) */
    if (tparam->comp == FHEAP_TEST_COMPRESS) {
        if (!test_write_filter_called)
            TEST_ERROR;
        test_write_filter_called = false;
    } /* end if */

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Initialize data to overwrite with */
    rewrite_obj = (unsigned char *)H5MM_malloc(shared_obj_size_g);
    for (u = 0; u < shared_obj_size_g; u++)
        rewrite_obj[u] = (unsigned char)(shared_wobj_g[u] * 2);

    /* Insert different sized objects, but stay out of "tiny" and "huge" zones */
    obj_size = 20;
    for (u = 0; u < 40; u++) {
        obj_loc = u;
        if (add_obj(fh, obj_loc, obj_size, NULL, &keep_ids))
            TEST_ERROR;

        /* Check for closing & re-opening the heap */
        if (reopen_heap(f, &fh, fh_addr, tparam) < 0)
            TEST_ERROR;

        /* Overwrite data just written */
        if (H5HF_write(fh, &keep_ids.ids[id_len * u], &id_changed, rewrite_obj) < 0)
            FAIL_STACK_ERROR;
        assert(!id_changed);

        /* Read data back in */
        if (H5HF_read(fh, &keep_ids.ids[id_len * u], shared_robj_g) < 0)
            FAIL_STACK_ERROR;

        /* Compare data read in */
        if (memcmp(rewrite_obj, shared_robj_g, obj_size) != 0)
            TEST_ERROR;

        /* Change size of data to write */
        if (u < 20)
            obj_size = (size_t)((float)obj_size * 1.3F);
        else
            obj_size = (size_t)((float)obj_size / 1.3F);
    } /* end for */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Verify that the custom filter has been applied to the managed objects (if
     * applicable) */
    if (tparam->comp == FHEAP_TEST_COMPRESS)
        if (!test_write_filter_called)
            TEST_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDONLY, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Verify changed objects */
    obj_size = 20;
    for (u = 0; u < 40; u++) {
        /* Read data back in */
        if (H5HF_read(fh, &keep_ids.ids[id_len * u], shared_robj_g) < 0)
            FAIL_STACK_ERROR;

        /* Compare data read in */
        if (memcmp(rewrite_obj, shared_robj_g, obj_size) != 0)
            TEST_ERROR;

        /* Change size of data to write */
        if (u < 20)
            obj_size = (size_t)((float)obj_size * 1.3F);
        else
            obj_size = (size_t)((float)obj_size / 1.3F);
    } /* end for */

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Free resources */
    if (tparam->comp == FHEAP_TEST_COMPRESS)
        H5O_msg_reset(H5O_PLINE_ID, &tmp_cparam.pline); /* Release the I/O pipeline filter information */

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);
    H5MM_xfree(rewrite_obj);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        H5MM_xfree(rewrite_obj);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_write() */

/*-------------------------------------------------------------------------
 * Function:  test_bug1
 *
 * Purpose:   Test inserting several objects, then deleting one and
 *              re-inserting an object, along with opening and closing
 *              the file.
 *
 * Return:    Success:    0
 *            Failure:    1
 *
 *-------------------------------------------------------------------------
 */
static unsigned
test_bug1(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t *tparam)
{
    hid_t              file = H5I_INVALID_HID;       /* File ID */
    char               filename[FHEAP_FILENAME_LEN]; /* Filename to use */
    H5F_t             *f  = NULL;                    /* Internal file object pointer */
    H5HF_t            *fh = NULL;                    /* Fractal heap wrapper */
    haddr_t            fh_addr;                      /* Address of fractal heap */
    size_t             id_len;                       /* Size of fractal heap IDs */
    fheap_heap_ids_t   keep_ids;                     /* Structure to retain heap IDs */
    h5_stat_size_t     empty_size;                   /* Size of a file with an empty heap */
    size_t             obj_size;                     /* Size of object */
    size_t             obj_loc;                      /* Location of object in buffer */
    fheap_heap_state_t state;                        /* State of fractal heap */

    /*
     * Display testing message
     */
    TESTING("bug1: inserting several objects & removing one, then re-inserting");

    /* Initialize the heap ID structure */
    memset(&keep_ids, 0, sizeof(fheap_heap_ids_t));

    /* Perform common file & heap open operations */
    if (open_heap(filename, fapl, cparam, tparam, &file, &f, &fh, &fh_addr, &state, &empty_size) < 0)
        TEST_ERROR;

    /* Get information about heap ID lengths */
    if (H5HF_get_id_len(fh, &id_len) < 0)
        FAIL_STACK_ERROR;
    if (id_len > MAX_HEAP_ID_LEN)
        TEST_ERROR;

    /* Insert objects */
    obj_size = 44;
    obj_loc  = 1;
    if (add_obj(fh, obj_loc, obj_size, NULL, &keep_ids))
        TEST_ERROR;

    obj_size = 484;
    obj_loc  = 2;
    if (add_obj(fh, obj_loc, obj_size, NULL, &keep_ids))
        TEST_ERROR;

    obj_size = 168;
    obj_loc  = 3;
    if (add_obj(fh, obj_loc, obj_size, NULL, &keep_ids))
        TEST_ERROR;

    obj_size = 96;
    obj_loc  = 4;
    if (add_obj(fh, obj_loc, obj_size, NULL, &keep_ids))
        TEST_ERROR;

    obj_size = 568;
    obj_loc  = 5;
    if (add_obj(fh, obj_loc, obj_size, NULL, &keep_ids))
        TEST_ERROR;

    obj_size = 568;
    obj_loc  = 6;
    if (add_obj(fh, obj_loc, obj_size, NULL, &keep_ids))
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Remove one of the objects */
    if (H5HF_remove(fh, &keep_ids.ids[id_len * 4]) < 0)
        FAIL_STACK_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the file */
    if ((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0)
        FAIL_STACK_ERROR;

    /* Get a pointer to the internal file object */
    if (NULL == (f = (H5F_t *)H5VL_object(file)))
        FAIL_STACK_ERROR;

    /* Ignore metadata tags in the file's cache */
    if (H5AC_ignore_tags(f) < 0)
        FAIL_STACK_ERROR;

    /* Re-open the heap */
    if (NULL == (fh = H5HF_open(f, fh_addr)))
        FAIL_STACK_ERROR;

    /* Insert another object */
    obj_size = 208;
    obj_loc  = 6;
    if (add_obj(fh, obj_loc, obj_size, NULL, &keep_ids))
        TEST_ERROR;

    /* Close the fractal heap */
    if (H5HF_close(fh) < 0)
        FAIL_STACK_ERROR;
    fh = NULL;

    /* Close the file */
    if (H5Fclose(file) < 0)
        FAIL_STACK_ERROR;

    /* Free resources */
    H5MM_xfree(keep_ids.ids);
    H5MM_xfree(keep_ids.lens);
    H5MM_xfree(keep_ids.offs);

    /* All tests passed */
    PASSED();

    return (0);

error:
    H5E_BEGIN_TRY
    {
        H5MM_xfree(keep_ids.ids);
        H5MM_xfree(keep_ids.lens);
        H5MM_xfree(keep_ids.offs);
        if (fh)
            H5HF_close(fh);
        H5Fclose(file);
    }
    H5E_END_TRY
    return (1);
} /* test_bug1() */

/*-------------------------------------------------------------------------
 * Function:  main
 *
 * Purpose:   Test the fractal heap code
 *
 * Return:    Success:
 *
 *            Failure:
 *
 *-------------------------------------------------------------------------
 */
int
main(void)
{
    fheap_test_param_t tparam;                                /* Testing parameters */
    H5HF_create_t      small_cparam;                          /* Creation parameters for "small" heap */
    H5HF_create_t      large_cparam;                          /* Creation parameters for "large" heap */
    hid_t fapl = H5I_INVALID_HID, def_fapl = H5I_INVALID_HID; /* File access property list for data files */
    hid_t pb_fapl = H5I_INVALID_HID;                          /* File access property list for data files */
    hid_t fcpl = H5I_INVALID_HID, def_fcpl = H5I_INVALID_HID; /* File creation property list for data files */
    fheap_test_type_t curr_test;                              /* Current test being worked on */
    unsigned          u, v;                                   /* Local index variable */
    unsigned          nerrors = 0;                            /* Cumulative error count */
    unsigned    num_pb_fs = 1; /* The number of settings to test for page buffering and file space handling */
    const char *driver_name;   /* Environment variable */
    bool        contig_addr_vfd;        /* Whether VFD used has a contiguous address space */
    bool        api_ctx_pushed = false; /* Whether API context pushed */

    /* Don't run this test using certain file drivers */
    driver_name = h5_get_test_driver_name();

    /* Current VFD that does not support contiguous address space */
    contig_addr_vfd = (bool)(strcmp(driver_name, "split") != 0 && strcmp(driver_name, "multi") != 0);

    /* Reset library */
    h5_test_init();

    def_fapl = h5_fileaccess();

    /*
     * Caution when turning on ExpressMode 0:
     *  It will activate testing with different combinations of
     *       page buffering and file space strategy and the
     *       running time will be long.
     *  For parallel build, the last two tests for page buffering
     *      are skipped because this feature is disabled in parallel.
     *      Activate full testing when this feature is re-enabled
     *      in the future for parallel build.
     */
    if (TestExpress > 0)
        printf("***Express test mode %d.  Some tests may be skipped\n", TestExpress);
    else if (TestExpress == 0) {
#ifdef H5_HAVE_PARALLEL
        num_pb_fs = NUM_PB_FS - 2;
#else
        num_pb_fs = NUM_PB_FS;
#endif
    }

    /* Initialize heap creation parameters */
    init_small_cparam(&small_cparam);
    init_large_cparam(&large_cparam);

    /* Push API context */
    if (H5CX_push() < 0)
        FAIL_STACK_ERROR;
    api_ctx_pushed = true;

    /* Allocate space for the shared objects */
    shared_obj_size_g = large_cparam.max_man_size + 256;
    shared_wobj_g     = (unsigned char *)H5MM_malloc(shared_obj_size_g);
    shared_robj_g     = (unsigned char *)H5MM_malloc(shared_obj_size_g);

    /* Create a copy def_fapl and enable page buffering */
    if ((pb_fapl = H5Pcopy(def_fapl)) < 0)
        TEST_ERROR;
    if (H5Pset_page_buffer_size(pb_fapl, PAGE_BUFFER_PAGE_SIZE, 0, 0) < 0)
        TEST_ERROR;

    /* Create a file creation property list */
    if ((def_fcpl = H5Pcreate(H5P_FILE_CREATE)) < 0)
        TEST_ERROR;

    /* Initialize the shared write buffer for objects */
    for (u = 0; u < shared_obj_size_g; u++)
        shared_wobj_g[u] = (unsigned char)u;

    for (v = 0; v < num_pb_fs; v++) {
        /* Skip test when:
           a) multi/split drivers and
           b) persisting free-space or using paged aggregation strategy
           because the library will fail file creation (temporary) for the above conditions */
        if (!contig_addr_vfd && v)
            break;

        if ((fcpl = H5Pcopy(def_fcpl)) < 0)
            TEST_ERROR;

        switch (v) {
            case 0:
                if (H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_FSM_AGGR, false, (hsize_t)1) < 0)
                    TEST_ERROR;
                fapl = def_fapl;
                break;
            case 1:
                if (H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_FSM_AGGR, true, (hsize_t)1) < 0)
                    TEST_ERROR;
                fapl = def_fapl;
                /* This is a fix for the daily test failure from the commit for libver bounds. */
                /*
                 * Many tests failed the file size check when comparing (a) and (b) as below:
                 * --Create a file and close the file.  Got the initial file size (a).
                 * --Reopen the file, perform fractal heap operations, and close the file.
                 *   Got the file size (b).
                 * The cause for the file size differences:
                 *   When the file is initially created with persisting free-space and with
                 *   (earliest, latest) libver bounds, the file will have version 2 superblock
                 *   due to non-default free-space handling.  As the low bound is earliest,
                 *   the library uses version 1 object header when creating the superblock
                 *   extension message.
                 *   When the file is reopened with the same libver bounds, the file's low
                 *   bound is upgraded to v18 because the file has version 2 superblock.
                 *   When the library creates the superblock extension message on file close,
                 *   the library uses version 2 object header for the superblock extension
                 *   message since the low bound is v18.
                 *   This leads to the discrepancy in file sizes as the file is persisting
                 *   free-space and there is object header version differences.
                 *  The fix:
                 *    Set libver bounds in fapl to (v18, latest) so that the file created in the
                 *    test routines will have low bound set to v18.  This will cause the
                 *    library to use version 2 object header for the superblock extension
                 *    message.
                 */
                if (H5Pset_libver_bounds(fapl, H5F_LIBVER_V18, H5F_LIBVER_LATEST) < 0)
                    TEST_ERROR;
                break;
            case 2:
                if (H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, false, (hsize_t)1) < 0)
                    TEST_ERROR;
                fapl = def_fapl;
                break;
            case 3:
                if (H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, true, (hsize_t)1) < 0)
                    TEST_ERROR;
                fapl = def_fapl;
                break;
            case 4:
                if (H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, false, (hsize_t)1) < 0)
                    TEST_ERROR;
                fapl = pb_fapl;
                break;
            case 5:
                if (H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, true, (hsize_t)1) < 0)
                    TEST_ERROR;
                fapl = pb_fapl;
                break;

            case NUM_PB_FS:
            default:
                goto error;
        }

        /* Iterate over the testing parameters */
        for (curr_test = FHEAP_TEST_NORMAL; curr_test < FHEAP_TEST_NTESTS; curr_test++) {
            /* Clear the testing parameters */
            memset(&tparam, 0, sizeof(fheap_test_param_t));
            tparam.actual_id_len = HEAP_ID_LEN;

            /* Set to run with different file space setting */
            tparam.my_fcpl = fcpl;

            /* Set appropriate testing parameters for each test */
            switch (curr_test) {
                /* "Normal" testing parameters */
                case FHEAP_TEST_NORMAL:
                    puts("Testing with normal parameters");
                    break;

                /* "Re-open heap" testing parameters */
                case FHEAP_TEST_REOPEN:
                    puts("Testing with reopen heap flag set");
                    tparam.reopen_heap = FHEAP_TEST_REOPEN;
                    break;

                /* An unknown test? */
                case FHEAP_TEST_NTESTS:
                default:
                    goto error;
            } /* end switch */

            /* Test fractal heap creation */
            nerrors += test_create(fapl, &small_cparam, &tparam);
            nerrors += test_reopen(fapl, &small_cparam, &tparam);
            nerrors += test_open_twice(fapl, &small_cparam, &tparam);
            nerrors += test_delete_open(fapl, &small_cparam, &tparam);

            nerrors += test_id_limits(fapl, &small_cparam, tparam.my_fcpl);
            nerrors += test_filtered_create(fapl, &small_cparam, tparam.my_fcpl);
            nerrors += test_size(fapl, &small_cparam, tparam.my_fcpl);
            nerrors += test_reopen_hdr(fapl, &small_cparam, tparam.my_fcpl);

            {
                fheap_test_fill_t fill; /* Size of objects to fill heap blocks with */

                /* Filling with different sized objects */
                for (fill = FHEAP_TEST_FILL_LARGE; fill < FHEAP_TEST_FILL_N; fill++) {
                    tparam.fill = fill;

                    /* Set appropriate testing parameters for each test */
                    switch (fill) {
                        /* "Bulk fill" heap blocks with 'large' objects */
                        case FHEAP_TEST_FILL_LARGE:
                            puts("Bulk-filling blocks w/large objects");
                            break;

                        /* "Bulk fill" heap blocks with 'single' objects */
                        case FHEAP_TEST_FILL_SINGLE:
                            puts("Bulk-filling blocks w/single object");
                            break;

                        /* An unknown test? */
                        case FHEAP_TEST_FILL_N:
                        default:
                            goto error;
                    } /* end switch */

                    /*
                     * Test fractal heap managed object insertion
                     */

                    /* "Weird" sized objects */
                    nerrors += test_man_insert_weird(fapl, &small_cparam, &tparam);

#ifdef ALL_INSERT_TESTS
                    /* "Standard" sized objects, building from simple to complex heaps */
                    nerrors += test_man_insert_first(fapl, &small_cparam, &tparam);
                    nerrors += test_man_insert_second(fapl, &small_cparam, &tparam);
                    nerrors += test_man_insert_root_mult(fapl, &small_cparam, &tparam);
                    nerrors += test_man_insert_force_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_insert_fill_second(fapl, &small_cparam, &tparam);
                    nerrors += test_man_insert_third_direct(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_first_row(fapl, &small_cparam, &tparam);
                    nerrors += test_man_start_second_row(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_second_row(fapl, &small_cparam, &tparam);
                    nerrors += test_man_start_third_row(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_fourth_row(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_all_root_direct(fapl, &small_cparam, &tparam);
                    nerrors += test_man_first_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_second_direct_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_first_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_second_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_second_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_recursive_indirect_row(fapl, &small_cparam, &tparam);
                    nerrors += test_man_start_2nd_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_recursive_indirect_two_deep(fapl, &small_cparam, &tparam);
                    nerrors += test_man_start_3rd_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_first_3rd_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_3rd_recursive_indirect_row(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_all_3rd_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_start_4th_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_first_4th_recursive_indirect(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_4th_recursive_indirect_row(fapl, &small_cparam, &tparam);
                    nerrors += test_man_fill_all_4th_recursive_indirect(fapl, &small_cparam, &tparam);
#endif /* ALL_INSERT_TESTS */
                    /* If this test fails, uncomment the tests above, which build up to this
                     * level of complexity gradually. -QAK
                     */
                    if (TestExpress > 1)
                        printf(
                            "***Express test mode on.  test_man_start_5th_recursive_indirect is skipped\n");
                    else
                        nerrors += test_man_start_5th_recursive_indirect(fapl, &small_cparam, &tparam);

                    /*
                     * Test fractal heap object deletion
                     */
                    /* Simple removal */
                    nerrors += test_man_remove_bogus(fapl, &small_cparam, &tparam);
                    nerrors += test_man_remove_one(fapl, &small_cparam, &tparam);
                    nerrors += test_man_remove_two(fapl, &small_cparam, &tparam);
                    nerrors += test_man_remove_one_larger(fapl, &small_cparam, &tparam);
                    tparam.del_dir = FHEAP_DEL_FORWARD;
                    nerrors += test_man_remove_two_larger(fapl, &small_cparam, &tparam);
                    tparam.del_dir = FHEAP_DEL_REVERSE;
                    nerrors += test_man_remove_two_larger(fapl, &small_cparam, &tparam);
                    tparam.del_dir = FHEAP_DEL_FORWARD;
                    nerrors += test_man_remove_three_larger(fapl, &small_cparam, &tparam);
                    tparam.del_dir = FHEAP_DEL_REVERSE;
                    nerrors += test_man_remove_three_larger(fapl, &small_cparam, &tparam);

                    /* Incremental insert & removal */
                    tparam.del_dir = FHEAP_DEL_FORWARD;
                    nerrors += test_man_incr_insert_remove(fapl, &small_cparam, &tparam);

                    {
                        fheap_test_del_dir_t   del_dir;    /* Deletion direction */
                        fheap_test_del_drain_t drain_half; /* Deletion draining */

                        /* More complex removal patterns */
                        for (del_dir = FHEAP_DEL_FORWARD; del_dir < FHEAP_DEL_NDIRS; del_dir++) {
                            tparam.del_dir = del_dir;
                            for (drain_half = FHEAP_DEL_DRAIN_ALL; drain_half < FHEAP_DEL_DRAIN_N;
                                 drain_half++) {
                                tparam.drain_half = drain_half;
                                /* Don't need to test deletion directions when deleting entire heap */
                                if (tparam.del_dir == FHEAP_DEL_HEAP &&
                                    tparam.drain_half > FHEAP_DEL_DRAIN_ALL)
                                    break;

                                /* Simple insertion patterns */
                                nerrors += test_man_remove_root_direct(fapl, &small_cparam, &tparam);
                                nerrors += test_man_remove_two_direct(fapl, &small_cparam, &tparam);
                                nerrors += test_man_remove_first_row(fapl, &small_cparam, &tparam);
                                nerrors += test_man_remove_first_two_rows(fapl, &small_cparam, &tparam);
                                nerrors += test_man_remove_first_four_rows(fapl, &small_cparam, &tparam);
                                if (TestExpress > 1)
                                    printf("***Express test mode on.  Some tests skipped\n");
                                else {
                                    nerrors += test_man_remove_all_root_direct(fapl, &small_cparam, &tparam);
                                    nerrors += test_man_remove_2nd_indirect(fapl, &small_cparam, &tparam);
                                    nerrors += test_man_remove_3rd_indirect(fapl, &small_cparam, &tparam);
                                } /* end else */

                                /* Skip blocks insertion */
                                /* (covers insertion & deletion of skipped blocks) */
                                nerrors += test_man_skip_start_block(fapl, &small_cparam, &tparam);
                                nerrors += test_man_skip_start_block_add_back(fapl, &small_cparam, &tparam);
                                nerrors +=
                                    test_man_skip_start_block_add_skipped(fapl, &small_cparam, &tparam);
                                nerrors += test_man_skip_2nd_block(fapl, &small_cparam, &tparam);
                                nerrors += test_man_skip_2nd_block_add_skipped(fapl, &small_cparam, &tparam);
                                nerrors += test_man_fill_one_partial_skip_2nd_block_add_skipped(
                                    fapl, &small_cparam, &tparam);
                                nerrors += test_man_fill_row_skip_add_skipped(fapl, &small_cparam, &tparam);
                                nerrors += test_man_skip_direct_skip_indirect_two_rows_add_skipped(
                                    fapl, &small_cparam, &tparam);
                                nerrors += test_man_fill_direct_skip_indirect_start_block_add_skipped(
                                    fapl, &small_cparam, &tparam);
                                nerrors += test_man_fill_direct_skip_2nd_indirect_start_block_add_skipped(
                                    fapl, &small_cparam, &tparam);
                                nerrors += test_man_fill_2nd_direct_less_one_wrap_start_block_add_skipped(
                                    fapl, &small_cparam, &tparam);
                                nerrors += test_man_fill_direct_skip_2nd_indirect_skip_2nd_block_add_skipped(
                                    fapl, &small_cparam, &tparam);
                                nerrors += test_man_fill_direct_skip_indirect_two_rows_add_skipped(
                                    fapl, &small_cparam, &tparam);
                                nerrors +=
                                    test_man_fill_direct_skip_indirect_two_rows_skip_indirect_row_add_skipped(
                                        fapl, &small_cparam, &tparam);
                                nerrors += test_man_fill_2nd_direct_skip_start_block_add_skipped(
                                    fapl, &small_cparam, &tparam);
                                nerrors += test_man_fill_2nd_direct_skip_2nd_indirect_start_block_add_skipped(
                                    fapl, &small_cparam, &tparam);
                                nerrors +=
                                    test_man_fill_2nd_direct_fill_direct_skip_3rd_indirect_start_block_add_skipped(
                                        fapl, &small_cparam, &tparam);
                                nerrors +=
                                    test_man_fill_2nd_direct_fill_direct_skip2_3rd_indirect_start_block_add_skipped(
                                        fapl, &small_cparam, &tparam);
                                nerrors +=
                                    test_man_fill_3rd_direct_less_one_fill_direct_wrap_start_block_add_skipped(
                                        fapl, &small_cparam, &tparam);
                                nerrors +=
                                    test_man_fill_1st_row_3rd_direct_fill_2nd_direct_less_one_wrap_start_block_add_skipped(
                                        fapl, &small_cparam, &tparam);
                                if (TestExpress > 1)
                                    printf("***Express test mode on.  Some tests skipped\n");
                                else {
                                    nerrors +=
                                        test_man_fill_3rd_direct_fill_direct_skip_start_block_add_skipped(
                                            fapl, &small_cparam, &tparam);
                                    nerrors +=
                                        test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_start_block_add_skipped(
                                            fapl, &small_cparam, &tparam);
                                    nerrors +=
                                        test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_two_rows_start_block_add_skipped(
                                            fapl, &small_cparam, &tparam);
                                    nerrors +=
                                        test_man_fill_3rd_direct_fill_2nd_direct_fill_direct_skip_3rd_indirect_wrap_start_block_add_skipped(
                                            fapl, &small_cparam, &tparam);
                                    nerrors +=
                                        test_man_fill_4th_direct_less_one_fill_2nd_direct_fill_direct_skip_3rd_indirect_wrap_start_block_add_skipped(
                                            fapl, &small_cparam, &tparam);
                                } /* end else */

                                /* Fragmented insertion patterns */
                                /* (covers insertion & deletion of fragmented blocks) */
                                nerrors += test_man_frag_simple(fapl, &small_cparam, &tparam);
                                nerrors += test_man_frag_direct(fapl, &small_cparam, &tparam);
                                nerrors += test_man_frag_2nd_direct(fapl, &small_cparam, &tparam);
                                nerrors += test_man_frag_3rd_direct(fapl, &small_cparam, &tparam);
                            } /* end for */
                        }     /* end for */

                        /* Reset deletion drain parameter */
                        tparam.drain_half = FHEAP_DEL_DRAIN_ALL;

                    } /* end block */
                }     /* end for */
            }         /* end block */

            /*
             * Test fractal heap 'huge' & 'tiny' object insertion & deletion
             */
            {
                fheap_test_del_dir_t del_dir; /* Deletion direction */
                unsigned             id_len;  /* Length of heap IDs */

                /* Test "normal" & "direct" storage of 'huge' & 'tiny' heap IDs */
                for (id_len = 0; id_len < 3; id_len++) {
                    /* Set the ID length for this test */
                    small_cparam.id_len = (uint16_t)id_len;

                    /* Print information about each test */
                    switch (id_len) {
                        /* Use "normal" form for 'huge' object's heap IDs */
                        case 0:
                            puts("Using 'normal' heap ID format for 'huge' objects");
                            break;

                        /* Use "direct" form for 'huge' object's heap IDs */
                        case 1:
                            puts("Using 'direct' heap ID format for 'huge' objects");

                            /* Adjust actual length of heap IDs for directly storing 'huge' object's file
                             * offset & length in heap ID */
                            tparam.actual_id_len = 17; /* 1 + 8 (file address size) + 8 (file length size) */
                            break;

                        /* Use "direct" storage for 'huge' objects and larger IDs for 'tiny' objects */
                        case 2:
                            small_cparam.id_len = 37;
                            puts("Using 'direct' heap ID format for 'huge' objects and larger IDs for "
                                 "'tiny' objects");
                            tparam.actual_id_len = 37;
                            break;

                        /* An unknown test? */
                        default:
                            goto error;
                    } /* end switch */

                    /* Try several different methods of deleting objects */
                    for (del_dir = FHEAP_DEL_FORWARD; del_dir < FHEAP_DEL_NDIRS; del_dir++) {
                        tparam.del_dir = del_dir;

                        /* Test 'huge' object insert & delete */
                        nerrors += test_huge_insert_one(fapl, &small_cparam, &tparam);
                        nerrors += test_huge_insert_two(fapl, &small_cparam, &tparam);
                        nerrors += test_huge_insert_three(fapl, &small_cparam, &tparam);
                        nerrors += test_huge_insert_mix(fapl, &small_cparam, &tparam);
                        nerrors += test_filtered_huge(fapl, &small_cparam, &tparam);

                        /* Test 'tiny' object insert & delete */
                        nerrors += test_tiny_insert_one(fapl, &small_cparam, &tparam);
                        nerrors += test_tiny_insert_two(fapl, &small_cparam, &tparam);
                        nerrors += test_tiny_insert_mix(fapl, &small_cparam, &tparam);
                    } /* end for */
                }     /* end for */

                /* Reset the "normal" heap ID lengths */
                small_cparam.id_len  = 0;
                tparam.actual_id_len = HEAP_ID_LEN;
            } /* end block */

            /* Test I/O filter support */

            /* Try several different methods of deleting objects */
            {
                fheap_test_del_dir_t del_dir; /* Deletion direction */

                for (del_dir = FHEAP_DEL_FORWARD; del_dir < FHEAP_DEL_NDIRS; del_dir++) {
                    tparam.del_dir = del_dir;

                    /* Controlled tests */
                    /* XXX: Re-enable file size checks in these tests, after the file has persistent free
                     * space tracking working */
                    nerrors += test_filtered_man_root_direct(fapl, &small_cparam, &tparam);
                    nerrors += test_filtered_man_root_indirect(fapl, &small_cparam, &tparam);

                    /* Random tests, with compressed blocks */
                    tparam.comp = FHEAP_TEST_COMPRESS;
                    nerrors += test_random((curr_test == FHEAP_TEST_NORMAL ? (hsize_t)(50 * 1000 * 1000)
                                                                           : (hsize_t)(25 * 1000 * 1000)),
                                           fapl, &small_cparam, &tparam);
                    nerrors += test_random_pow2((curr_test == FHEAP_TEST_NORMAL ? (hsize_t)(50 * 1000 * 1000)
                                                                                : (hsize_t)(2 * 1000 * 1000)),
                                                fapl, &small_cparam, &tparam);

                    /* Reset block compression */
                    tparam.comp = FHEAP_TEST_NO_COMPRESS;
                } /* end for */
            }     /* end block */

            /* Random object insertion & deletion */
            if (TestExpress > 1)
                printf("***Express test mode on.  Some tests skipped\n");
            else {
                /* Random tests using "small" heap creation parameters */
                puts("Using 'small' heap creation parameters");

                /* (reduce size of tests when re-opening each time) */
                /* XXX: Try to speed things up enough that these tests don't have to be reduced when
                 * re-opening */
                tparam.del_dir = FHEAP_DEL_FORWARD;
                nerrors += test_random((curr_test == FHEAP_TEST_NORMAL ? (hsize_t)(100 * 1000 * 1000)
                                                                       : (hsize_t)(50 * 1000 * 1000)),
                                       fapl, &small_cparam, &tparam);
                nerrors += test_random_pow2((curr_test == FHEAP_TEST_NORMAL ? (hsize_t)(100 * 1000 * 1000)
                                                                            : (hsize_t)(4 * 1000 * 1000)),
                                            fapl, &small_cparam, &tparam);

                tparam.del_dir = FHEAP_DEL_HEAP;
                nerrors += test_random((curr_test == FHEAP_TEST_NORMAL ? (hsize_t)(100 * 1000 * 1000)
                                                                       : (hsize_t)(50 * 1000 * 1000)),
                                       fapl, &small_cparam, &tparam);
                nerrors += test_random_pow2((curr_test == FHEAP_TEST_NORMAL ? (hsize_t)(100 * 1000 * 1000)
                                                                            : (hsize_t)(4 * 1000 * 1000)),
                                            fapl, &small_cparam, &tparam);

                /* Random tests using "large" heap creation parameters */
                puts("Using 'large' heap creation parameters");
                tparam.actual_id_len = LARGE_HEAP_ID_LEN;

                /* (reduce size of tests when re-opening each time) */
                /* XXX: Try to speed things up enough that these tests don't have to be reduced when
                 * re-opening */
                tparam.del_dir = FHEAP_DEL_FORWARD;
                nerrors += test_random((curr_test == FHEAP_TEST_NORMAL ? (hsize_t)(100 * 1000 * 1000)
                                                                       : (hsize_t)(50 * 1000 * 1000)),
                                       fapl, &large_cparam, &tparam);
                nerrors += test_random_pow2((curr_test == FHEAP_TEST_NORMAL ? (hsize_t)(100 * 1000 * 1000)
                                                                            : (hsize_t)(4 * 1000 * 1000)),
                                            fapl, &large_cparam, &tparam);

                tparam.del_dir = FHEAP_DEL_HEAP;
                nerrors += test_random((curr_test == FHEAP_TEST_NORMAL ? (hsize_t)(100 * 1000 * 1000)
                                                                       : (hsize_t)(50 * 1000 * 1000)),
                                       fapl, &large_cparam, &tparam);
                nerrors += test_random_pow2((curr_test == FHEAP_TEST_NORMAL ? (hsize_t)(100 * 1000 * 1000)
                                                                            : (hsize_t)(4 * 1000 * 1000)),
                                            fapl, &large_cparam, &tparam);

                /* Reset the "normal" heap ID length */
                tparam.actual_id_len = SMALL_HEAP_ID_LEN;
            } /* end else */

            /* Test object writing support */

            /* Basic object writing */
            nerrors += test_write(fapl, &small_cparam, &tparam);

            /* Writing objects in heap with filters */
            tparam.comp = FHEAP_TEST_COMPRESS;
            nerrors += test_write(fapl, &small_cparam, &tparam);

            /* Reset block compression */
            tparam.comp = FHEAP_TEST_NO_COMPRESS;
        } /* end for */

        if (H5Pclose(fcpl) < 0)
            TEST_ERROR;
    } /* end num_pb_fs */

    /* Tests that address specific bugs */
    tparam.my_fcpl = def_fcpl;
    fapl           = def_fapl;

    /* Tests that address specific bugs */
    nerrors += test_bug1(fapl, &small_cparam, &tparam);

    /* Verify symbol table messages are cached */
    nerrors += (h5_verify_cached_stabs(FILENAME, fapl) < 0 ? 1 : 0);

    if (nerrors)
        goto error;
    puts("All fractal heap tests passed.");

    /* Release space for the shared objects */
    H5MM_xfree(shared_wobj_g);
    H5MM_xfree(shared_robj_g);
    H5MM_xfree(shared_ids_g);
    H5MM_xfree(shared_lens_g);
    H5MM_xfree(shared_offs_g);

    if (H5Pclose(def_fcpl) < 0)
        TEST_ERROR;
    if (H5Pclose(pb_fapl) < 0)
        TEST_ERROR;

    /* Pop API context */
    if (api_ctx_pushed && H5CX_pop(false) < 0)
        FAIL_STACK_ERROR;
    api_ctx_pushed = false;

    /* Clean up file used */
    h5_cleanup(FILENAME, def_fapl);

    return 0;

error:
    puts("*** TESTS FAILED ***");
    H5E_BEGIN_TRY
    {
        H5MM_xfree(shared_wobj_g);
        H5MM_xfree(shared_robj_g);
        H5MM_xfree(shared_ids_g);
        H5MM_xfree(shared_lens_g);
        H5MM_xfree(shared_offs_g);
        H5Pclose(def_fapl);
        H5Pclose(pb_fapl);
        H5Pclose(def_fcpl);
        H5Pclose(fcpl);
    }
    H5E_END_TRY

    if (api_ctx_pushed)
        H5CX_pop(false);

    return 1;
} /* end main() */
