From 3ad18072eba378ca1f598d33cc83587e8a76880f Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sat, 28 Jan 2017 23:21:22 -0800 Subject: Add missing files --- src/H5Cimage.c | 4100 +++++++++++++++++++++++++++++++ src/H5Cprefetched.c | 352 +++ src/H5Ocache_image.c | 337 +++ test/cache_image.c | 6490 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/genall5.c | 3893 ++++++++++++++++++++++++++++++ test/genall5.h | 53 + 6 files changed, 15225 insertions(+) create mode 100644 src/H5Cimage.c create mode 100644 src/H5Cprefetched.c create mode 100644 src/H5Ocache_image.c create mode 100644 test/cache_image.c create mode 100644 test/genall5.c create mode 100644 test/genall5.h diff --git a/src/H5Cimage.c b/src/H5Cimage.c new file mode 100644 index 0000000..dec8283 --- /dev/null +++ b/src/H5Cimage.c @@ -0,0 +1,4100 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Cimage.c + * July 20, 2015 + * John Mainzer + * + * Purpose: Functions in this file are specific to the implementation + * of the metadata cache image feature. + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#include "H5Cmodule.h" /* This source code file is part of the H5C module */ +#define H5F_FRIEND /*suppress error about including H5Fpkg */ + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#ifdef H5_HAVE_PARALLEL +#define H5AC_FRIEND /*suppress error about including H5ACpkg */ +#include "H5ACpkg.h" /* Metadata cache */ +#endif /* H5_HAVE_PARALLEL */ +#include "H5Cpkg.h" /* Cache */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fpkg.h" /* Files */ +#include "H5FDprivate.h" /* File drivers */ +#include "H5FLprivate.h" /* Free Lists */ +#include "H5MFprivate.h" /* File memory management */ +#include "H5MMprivate.h" /* Memory management */ + + +/****************/ +/* Local Macros */ +/****************/ +#if H5C_DO_MEMORY_SANITY_CHECKS +#define H5C_IMAGE_EXTRA_SPACE 8 +#define H5C_IMAGE_SANITY_VALUE "DeadBeef" +#else /* H5C_DO_MEMORY_SANITY_CHECKS */ +#define H5C_IMAGE_EXTRA_SPACE 0 +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + +/* Cache image buffer components, on disk */ +#define H5C__MDCI_BLOCK_SIGNATURE "MDCI" +#define H5C__MDCI_BLOCK_SIGNATURE_LEN 4 +#define H5C__MDCI_BLOCK_VERSION_0 0 + +/* Metadata cache image header flags -- max 8 bits */ +#define H5C__MDCI_HEADER_HAVE_RESIZE_STATUS 0x01 + +/* Metadata cache image entry flags -- max 8 bits */ +#define H5C__MDCI_ENTRY_DIRTY_FLAG 0x01 +#define H5C__MDCI_ENTRY_IN_LRU_FLAG 0x02 +#define H5C__MDCI_ENTRY_IS_FD_PARENT_FLAG 0x04 +#define H5C__MDCI_ENTRY_IS_FD_CHILD_FLAG 0x08 + +/* Limits on flush dependency values, stored in 16-bit values on disk */ +#define H5C__MDCI_MAX_FD_CHILDREN USHRT_MAX +#define H5C__MDCI_MAX_FD_PARENTS USHRT_MAX + +/* Values for image entry magic field */ +#define H5C_IMAGE_ENTRY_T_MAGIC 0x005CAC08 +#define H5C_IMAGE_ENTRY_T_BAD_MAGIC 0xBeefDead + +/* Maximum ring allowed in image */ +#define H5C_MAX_RING_IN_IMAGE 3 + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + +/* Helper routines */ +static size_t H5C__cache_image_block_entry_header_size(const H5F_t *f); +static size_t H5C__cache_image_block_header_size(const H5F_t *f); +static herr_t H5C__decode_cache_image_buffer(const H5F_t *f, H5C_t *cache_ptr); +static herr_t H5C__decode_cache_image_header(const H5F_t *f, + H5C_t *cache_ptr, const uint8_t **buf); +static herr_t H5C__decode_cache_image_entry(const H5F_t *f, + const H5C_t *cache_ptr, const uint8_t **buf, unsigned entry_num); +static herr_t H5C__destroy_pf_entry_child_flush_deps(H5C_t *cache_ptr, + H5C_cache_entry_t *pf_entry_ptr, H5C_cache_entry_t **fd_children); +static herr_t H5C__encode_cache_image_header(const H5F_t *f, + const H5C_t *cache_ptr, uint8_t **buf); +static herr_t H5C__encode_cache_image_entry(H5F_t *f, H5C_t *cache_ptr, + uint8_t **buf, unsigned entry_num); +static herr_t H5C__prep_for_file_close__compute_fd_heights(const H5C_t *cache_ptr); +static void H5C__prep_for_file_close__compute_fd_heights_real( + H5C_cache_entry_t *entry_ptr, uint32_t fd_height); +static herr_t H5C__prep_for_file_close__setup_image_entries_array(H5C_t *cache_ptr); +static herr_t H5C__prep_for_file_close__scan_entries(const H5F_t *f, + H5C_t *cache_ptr); +static herr_t H5C__reconstruct_cache_contents(H5F_t *f, hid_t dxpl_id, + H5C_t *cache_ptr); +static H5C_cache_entry_t *H5C__reconstruct_cache_entry(H5C_t *cache_ptr, + unsigned index); +static herr_t H5C__serialize_cache(H5F_t *f, hid_t dxpl_id); +static herr_t H5C__serialize_ring(H5F_t *f, hid_t dxpl_id, + H5C_ring_t ring); +static herr_t H5C__serialize_single_entry(H5F_t *f, hid_t dxpl_id, + H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr, + hbool_t *restart_list_scan_ptr); +static herr_t H5C__write_cache_image_superblock_msg(H5F_t *f, hid_t dxpl_id, + hbool_t create); +static herr_t H5C__read_cache_image(H5F_t * f, hid_t dxpl_id, const H5C_t *cache_ptr); +static herr_t H5C__write_cache_image(H5F_t *f, hid_t dxpl_id, const H5C_t *cache_ptr); +static herr_t H5C__construct_cache_image_buffer(H5F_t *f, H5C_t *cache_ptr); +static herr_t H5C__free_image_entries_array(H5C_t *cache_ptr); + + +/*********************/ +/* Package Variables */ +/*********************/ + +/* Declare a free list to manage H5C_cache_entry_t objects */ +H5FL_DEFINE(H5C_cache_entry_t); + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + + +/*------------------------------------------------------------------------- + * Function: H5C_cache_image_status() + * + * Purpose: Examine the metadata cache associated with the supplied + * instance of H5F_t to determine whether the load of a + * cache image has either been queued ir executed, and if + * construction of a cache image has been requested. + * + * This done, it set *load_ci_ptr to TRUE if a cache image + * has either been loaded or a load has been requested, and + * to FALSE otherwise. + * + * Similarly, set *write_ci_ptr to TRUE if construction of + * a cache image has been requested, and to FALSE otherwise. + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 12/29/16 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C_cache_image_status(H5F_t * f, hbool_t *load_ci_ptr, hbool_t *write_ci_ptr) +{ + H5C_t * cache_ptr; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + cache_ptr = f->shared->cache; + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(load_ci_ptr); + HDassert(write_ci_ptr); + + *load_ci_ptr = cache_ptr->load_image || cache_ptr->image_loaded; + *write_ci_ptr = cache_ptr->image_ctl.generate_image; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5C_cache_image_status() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__construct_cache_image_buffer() + * + * Purpose: Allocate a buffer of size cache_ptr->image_len, and + * load it with an image of the metadata cache image block. + * + * Note that by the time this function is called, the cache + * should have removed all entries from its data structures. + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 8/5/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__construct_cache_image_buffer(H5F_t * f, H5C_t *cache_ptr) +{ + uint8_t * p; /* Pointer into image buffer */ + uint32_t chksum; + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(cache_ptr == f->shared->cache); + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->close_warning_received); + HDassert(cache_ptr->image_ctl.generate_image); + HDassert(cache_ptr->num_entries_in_image > 0); + HDassert(cache_ptr->index_len == 0); + HDassert(cache_ptr->image_data_len > 0); + HDassert(cache_ptr->image_data_len <= cache_ptr->image_len); + + /* Allocate the buffer in which to construct the cache image block */ + if(NULL == (cache_ptr->image_buffer = H5MM_malloc(cache_ptr->image_len + 1))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for cache image buffer") + + /* Construct the cache image block header image */ + p = (uint8_t *)cache_ptr->image_buffer; + if(H5C__encode_cache_image_header(f, cache_ptr, &p) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTENCODE, FAIL, "header image construction failed") + HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) < cache_ptr->image_data_len); + + /* Construct the cache entry images */ + for(u = 0; u < cache_ptr->num_entries_in_image; u++) + if(H5C__encode_cache_image_entry(f, cache_ptr, &p, u) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTENCODE, FAIL, "entry image construction failed") + HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) < cache_ptr->image_data_len); + + /* Construct the adaptive resize status image -- not yet */ + + /* Compute the checksum and encode */ + chksum = H5_checksum_metadata(cache_ptr->image_buffer, (size_t)(cache_ptr->image_data_len - H5F_SIZEOF_CHKSUM), 0); + UINT32ENCODE(p, chksum); + HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) == cache_ptr->image_data_len); + HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) <= cache_ptr->image_len); + +#ifndef NDEBUG + /* validate the metadata cache image we just constructed by decoding it + * and comparing the result with the original data. + */ + { + uint32_t old_chksum; + const uint8_t * q; + H5C_t * fake_cache_ptr = NULL; + unsigned v; + herr_t status; /* Status from decoding */ + + fake_cache_ptr = (H5C_t *)H5MM_malloc(sizeof(H5C_t)); + HDassert(fake_cache_ptr); + fake_cache_ptr->magic = H5C__H5C_T_MAGIC; + + /* needed for sanity checks */ + fake_cache_ptr->image_len = cache_ptr->image_len; + q = (const uint8_t *)cache_ptr->image_buffer; + status = H5C__decode_cache_image_header(f, fake_cache_ptr, &q); + HDassert(status >= 0); + + HDassert(NULL != p); + HDassert(fake_cache_ptr->num_entries_in_image == cache_ptr->num_entries_in_image); + + fake_cache_ptr->image_entries = (H5C_image_entry_t *)H5MM_malloc(sizeof(H5C_image_entry_t) * + (size_t)(fake_cache_ptr->num_entries_in_image + 1)); + HDassert(fake_cache_ptr->image_entries); + + for(u = 0; u < fake_cache_ptr->num_entries_in_image; u++) { + (fake_cache_ptr->image_entries)[u].magic = H5C_IMAGE_ENTRY_T_MAGIC; + (fake_cache_ptr->image_entries)[u].image_ptr = NULL; + + /* touch up f->shared->cache to satisfy sanity checks... */ + f->shared->cache = fake_cache_ptr; + status = H5C__decode_cache_image_entry(f, fake_cache_ptr, &q, u); + HDassert(status >= 0); + + /* ...and then return f->shared->cache to its correct value */ + f->shared->cache = cache_ptr; + + /* verify expected contents */ + HDassert((cache_ptr->image_entries)[u].addr == (fake_cache_ptr->image_entries)[u].addr); + HDassert((cache_ptr->image_entries)[u].size == (fake_cache_ptr->image_entries)[u].size); + HDassert((cache_ptr->image_entries)[u].type_id == (fake_cache_ptr->image_entries)[u].type_id); + HDassert((cache_ptr->image_entries)[u].lru_rank == (fake_cache_ptr->image_entries)[u].lru_rank); + HDassert((cache_ptr->image_entries)[u].is_dirty == (fake_cache_ptr->image_entries)[u].is_dirty); + /* don't check image_fd_height as it is not stored in + * the metadata cache image block. + */ + HDassert((cache_ptr->image_entries)[u].fd_child_count == (fake_cache_ptr->image_entries)[u].fd_child_count); + HDassert((cache_ptr->image_entries)[u].fd_dirty_child_count == (fake_cache_ptr->image_entries)[u].fd_dirty_child_count); + HDassert((cache_ptr->image_entries)[u].fd_parent_count == (fake_cache_ptr->image_entries)[u].fd_parent_count); + + for(v = 0; v < (cache_ptr->image_entries)[u].fd_parent_count; v++) + HDassert((cache_ptr->image_entries)[u].fd_parent_addrs[v] == (fake_cache_ptr->image_entries)[u].fd_parent_addrs[v]); + + /* free the fd_parent_addrs array if it exists */ + if((fake_cache_ptr->image_entries)[u].fd_parent_addrs) { + HDassert((fake_cache_ptr->image_entries)[u].fd_parent_count > 0); + (fake_cache_ptr->image_entries)[u].fd_parent_addrs = (haddr_t *)H5MM_xfree((fake_cache_ptr->image_entries)[u].fd_parent_addrs); + (fake_cache_ptr->image_entries)[u].fd_parent_count = 0; + } /* end if */ + else + HDassert((fake_cache_ptr->image_entries)[u].fd_parent_count == 0); + + HDassert((cache_ptr->image_entries)[u].image_ptr); + HDassert((fake_cache_ptr->image_entries)[u].image_ptr); + HDassert(!HDmemcmp((cache_ptr->image_entries)[u].image_ptr, + (fake_cache_ptr->image_entries)[u].image_ptr, + (cache_ptr->image_entries)[u].size)); + + (fake_cache_ptr->image_entries)[u].image_ptr = H5MM_xfree((fake_cache_ptr->image_entries)[u].image_ptr); + } /* end for */ + + HDassert((size_t)(q - (const uint8_t *)cache_ptr->image_buffer) == cache_ptr->image_data_len - H5F_SIZEOF_CHKSUM); + + /* compute the checksum */ + old_chksum = chksum; + chksum = H5_checksum_metadata(cache_ptr->image_buffer, (size_t)(cache_ptr->image_data_len - H5F_SIZEOF_CHKSUM), 0); + HDassert(chksum == old_chksum); + + fake_cache_ptr->image_entries = (H5C_image_entry_t *)H5MM_xfree(fake_cache_ptr->image_entries); + fake_cache_ptr = (H5C_t *)H5MM_xfree(fake_cache_ptr); + } /* end block */ +#endif /* NDEBUG */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__construct_cache_image_buffer() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__generate_cache_image() + * + * Purpose: Generate the cache image and write it to the file, if + * directed. + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: Quincey Koziol + * 1/26/17 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C__generate_cache_image(H5F_t *f, hid_t dxpl_id, H5C_t *cache_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(cache_ptr == f->shared->cache); + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + + /* Construct cache image */ + if(H5C__construct_cache_image_buffer(f, cache_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't create metadata cache image") + + /* Free image entries array */ + if(H5C__free_image_entries_array(cache_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't free image entries array") + + /* Write cache image block if so configured */ + if(cache_ptr->image_ctl.flags & H5C_CI__GEN_MDC_IMAGE_BLK) { + if(H5C__write_cache_image(f, dxpl_id, cache_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't write metadata cache image block to file") + + H5C__UPDATE_STATS_FOR_CACHE_IMAGE_CREATE(cache_ptr); + } /* end if */ + + /* Free cache image buffer */ + HDassert(cache_ptr->image_buffer); + cache_ptr->image_buffer = H5MM_xfree(cache_ptr->image_buffer); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__generate_cache_image() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__deserialize_prefetched_entry() + * + * Purpose: Deserialize the supplied prefetched entry entry, and return + * a pointer to the deserialized entry in *entry_ptr_ptr. + * If successful, remove the prefetched entry from the cache, + * and free it. Insert the deserialized entry into the cache. + * + * Note that the on disk image of the entry is not freed -- + * a pointer to it is stored in the deserialized entries' + * image_ptr field, and its image_up_to_date field is set to + * TRUE unless the entry is dirtied by the deserialize call. + * + * If the prefetched entry is a flush dependency child, + * destroy that flush dependency prior to calling the + * deserialize callback. If appropriate, the flush dependency + * relationship will be recreated by the cache client. + * + * If the prefetched entry is a flush dependency parent, + * destroy the flush dependency relationship with all its + * children. As all these children must be prefetched entries, + * recreate these flush dependency relationships with + * deserialized entry after it is inserted in the cache. + * + * Since deserializing a prefetched entry is semantically + * equivalent to a load, issue an entry loaded nofification + * if the notify callback is defined. + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Note that *entry_ptr_ptr is undefined on failure. + * + * Programmer: John Mainzer, 8/10/15 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C__deserialize_prefetched_entry(H5F_t *f, hid_t dxpl_id, H5C_t *cache_ptr, + H5C_cache_entry_t **entry_ptr_ptr, const H5C_class_t *type, + haddr_t addr, void *udata) +{ + hbool_t dirty = FALSE; /* Flag indicating whether thing was + * dirtied during deserialize + */ + size_t len; /* Size of image in file */ + void * thing = NULL; /* Pointer to thing loaded */ + H5C_cache_entry_t * pf_entry_ptr; /* pointer to the prefetched entry */ + /* supplied in *entry_ptr_ptr. */ + H5C_cache_entry_t * ds_entry_ptr; /* Alias for thing loaded, as cache + * entry + */ + H5C_cache_entry_t** fd_children = NULL; /* Pointer to a dynamically */ + /* allocated array of pointers to */ + /* the flush dependency children of */ + /* the prefetched entry, or NULL if */ + /* that array does not exist. */ + unsigned flush_flags = (H5C__FLUSH_INVALIDATE_FLAG | + H5C__FLUSH_CLEAR_ONLY_FLAG); + int i; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->cache); + HDassert(f->shared->cache == cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(entry_ptr_ptr); + HDassert(*entry_ptr_ptr); + pf_entry_ptr = *entry_ptr_ptr; + HDassert(pf_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(pf_entry_ptr->type); + HDassert(pf_entry_ptr->type->id == H5AC_PREFETCHED_ENTRY_ID); + HDassert(pf_entry_ptr->prefetched); + HDassert(pf_entry_ptr->image_up_to_date); + HDassert(pf_entry_ptr->image_ptr); + HDassert(pf_entry_ptr->size > 0); + HDassert(pf_entry_ptr->addr == addr); + HDassert(type); + HDassert(type->id == pf_entry_ptr->prefetch_type_id); + HDassert(type->mem_type == cache_ptr->class_table_ptr[type->id]->mem_type); + + /* verify absence of prohibited or unsupported type flag combinations */ + HDassert(!(type->flags & H5C__CLASS_SKIP_READS)); + + /* Can't see how skip reads could be usefully combined with + * either the speculative read flag. Hence disallow. + */ + HDassert(!((type->flags & H5C__CLASS_SKIP_READS) && + (type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG))); + + HDassert(H5F_addr_defined(addr)); + HDassert(type->get_initial_load_size); + HDassert(type->deserialize); + + /* if *pf_entry_ptr is a flush dependency child, destroy all such + * relationships now. The client will restore the relationship(s) with + * the deserialized entry if appropriate. + */ + for(i = (int)(pf_entry_ptr->fd_parent_count) - 1; i >= 0; i--) { + HDassert(pf_entry_ptr->flush_dep_parent); + HDassert(pf_entry_ptr->flush_dep_parent[i]); + HDassert(pf_entry_ptr->flush_dep_parent[i]->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(pf_entry_ptr->flush_dep_parent[i]->flush_dep_nchildren > 0); + HDassert(pf_entry_ptr->fd_parent_addrs); + HDassert(pf_entry_ptr->flush_dep_parent[i]->addr == pf_entry_ptr->fd_parent_addrs[i]); + + if(H5C_destroy_flush_dependency(pf_entry_ptr->flush_dep_parent[i], pf_entry_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "can't destroy pf entry parent flush dependency") + + pf_entry_ptr->fd_parent_addrs[i] = HADDR_UNDEF; + } /* end for */ + HDassert(pf_entry_ptr->flush_dep_nparents == 0); + + /* If *pf_entry_ptr is a flush dependency parent, destroy its flush + * dependency relationships with all its children (which must be + * prefetched entries as well). + * + * These flush dependency relationships will have to be restored + * after the deserialized entry is inserted into the cache in order + * to transfer these relationships to the new entry. Hence save the + * pointers to the flush dependency children of *pf_enty_ptr for later + * use. + */ + if(pf_entry_ptr->fd_child_count > 0) { + if(NULL == (fd_children = (H5C_cache_entry_t **)H5MM_calloc(sizeof(H5C_cache_entry_t **) * (size_t)(pf_entry_ptr->fd_child_count + 1)))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for fd child ptr array") + + if(H5C__destroy_pf_entry_child_flush_deps(cache_ptr, pf_entry_ptr, fd_children) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "can't destroy pf entry child flush dependency(s).") + } /* end if */ + + /* Since the size of the on disk image is known exactly, there is + * no need for either a call to the get_initial_load_size() callback, + * or retries if the H5C__CLASS_SPECULATIVE_LOAD_FLAG flag is set. + * Similarly, there is no need to clamp possible reads beyond + * EOF. + */ + len = pf_entry_ptr->size; + + /* Deserialize the prefetched on-disk image of the entry into the + * native memory form + */ + if(NULL == (thing = type->deserialize(pf_entry_ptr->image_ptr, len, udata, &dirty))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, FAIL, "Can't deserialize image") + + ds_entry_ptr = (H5C_cache_entry_t *)thing; + + /* In general, an entry should be clean just after it is loaded. + * + * However, when this code is used in the metadata cache, it is + * possible that object headers will be dirty at this point, as + * the deserialize function will alter object headers if necessary to + * fix an old bug. + * + * In the following assert: + * + * HDassert( ( dirty == FALSE ) || ( type->id == 5 || type->id == 6 ) ); + * + * note that type ids 5 & 6 are associated with object headers in the + * metadata cache. + * + * When we get to using H5C for other purposes, we may wish to + * tighten up the assert so that the loophole only applies to the + * metadata cache. + * + * Note that at present, dirty can't be set to true with prefetched + * entries. However this may change, so include this functionality + * against that posibility. + * + * Also, note that it is possible for a prefetched entry to be dirty -- + * hence the value assigned to ds_entry_ptr->is_dirty below. + */ + + HDassert( ( dirty == FALSE ) || ( type->id == 5 || type->id == 6) ); + + ds_entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC; + ds_entry_ptr->cache_ptr = f->shared->cache; + ds_entry_ptr->addr = addr; + ds_entry_ptr->size = len; + HDassert(ds_entry_ptr->size < H5C_MAX_ENTRY_SIZE); + ds_entry_ptr->image_ptr = pf_entry_ptr->image_ptr; + ds_entry_ptr->image_up_to_date = !dirty; + ds_entry_ptr->type = type; + ds_entry_ptr->is_dirty = dirty | + pf_entry_ptr->is_dirty; + ds_entry_ptr->dirtied = FALSE; + ds_entry_ptr->is_protected = FALSE; + ds_entry_ptr->is_read_only = FALSE; + ds_entry_ptr->ro_ref_count = 0; + ds_entry_ptr->is_pinned = FALSE; + ds_entry_ptr->in_slist = FALSE; + ds_entry_ptr->flush_marker = FALSE; +#ifdef H5_HAVE_PARALLEL + ds_entry_ptr->clear_on_unprotect = FALSE; + ds_entry_ptr->flush_immediately = FALSE; + ds_entry_ptr->coll_access = FALSE; +#endif /* H5_HAVE_PARALLEL */ + ds_entry_ptr->flush_in_progress = FALSE; + ds_entry_ptr->destroy_in_progress = FALSE; + + ds_entry_ptr->ring = pf_entry_ptr->ring; + + /* Initialize flush dependency height fields */ + ds_entry_ptr->flush_dep_parent = NULL; + ds_entry_ptr->flush_dep_nparents = 0; + ds_entry_ptr->flush_dep_parent_nalloc = 0; + ds_entry_ptr->flush_dep_nchildren = 0; + ds_entry_ptr->flush_dep_ndirty_children = 0; + ds_entry_ptr->flush_dep_nunser_children = 0; + + /* Initialize fields supporting the hash table: */ + ds_entry_ptr->ht_next = NULL; + ds_entry_ptr->ht_prev = NULL; + ds_entry_ptr->il_next = NULL; + ds_entry_ptr->il_prev = NULL; + + /* Initialize fields supporting replacement policies: */ + ds_entry_ptr->next = NULL; + ds_entry_ptr->prev = NULL; + ds_entry_ptr->aux_next = NULL; + ds_entry_ptr->aux_prev = NULL; +#ifdef H5_HAVE_PARALLEL + pf_entry_ptr->coll_next = NULL; + pf_entry_ptr->coll_prev = NULL; +#endif /* H5_HAVE_PARALLEL */ + + /* initialize cache image related fields */ + ds_entry_ptr->include_in_image = FALSE; + ds_entry_ptr->lru_rank = 0; + ds_entry_ptr->image_dirty = FALSE; + ds_entry_ptr->fd_parent_count = 0; + ds_entry_ptr->fd_parent_addrs = NULL; + ds_entry_ptr->fd_child_count = pf_entry_ptr->fd_child_count; + ds_entry_ptr->fd_dirty_child_count = 0; + ds_entry_ptr->image_fd_height = 0; + ds_entry_ptr->prefetched = FALSE; + ds_entry_ptr->prefetch_type_id = 0; + ds_entry_ptr->age = 0; + + H5C__RESET_CACHE_ENTRY_STATS(ds_entry_ptr); + + /* Apply to to the newly deserialized entry */ + if(H5C__tag_entry(cache_ptr, ds_entry_ptr, dxpl_id) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "Cannot tag metadata entry") + + /* We have successfully deserialized the prefetched entry. + * + * Before we return a pointer to the deserialized entry, we must remove + * the prefetched entry from the cache, discard it, and replace it with + * the deserialized entry. Note that we do not free the prefetched + * entries image, as that has been transferred to the deserialized + * entry. + * + * Also note that we have not yet restored any flush dependencies. This + * must wait until the deserialized entry is inserted in the cache. + * + * To delete the prefetched entry from the cache: + * + * 1) Set pf_entry_ptr->image_ptr to NULL. Since we have already + * transferred the buffer containing the image to *ds_entry_ptr, + * this is not a memory leak. + * + * 2) Call H5C__flush_single_entry() with the H5C__FLUSH_INVALIDATE_FLAG + * and H5C__FLUSH_CLEAR_ONLY_FLAG flags set. + */ + pf_entry_ptr->image_ptr = NULL; + if ( pf_entry_ptr->is_dirty ) { + HDassert(pf_entry_ptr->in_slist); + flush_flags |= H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG; + } /* end if */ + + if(H5C__flush_single_entry(f, dxpl_id, pf_entry_ptr, flush_flags) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "can't expunge prefetched entry") + +#ifndef NDEGUG /* verify deletion */ + H5C__SEARCH_INDEX(cache_ptr, addr, pf_entry_ptr, FAIL); + + HDassert(NULL == pf_entry_ptr); +#endif /* NDEBUG */ + + /* Insert the deserialized entry into the cache. */ + H5C__INSERT_IN_INDEX(cache_ptr, ds_entry_ptr, FAIL) + + HDassert(!ds_entry_ptr->in_slist); + + if(ds_entry_ptr->is_dirty) + H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, ds_entry_ptr, FAIL) + + H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, ds_entry_ptr, FAIL) + + /* Deserializing a prefetched entry is the conceptual equivalent of + * loading it from file. If the deserialized entry has a notify callback, + * send an "after load" notice now that the deserialized entry is fully + * integrated into the cache. + */ + if(ds_entry_ptr->type->notify && + (ds_entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_LOAD, ds_entry_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry loaded into cache") + + /* restore flush dependencies with the flush dependency children of + * of the prefetched entry. Note that we must protect *ds_entry_ptr + * before the call to avoid triggering sanity check failures, and + * then unprotect it afterwards. + */ + i = 0; + if(fd_children != NULL) { + int j; + hbool_t found; + + H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, ds_entry_ptr, FAIL) + ds_entry_ptr->is_protected = TRUE; + while(fd_children[i] != NULL) { + /* Sanity checks */ + HDassert((fd_children[i])->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert((fd_children[i])->prefetched); + HDassert((fd_children[i])->fd_parent_count > 0); + HDassert((fd_children[i])->fd_parent_addrs); + + j = 0; + found = FALSE; + while((j < (int)((fd_children[i])->fd_parent_count)) && (!found)) { + if((fd_children[i])->fd_parent_addrs[j] == ds_entry_ptr->addr) + found = TRUE; + + j++; + } /* end while */ + HDassert(found); + + if(H5C_create_flush_dependency(ds_entry_ptr, fd_children[i]) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "Can't restore child flush dependency.") + + i++; + } /* end while */ + + H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, ds_entry_ptr, FAIL); + + ds_entry_ptr->is_protected = FALSE; + } /* end if ( fd_children != NULL ) */ + HDassert((unsigned)i == ds_entry_ptr->fd_child_count); + + ds_entry_ptr->fd_child_count = 0; + H5C__UPDATE_STATS_FOR_PREFETCH_HIT(cache_ptr) + + /* finally, pass ds_entry_ptr back to the caller */ + *entry_ptr_ptr = ds_entry_ptr; + +done: + if(fd_children) + fd_children = (H5C_cache_entry_t **)H5MM_xfree((void *)fd_children); + + /* Release resources on error */ + if(FAIL == ret_value) + if(thing && type->free_icr(thing) < 0) + HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "free_icr callback failed") + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__deserialize_prefetched_entry() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__free_image_entries_array + * + * Purpose: If the image entries array exists, free the image + * associated with each entry, and then free the image + * entries array proper. + * + * Note that by the time this function is called, the cache + * should have removed all entries from its data structures. + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 8/4/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__free_image_entries_array(H5C_t * cache_ptr) +{ + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->close_warning_received); + HDassert(cache_ptr->image_ctl.generate_image); + HDassert(cache_ptr->index_len == 0); + + /* Check for entries to free */ + if(cache_ptr->image_entries != NULL) { + unsigned u; /* Local index variable */ + + for(u = 0; u < cache_ptr->num_entries_in_image; u++) { + H5C_image_entry_t *ie_ptr; /* Image entry to release */ + + /* Get pointer to image entry */ + ie_ptr = &((cache_ptr->image_entries)[u]); + + /* Sanity checks */ + HDassert(ie_ptr); + HDassert(ie_ptr->magic == H5C_IMAGE_ENTRY_T_MAGIC); + HDassert(ie_ptr->image_ptr); + + /* Free the parent addrs array if appropriate */ + if(ie_ptr->fd_parent_addrs) { + HDassert(ie_ptr->fd_parent_count > 0); + + ie_ptr->fd_parent_addrs = (haddr_t *)H5MM_xfree(ie_ptr->fd_parent_addrs); + } /* end if */ + else + HDassert(ie_ptr->fd_parent_count == 0); + + /* Free the image */ + ie_ptr->image_ptr = H5MM_xfree(ie_ptr->image_ptr); + + /* Set magic field to bad magic so we can detect freed entries */ + ie_ptr->magic = H5C_IMAGE_ENTRY_T_BAD_MAGIC; + } /* end for */ + + /* Free the image entries array */ + cache_ptr->image_entries = (H5C_image_entry_t *)H5MM_xfree(cache_ptr->image_entries); + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5C__free_image_entries_array() */ + + +/*------------------------------------------------------------------------- + * Function: H5C_get_cache_image_config + * + * Purpose: Copy the current configuration for cache image generation + * on file close into the instance of H5C_cache_image_ctl_t + * pointed to by config_ptr. + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 7/3/15 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C_get_cache_image_config(const H5C_t * cache_ptr, + H5C_cache_image_ctl_t *config_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC)) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad cache_ptr on entry") + if(config_ptr == NULL) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad config_ptr on entry") + + *config_ptr = cache_ptr->image_ctl; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C_get_cache_image_config() */ + + +/*------------------------------------------------------------------------- + * Function: H5C_image_stats + * + * Purpose: Prints statistics specific to the cache image. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 10/26/15 + * + *------------------------------------------------------------------------- + */ +herr_t +#if H5C_COLLECT_CACHE_STATS +H5C_image_stats(H5C_t * cache_ptr, hbool_t print_header) +#else /* H5C_COLLECT_CACHE_STATS */ +H5C_image_stats(H5C_t * cache_ptr, hbool_t H5_ATTR_UNUSED print_header) +#endif /* H5C_COLLECT_CACHE_STATS */ +{ +#if H5C_COLLECT_CACHE_STATS + int i; + int64_t total_hits = 0; + int64_t total_misses = 0; + double hit_rate; + double prefetch_use_rate; +#endif /* H5C_COLLECT_CACHE_STATS */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + if(!cache_ptr || cache_ptr->magic != H5C__H5C_T_MAGIC) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr") + +#if H5C_COLLECT_CACHE_STATS + for(i = 0; i <= cache_ptr->max_type_id; i++) { + total_hits += cache_ptr->hits[i]; + total_misses += cache_ptr->misses[i]; + } /* end for */ + + if((total_hits > 0) || (total_misses > 0)) + hit_rate = (double)100.0f * ((double)(total_hits)) / ((double)(total_hits + total_misses)); + else + hit_rate = 0.0f; + + if(cache_ptr->prefetches > 0) + prefetch_use_rate = (double)100.0f * ((double)(cache_ptr->prefetch_hits)) / + ((double)(cache_ptr->prefetches)); + else + prefetch_use_rate = 0.0f; + + if(print_header) { + HDfprintf(stdout, + "\nhit prefetches prefetch image pf hit\n"); + HDfprintf(stdout, + "rate: total: dirty: hits: flshs: evct: size: rate:\n"); + } /* end if */ + + HDfprintf(stdout, + "%3.1lf %5lld %5lld %5lld %5lld %5lld %5lld %3.1lf\n", + hit_rate, + (long long)(cache_ptr->prefetches), + (long long)(cache_ptr->dirty_prefetches), + (long long)(cache_ptr->prefetch_hits), + (long long)(cache_ptr->flushes[H5AC_PREFETCHED_ENTRY_ID]), + (long long)(cache_ptr->evictions[H5AC_PREFETCHED_ENTRY_ID]), + (long long)(cache_ptr->last_image_size), + prefetch_use_rate); +#endif /* H5C_COLLECT_CACHE_STATS */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C_image_stats() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__read_cache_image + * + * Purpose: Load the metadata cache image from the specified location + * in the file, and return it in the supplied buffer. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 8/16/15 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C__read_cache_image(H5F_t *f, hid_t dxpl_id, const H5C_t *cache_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(cache_ptr); + HDassert(H5F_addr_defined(cache_ptr->image_addr)); + HDassert(cache_ptr->image_len > 0); + HDassert(cache_ptr->image_buffer); + +#ifdef H5_HAVE_PARALLEL +{ + H5AC_aux_t *aux_ptr = (H5AC_aux_t *)cache_ptr->aux_ptr; + int mpi_result; + + if((NULL == aux_ptr) || (aux_ptr->mpi_rank == 0)) { + HDassert((NULL == aux_ptr) || (aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC)); +#endif /* H5_HAVE_PARALLEL */ + + /* Read the buffer (if serial access, or rank 0 of parallel access) */ + if(H5F_block_read(f, H5FD_MEM_SUPER, cache_ptr->image_addr, cache_ptr->image_len, dxpl_id, cache_ptr->image_buffer) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_READERROR, FAIL, "Can't read metadata cache image block") + +#ifdef H5_HAVE_PARALLEL + if(aux_ptr) { + /* Broadcast cache image */ + if(MPI_SUCCESS != (mpi_result = MPI_Bcast(cache_ptr->image_buffer, (int)cache_ptr->image_len, MPI_BYTE, 0, aux_ptr->mpi_comm))) + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result) + } /* end if */ + } /* end if */ + else if(aux_ptr) { + /* Retrieve the contents of the metadata cache image from process 0 */ + if(MPI_SUCCESS != (mpi_result = MPI_Bcast(cache_ptr->image_buffer, (int)cache_ptr->image_len, MPI_BYTE, 0, aux_ptr->mpi_comm))) + HMPI_GOTO_ERROR(FAIL, "can't receive cache image MPI_Bcast", mpi_result) + } /* end else-if */ +} /* end block */ +#endif /* H5_HAVE_PARALLEL */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__read_cache_image() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__load_cache_image + * + * Purpose: Read the cache image superblock extension message and + * delete it if so directed. + * + * Then load the cache image block at the specified location, + * decode it, and insert its contents into the metadata + * cache. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 7/6/15 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C__load_cache_image(H5F_t *f, hid_t dxpl_id) +{ + H5C_t * cache_ptr; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + cache_ptr = f->shared->cache; + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + + /* If the image address is defined, load the image, decode it, + * and insert its contents into the metadata cache. + * + * Note that under normal operating conditions, it is an error if the + * image address is HADDR_UNDEF. However, to facilitate testing, + * we allow this special value of the image address which means that + * no image exists, and that the load operation should be skipped + * silently. + */ + if(H5F_addr_defined(cache_ptr->image_addr)) { + /* Sanity checks */ + HDassert(cache_ptr->image_len > 0); + HDassert(cache_ptr->image_buffer == NULL); + + /* Allocate space for the image */ + if(NULL == (cache_ptr->image_buffer = H5MM_malloc(cache_ptr->image_len + 1))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for cache image buffer") + + /* Load the image from file */ + if(H5C__read_cache_image(f, dxpl_id, cache_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_READERROR, FAIL, "Can't read metadata cache image block") + + /* Decode metadata cache image */ + if(H5C__decode_cache_image_buffer(f, cache_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTDECODE, FAIL, "Can't decode metadata cache image block") + + /* At this point, the image_data_len should be known */ + HDassert(cache_ptr->image_data_len > 0); + HDassert(cache_ptr->image_data_len <= cache_ptr->image_len); + + /* Insert image contents into cache */ + if(H5C__reconstruct_cache_contents(f, dxpl_id, cache_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTDECODE, FAIL, "Can't reconstruct cache contents from image block") + + /* Free the image buffer */ + cache_ptr->image_buffer = H5MM_xfree(cache_ptr->image_buffer); + + /* Update stats -- must do this now, as we are about + * to discard the size of the cache image. + */ + H5C__UPDATE_STATS_FOR_CACHE_IMAGE_LOAD(cache_ptr) + + /* Free the image entries array. Note that all on disk image + * image buffers and fd parent address arrays have been transferred + * to their respective prefetched entries so we can just free the + * array of H5C_image_entry_t. + */ +#ifndef NDEBUG + { + unsigned u; + + for(u = 0; u < cache_ptr->num_entries_in_image; u++) { + H5C_image_entry_t * ie_ptr; + + ie_ptr = &((cache_ptr->image_entries)[u]); + + HDassert(ie_ptr); + HDassert(ie_ptr->magic == H5C_IMAGE_ENTRY_T_MAGIC); + HDassert(ie_ptr->fd_parent_addrs == NULL); + HDassert(ie_ptr->image_ptr == NULL); + } /* end for */ + } /* end block */ +#endif /* NDEBUG */ + + cache_ptr->image_entries = (H5C_image_entry_t *)H5MM_xfree(cache_ptr->image_entries); + cache_ptr->num_entries_in_image = 0; + + cache_ptr->image_loaded = TRUE; + } /* end if */ + + /* If directed, free the on disk metadata cache image */ + if(cache_ptr->delete_image) { + if(H5F_super_ext_remove_msg(f, dxpl_id, H5O_MDCI_MSG_ID) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove metadata cache image message from superblock extension") + + /* Reset image block values */ + cache_ptr->image_len = 0; + cache_ptr->image_data_len = 0; + cache_ptr->image_addr = HADDR_UNDEF; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__load_cache_image() */ + + +/*------------------------------------------------------------------------- + * Function: H5C_load_cache_image_on_next_protect() + * + * Purpose: Note the fact that a metadata cache image superblock + * extension message exists, along with the base address + * and length of the metadata cache image block. + * + * Once this notification is received the metadata cache + * image block must be read, decoded, and loaded into the + * cache on the next call to H5C_protect(). + * + * Further, if the file is opened R/W, the metadata cache + * image superblock extension message must be deleted from + * the superblock extension and the image block freed + * + * Contrawise, if the file is openened R/O, the metadata + * cache image superblock extension message and image block + * must be left as is. Further, any dirty entries in the + * cache image block must be marked as clean to avoid + * attempts to write them on file close. + * + * Return: SUCCEED + * + * Programmer: John Mainzer + * 7/6/15 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C_load_cache_image_on_next_protect(H5F_t *f, haddr_t addr, hsize_t len, + hbool_t rw) +{ + H5C_t *cache_ptr; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + cache_ptr = f->shared->cache; + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + + /* Set information needed to load cache image */ + cache_ptr->image_addr = addr, + cache_ptr->image_len = len; + cache_ptr->load_image = TRUE; + cache_ptr->delete_image = rw; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5C_load_cache_image_on_next_protect() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__image_entry_cmp + * + * Purpose: Comparison callback for qsort(3) on image entries. + * Entries are sorted first by flush dependency height, + * and then by LRU rank. + * + * Note: Entries with a _greater_ flush dependency height should + * be sorted earlier than entries with lower heights, since + * leafs in the flush dependency graph are at height 0, and their + * parents need to be earlier in the image, so that they can + * construct their flush dependencies when decoded. + * + * Return: An integer less than, equal to, or greater than zero if the + * first entry is considered to be respectively less than, + * equal to, or greater than the second. + * + * Programmer: Quincey Koziol + * 1/20/16 + * + *------------------------------------------------------------------------- + */ +static int +H5C__image_entry_cmp(const void *_entry1, const void *_entry2) +{ + const H5C_image_entry_t *entry1 = (const H5C_image_entry_t *)_entry1; /* Pointer to first image entry to compare */ + const H5C_image_entry_t *entry2 = (const H5C_image_entry_t *)_entry2; /* Pointer to second image entry to compare */ + int ret_value = 0; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(entry1); + HDassert(entry2); + + if(entry1->image_fd_height > entry2->image_fd_height) + ret_value = -1; + else if(entry1->image_fd_height < entry2->image_fd_height) + ret_value = 1; + else { + /* Sanity check */ + HDassert(entry1->lru_rank >= -1); + HDassert(entry2->lru_rank >= -1); + + if(entry1->lru_rank < entry2->lru_rank) + ret_value = -1; + else if(entry1->lru_rank > entry2->lru_rank) + ret_value = 1; + } /* end else */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__image_entry_cmp() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__prep_image_for_file_close + * + * Purpose: The objective of the call is to allow the metadata cache + * to do any preparatory work prior to generation of a + * cache image. + * + * In particular, the cache must + * + * 1) serialize all its entries, + * + * 2) compute the size of the metadata cache image, + * + * 3) allocate space for the metadata cache image, and + * + * 4) setup the metadata cache image superblock extension + * message with the address and size of the metadata + * cache image. + * + * The parallel case is complicated by the fact that + * while all metadata caches must contain the same set of + * dirty entries, there is no such requirement for clean + * entries or the order that entries appear in the LRU. + * + * Thus, there is no requirement that different processes + * will construct cache images of the same size. + * + * This is not a major issue as long as all processes include + * the same set of dirty entries in the cache -- as they + * currently do (note that this will change when we implement + * the ageout feature). Since only the process zero cache + * writes the cache image, all that is necessary is to + * broadcast the process zero cache size for use in the + * superblock extension messages and cache image block + * allocations. + * + * Note: At present, cache image is disabled in the + * parallel case as the new collective metadata write + * code must be modified to support cache image. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 7/3/15 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C__prep_image_for_file_close(H5F_t *f, hid_t dxpl_id) +{ + H5C_t * cache_ptr = NULL; + haddr_t eoa_frag_addr = HADDR_UNDEF; + hsize_t eoa_frag_size = 0; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->cache); + cache_ptr = f->shared->cache; + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + + /* Create the cache image super block extension message. + * + * Note that the base address and length of the metadata cache + * image are undefined at this point, and thus will have to be + * updated later. + * + * Create the super block extension message now so that space + * is allocated for it (if necessary) before we allocate space + * for the cache image block. + * + * To simplify testing, do this only if the + * H5C_CI__GEN_MDCI_SBE_MESG bit is set in + * cache_ptr->image_ctl.flags. + */ + if(cache_ptr->image_ctl.flags & H5C_CI__GEN_MDCI_SBE_MESG) + if(H5C__write_cache_image_superblock_msg(f, dxpl_id, TRUE) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "creation of cache image SB mesg failed.") + + /* Serialize the cache */ + if(H5C__serialize_cache(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "serialization of the cache failed") + + /* Scan the cache and record data needed to construct the + * cache image. In particular, for each entry we must record: + * + * 1) rank in LRU (if entry is in LRU) + * + * 2) Whether the entry is dirty prior to flush of + * cache just prior to close. + * + * 3) Addresses of flush dependency parents (if any). + * + * 4) Number of flush dependency children (if any). + * + * In passing, also compute the size of the metadata cache + * image. With the recent modifications of the free space + * manager code, this size should be correct. + */ + if(H5C__prep_for_file_close__scan_entries(f, cache_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C__prep_for_file_close__scan_entries failed") + HDassert(HADDR_UNDEF == cache_ptr->image_addr); + +#ifdef H5_HAVE_PARALLEL + /* In the parallel case, overwrite the image_len with the + * value computed by process 0. + */ + if(cache_ptr->aux_ptr) { /* we have multiple processes */ + int mpi_result; + unsigned p0_image_len; + H5AC_aux_t * aux_ptr; + + aux_ptr = (H5AC_aux_t *)cache_ptr->aux_ptr; + if(aux_ptr->mpi_rank == 0) { + aux_ptr->p0_image_len = (unsigned)cache_ptr->image_data_len; + p0_image_len = aux_ptr->p0_image_len; + + if(MPI_SUCCESS != (mpi_result = MPI_Bcast(&p0_image_len, 1, MPI_UNSIGNED, 0, aux_ptr->mpi_comm))) + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result) + + HDassert(p0_image_len == aux_ptr->p0_image_len); + } /* end if */ + else { + if(MPI_SUCCESS != (mpi_result = MPI_Bcast(&p0_image_len, 1, MPI_UNSIGNED, 0, aux_ptr->mpi_comm))) + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_result) + + aux_ptr->p0_image_len = p0_image_len; + } /* end else */ + + /* Allocate space for a cache image of size equal to that + * computed by the process 0. This may be different from + * cache_ptr->image_data_len if mpi_rank != 0. However, since + * cache image write is suppressed on all processes other than + * process 0, this doesn't matter. + * + * Note that we allocate the cache image directly from the file + * driver so as to avoid unsettling the free space managers. + */ + if(HADDR_UNDEF == (cache_ptr->image_addr = H5FD_alloc(f->shared->lf, dxpl_id, H5FD_MEM_SUPER, f, + (hsize_t)p0_image_len, &eoa_frag_addr, &eoa_frag_size))) + HGOTO_ERROR(H5E_CACHE, H5E_NOSPACE, FAIL, "can't allocate file space for metadata cache image") + } /* end if */ + else +#endif /* H5_HAVE_PARALLEL */ + /* Allocate the cache image block. Note that we allocate this + * this space directly from the file driver so as to avoid + * unsettling the free space managers. + */ + if(HADDR_UNDEF == (cache_ptr->image_addr = H5FD_alloc(f->shared->lf, dxpl_id, H5FD_MEM_SUPER, f, + (hsize_t)(cache_ptr->image_data_len), &eoa_frag_addr, &eoa_frag_size))) + HGOTO_ERROR(H5E_CACHE, H5E_NOSPACE, FAIL, "can't allocate file space for metadata cache image") + + /* For now, drop any fragment left over from the allocation of the + * image block on the ground. A fragment should only be returned + * if the underlying file alignment is greater than 1. + * + * Clean this up eventually by extending the size of the cache + * image block to the next alignement boundary, and then setting + * the image_data_len to the actual size of the cache_image. + * + * On the off chance that there is some other way to get a + * a fragment on a cache image allocation, leave the following + * assertion in the code so we will find out. + */ + HDassert((eoa_frag_size == 0) || (f->shared->alignment != 1)); + + /* Eventually it will be possible for the length of the cache image + * block on file to be greater than the size of the data it + * contains. However, for now they must be the same. Set + * cache_ptr->image_len accordingly. + */ + cache_ptr->image_len = cache_ptr->image_data_len; + + /* update the metadata cache image superblock extension + * message with the new cache image block base address and + * length. + * + * to simplify testing, do this only if the + * H5C_CI__GEN_MDC_IMAGE_BLK bit is set in + * cache_ptr->image_ctl.flags. + */ + if(cache_ptr->image_ctl.flags & H5C_CI__GEN_MDC_IMAGE_BLK) + if(H5C__write_cache_image_superblock_msg(f, dxpl_id, FALSE) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "update of cache image SB mesg failed.") + + /* At this point: + * + * 1) space in the file for the metadata cache image + * is allocated, + * + * 2) the metadata cache image superblock extension + * message exists and (if so configured) contains + * the correct data, + * + * 3) All entries in the cache that will appear in the + * cache image are serialized with up to date images. + * + * Since we just updated the cache image message, + * the super block extension message is dirty. However, + * since the superblock and the superblock extension + * can't be included in the cache image, this is a non- + * issue. + * + * 4) All entries in the cache that will be include in + * the cache are marked as such, and we have a count + * of same. + * + * 5) Flush dependency heights are calculated for all + * entries that will be included in the cache image. + * + * If there are any entries to be included in the metadata cache + * image, allocate, populate, and sort the image_entries array. + * + * If the metadata cache image will be empty, delete the + * metadata cache image superblock extension message, set + * cache_ptr->image_ctl.generate_image to FALSE. This will + * allow the file close to continue normally without the + * unecessary generation of the metadata cache image. + */ + if(cache_ptr->num_entries_in_image > 0) { + if(H5C__prep_for_file_close__setup_image_entries_array(cache_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTINIT, FAIL, "can't setup image entries array.") + + /* Sort the entries */ + HDqsort(cache_ptr->image_entries, (size_t)cache_ptr->num_entries_in_image, + sizeof(H5C_image_entry_t), H5C__image_entry_cmp); + } /* end if */ + else { /* cancel creation of metadata cache iamge */ + HDassert(cache_ptr->image_entries == NULL); + + /* To avoid breaking the control flow tests, only delete + * the mdci superblock extension message if the + * H5C_CI__GEN_MDC_IMAGE_BLK flag is set in + * cache_ptr->image_ctl.flags. + */ + if(cache_ptr->image_ctl.flags & H5C_CI__GEN_MDC_IMAGE_BLK) + if(H5F_super_ext_remove_msg(f, dxpl_id, H5O_MDCI_MSG_ID) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove MDC image msg from superblock ext.") + + cache_ptr->image_ctl.generate_image = FALSE; + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__prep_image_for_file_close() */ + + +/*------------------------------------------------------------------------- + * Function: H5C_set_cache_image_config + * + * Purpose: If *config_ptr contains valid data, copy it into the + * image_ctl field of *cache_ptr. Make adjustments for + * changes in configuration as required. + * + * Fail if the new configuration is invalid. + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 7/3/15 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C_set_cache_image_config(const H5F_t *f, H5C_t *cache_ptr, + H5C_cache_image_ctl_t *config_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->cache == f->shared->cache); + + /* Check arguments */ + if((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC)) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad cache_ptr on entry") + if(config_ptr == NULL) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "NULL config_ptr on entry") + if(config_ptr->version != H5C__CURR_CACHE_IMAGE_CTL_VER) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Unknown config version") + + /* check general configuration section of the config: */ + if(H5C_validate_cache_image_config(config_ptr) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid cache image configuration") + + if(H5F_INTENT(f) & H5F_ACC_RDWR) /* file has been opened R/W */ + cache_ptr->image_ctl = *config_ptr; + else { /* file opened R/O -- suppress cache image silently */ + H5C_cache_image_ctl_t default_image_ctl = H5C__DEFAULT_CACHE_IMAGE_CTL; + + cache_ptr->image_ctl = default_image_ctl; + HDassert(!(cache_ptr->image_ctl.generate_image)); + } /* end else */ + +#ifdef H5_HAVE_PARALLEL + /* the collective metadata write code is not currently compatible + * with cache image. Until this is fixed, suppress cache image silently + * if there is more than one process. + * JRM -- 11/8/16 + */ + if(cache_ptr->aux_ptr) { + H5C_cache_image_ctl_t default_image_ctl = H5C__DEFAULT_CACHE_IMAGE_CTL; + + cache_ptr->image_ctl = default_image_ctl; + HDassert(!(cache_ptr->image_ctl.generate_image)); + } /* end if */ +#endif /* H5_HAVE_PARALLEL */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C_set_cache_image_config() */ + + +/*------------------------------------------------------------------------- + * Function: H5C_validate_cache_image_config() + * + * Purpose: Run a sanity check on the provided instance of struct + * H5AC_cache_image_config_t. + * + * Do nothing and return SUCCEED if no errors are detected, + * and flag an error and return FAIL otherwise. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 6/15/15 + * + *------------------------------------------------------------------------- + */ +herr_t +H5C_validate_cache_image_config(H5C_cache_image_ctl_t * ctl_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + if(ctl_ptr == NULL) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "NULL ctl_ptr on entry") + if(ctl_ptr->version != H5C__CURR_CACHE_IMAGE_CTL_VER) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown cache image control version") + + /* At present, we do not support inclusion of the adaptive resize + * configuration in the cache image. Thus the save_resize_status + * field must be FALSE. + */ + if(ctl_ptr->save_resize_status != FALSE) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "unexpected value in save_resize_status field") + + /* At present, we do not support prefetched entry ageouts. Thus + * the entry_ageout field must be set to + * H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE. + */ + if(ctl_ptr->entry_ageout != H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "unexpected value in entry_ageout field") + + if((ctl_ptr->flags & ~H5C_CI__ALL_FLAGS) != 0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "unknown flag set") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C_validate_cache_image_config() */ + + +/*************************************************************************/ +/**************************** Private Functions: *************************/ +/*************************************************************************/ + +/*------------------------------------------------------------------------- + * Function: H5C__cache_image_block_entry_header_size + * + * Purpose: Compute the size of the header of the metadata cache + * image block, and return the value. + * + * Return: Size of the header section of the metadata cache image + * block in bytes. + * + * Programmer: John Mainzer + * 7/27/15 + * + *------------------------------------------------------------------------- + */ +static size_t +H5C__cache_image_block_entry_header_size(const H5F_t * f) +{ + size_t ret_value = 0; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Set return value */ + ret_value = (size_t)( 1 + /* type */ + 1 + /* flags */ + 1 + /* ring */ + 1 + /* age */ + 2 + /* dependency child count */ + 2 + /* dirty dep child count */ + 2 + /* dependency parent count */ + 4 + /* index in LRU */ + H5F_SIZEOF_ADDR(f) + /* entry offset */ + H5F_SIZEOF_SIZE(f) ); /* entry length */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__cache_image_block_entry_header_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__cache_image_block_header_size + * + * Purpose: Compute the size of the header of the metadata cache + * image block, and return the value. + * + * Return: Size of the header section of the metadata cache image + * block in bytes. + * + * Programmer: John Mainzer + * 7/27/15 + * + *------------------------------------------------------------------------- + */ +static size_t +H5C__cache_image_block_header_size(const H5F_t * f) +{ + size_t ret_value = 0; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Set return value */ + ret_value = (size_t)( 4 + /* signature */ + 1 + /* version */ + 1 + /* flags */ + H5F_SIZEOF_SIZE(f) + /* image data length */ + 4 ); /* num_entries */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__cache_image_block_header_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__decode_cache_image_buffer() + * + * Purpose: Allocate a suitably size array of instances of + * H5C_image_entry_t and and set cache_ptr->image_entries + * to point to this array. Set cache_ptr->num_entries_in_image + * equal to the number of entries in this array. + * + * Decode the contents of cache_ptr->image_buffer into the + * array. + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 8/9/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__decode_cache_image_buffer(const H5F_t *f, H5C_t *cache_ptr) +{ + uint32_t read_chksum; + uint32_t computed_chksum; + const uint8_t * p; + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(cache_ptr == f->shared->cache); + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->image_buffer); + HDassert(cache_ptr->image_len > 0); + HDassert(cache_ptr->image_data_len == 0); + HDassert(cache_ptr->image_entries == NULL); + HDassert(cache_ptr->num_entries_in_image == 0); + + /* Decode metadata cache image header */ + p = (uint8_t *)cache_ptr->image_buffer; + if(H5C__decode_cache_image_header(f, cache_ptr, &p) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTDECODE, FAIL, "cache image header decode failed") + HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) < cache_ptr->image_len); + + /* cache_ptr->image_data_len should be defined now */ + HDassert(cache_ptr->image_data_len > 0); + HDassert(cache_ptr->image_data_len <= cache_ptr->image_len); + + /* We should now have cache_ptr->num_entries_in_image -- allocate the + * image entries array. + */ + HDassert(cache_ptr->num_entries_in_image > 0); + if(NULL == (cache_ptr->image_entries = (H5C_image_entry_t *)H5MM_malloc(sizeof(H5C_image_entry_t) * (size_t)(cache_ptr->num_entries_in_image + 1)))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed image entries array") + + /* Load the image entries */ + for(u = 0; u < cache_ptr->num_entries_in_image; u++) { + (cache_ptr->image_entries)[u].magic = H5C_IMAGE_ENTRY_T_MAGIC; + (cache_ptr->image_entries)[u].image_fd_height = 0; + (cache_ptr->image_entries)[u].image_ptr = NULL; + + if(H5C__decode_cache_image_entry(f, cache_ptr, &p, u) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTDECODE, FAIL, "entry image decode failed") + } /* end for */ + HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) < cache_ptr->image_len); + + /* (Load the adaptive cache resize status -- not yet) */ + + /* Verify the checksum */ + UINT32DECODE(p, read_chksum); + HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) == cache_ptr->image_data_len); + HDassert((size_t)(p - (uint8_t *)cache_ptr->image_buffer) <= cache_ptr->image_len); + computed_chksum = H5_checksum_metadata(cache_ptr->image_buffer, (size_t)(cache_ptr->image_data_len - H5F_SIZEOF_CHKSUM), 0); + if(read_chksum != computed_chksum) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "bad checksum on metadata cache image block") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__decode_cache_image_buffer() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__decode_cache_image_header() + * + * Purpose: Decode the metadata cache image buffer header from the + * supplied buffer and load the data into the supplied instance + * of H5C_t. Advances the buffer pointer to the first byte + * after the header image, or unchanged on failure. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 8/6/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__decode_cache_image_header(const H5F_t *f, H5C_t *cache_ptr, + const uint8_t **buf) +{ + uint8_t version; + uint8_t flags; + hbool_t have_resize_status = FALSE; + size_t actual_header_len; + size_t expected_header_len; + const uint8_t * p; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(buf); + HDassert(*buf); + + /* Point to buffer to decode */ + p = *buf; + + /* Check signature */ + if(HDmemcmp(p, H5C__MDCI_BLOCK_SIGNATURE, (size_t)H5C__MDCI_BLOCK_SIGNATURE_LEN)) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad metadata cache image header signature") + p += H5C__MDCI_BLOCK_SIGNATURE_LEN; + + /* Check version */ + version = *p++; + if(version != (uint8_t)H5C__MDCI_BLOCK_VERSION_0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad metadata cache image version") + + /* Decode flags */ + flags = *p++; + if(flags & H5C__MDCI_HEADER_HAVE_RESIZE_STATUS) + have_resize_status = TRUE; + if(have_resize_status) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "MDC resize status not yet supported") + + /* Read image data length */ + H5F_DECODE_LENGTH(f, p, cache_ptr->image_data_len); + + /* For now -- will become <= eventually */ + if(cache_ptr->image_data_len != cache_ptr->image_len) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad metadata cache image data length") + + /* Read num entries */ + UINT32DECODE(p, cache_ptr->num_entries_in_image); + if(cache_ptr->num_entries_in_image == 0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad metadata cache entry count") + + /* Verify expected length of header */ + actual_header_len = (size_t)(p - *buf); + expected_header_len = H5C__cache_image_block_header_size(f); + if(actual_header_len != expected_header_len) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad header image len.") + + /* Update buffer pointer */ + *buf = p; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__decode_cache_image_header() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__decode_cache_image_entry() + * + * Purpose: Decode the metadata cache image entry from the supplied + * buffer into the supplied instance of H5C_image_entry_t. + * This includes allocating a buffer for the entry image, + * loading it, and seting ie_ptr->image_ptr to point to + * the buffer. + * + * Advances the buffer pointer to the first byte + * after the entry, or unchanged on failure. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 8/6/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__decode_cache_image_entry(const H5F_t *f, const H5C_t *cache_ptr, + const uint8_t **buf, unsigned entry_num) +{ + hbool_t is_dirty = FALSE; +#ifndef NDEBUG /* only used in assertions */ + hbool_t in_lru = FALSE; + hbool_t is_fd_parent = FALSE; + hbool_t is_fd_child = FALSE; +#endif /* NDEBUG */ /* only used in assertions */ + haddr_t addr; + hsize_t size = 0; + void * image_ptr; + uint8_t flags = 0; + uint8_t type_id; + uint8_t ring; + uint8_t age; + uint16_t fd_child_count; + uint16_t fd_dirty_child_count; + uint16_t fd_parent_count; + haddr_t * fd_parent_addrs = NULL; + int32_t lru_rank; + H5C_image_entry_t * ie_ptr = NULL; + const uint8_t * p; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(cache_ptr == f->shared->cache); + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(buf); + HDassert(*buf); + HDassert(entry_num < cache_ptr->num_entries_in_image); + ie_ptr = &((cache_ptr->image_entries)[entry_num]); + HDassert(ie_ptr); + HDassert(ie_ptr->magic == H5C_IMAGE_ENTRY_T_MAGIC); + + /* Get pointer to buffer */ + p = *buf; + + /* Decode type id */ + type_id = *p++; + + /* Decode flags */ + flags = *p++; + if(flags & H5C__MDCI_ENTRY_DIRTY_FLAG) + is_dirty = TRUE; +#ifndef NDEBUG /* only used in assertions */ + if(flags & H5C__MDCI_ENTRY_IN_LRU_FLAG) + in_lru = TRUE; + if(flags & H5C__MDCI_ENTRY_IS_FD_PARENT_FLAG) + is_fd_parent = TRUE; + if(flags & H5C__MDCI_ENTRY_IS_FD_CHILD_FLAG) + is_fd_child = TRUE; +#endif /* NDEBUG */ /* only used in assertions */ + + /* Decode ring */ + ring = *p++; + HDassert(ring > (uint8_t)(H5C_RING_UNDEFINED)); + HDassert(ring < (uint8_t)(H5C_RING_NTYPES)); + + /* Decode age */ + age = *p++; + + /* Decode dependency child count */ + UINT16DECODE(p, fd_child_count); + HDassert((is_fd_parent && fd_child_count > 0) || (!is_fd_parent && fd_child_count == 0)); + + /* Decode dirty dependency child count */ + UINT16DECODE(p, fd_dirty_child_count); + if(fd_dirty_child_count > fd_child_count) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid dirty flush dependency child count") + + /* Decode dependency parent count */ + UINT16DECODE(p, fd_parent_count); + HDassert((is_fd_child && fd_parent_count > 0) || (!is_fd_child && fd_parent_count == 0)); + + /* Decode index in LRU */ + INT32DECODE(p, lru_rank); + HDassert((in_lru && lru_rank >= 0) || (!in_lru && lru_rank == -1)); + + /* Decode entry offset */ + H5F_addr_decode(f, &p, &addr); + if(!H5F_addr_defined(addr)) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid entry offset") + + /* Decode entry length */ + H5F_DECODE_LENGTH(f, p, size); + if(size == 0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid entry size") + + /* Verify expected length of entry image */ + if((size_t)(p - *buf) != H5C__cache_image_block_entry_header_size(f)) + HGOTO_ERROR(H5E_CACHE, H5E_BADSIZE, FAIL, "Bad entry image len") + + /* If parent count greater than zero, allocate array for parent + * addresses, and decode addresses into the array. + */ + if(fd_parent_count > 0) { + int i; /* Local index variable */ + + if(NULL == (fd_parent_addrs = (haddr_t *)H5MM_malloc((size_t)(fd_parent_count) * H5F_SIZEOF_ADDR(f)))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for fd parent addrs buffer") + + for(i = 0; i < fd_parent_count; i++) { + H5F_addr_decode(f, &p, &(fd_parent_addrs[i])); + if(!H5F_addr_defined(fd_parent_addrs[i])) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid flush dependency parent offset") + } /* end for */ + } /* end if */ + + /* Allocate buffer for entry image */ + if(NULL == (image_ptr = H5MM_malloc(size + H5C_IMAGE_EXTRA_SPACE))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for on disk image buffer") + +#if H5C_DO_MEMORY_SANITY_CHECKS + HDmemcpy(((uint8_t *)image_ptr) + size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + + /* Copy the entry image from the cache image block */ + HDmemcpy(image_ptr, p, size); + p += size; + + /* Copy data into target */ + ie_ptr->addr = addr; + ie_ptr->size = size; + ie_ptr->ring = (H5C_ring_t)ring; + ie_ptr->age = (int32_t)age; + ie_ptr->type_id = (int32_t)type_id; + ie_ptr->lru_rank = lru_rank; + ie_ptr->is_dirty = is_dirty; + ie_ptr->fd_child_count = (uint64_t)fd_child_count; + ie_ptr->fd_dirty_child_count = (uint64_t)fd_dirty_child_count; + ie_ptr->fd_parent_count = (uint64_t)fd_parent_count; + ie_ptr->fd_parent_addrs = fd_parent_addrs; + ie_ptr->image_ptr = image_ptr; + + /* Update buffer pointer */ + *buf = p; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__decode_cache_image_entry() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__destroy_pf_entry_child_flush_deps() + * + * Purpose: Destroy all flush dependencies in this the supplied + * prefetched entry is the parent. Note that the children + * in these flush dependencies must be prefetched entries as + * well. + * + * As this action is part of the process of transferring all + * such flush dependencies to the deserialized version of the + * prefetched entry, ensure that the data necessary to complete + * the transfer is retained. + * + * Note: The current implementation of this function is + * quite inefficient -- mostly due to the current + * implementation of flush dependencies. This should + * be fixed at some point. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 8/11/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__destroy_pf_entry_child_flush_deps(H5C_t *cache_ptr, + H5C_cache_entry_t *pf_entry_ptr, H5C_cache_entry_t **fd_children) +{ + H5C_cache_entry_t * entry_ptr; + unsigned entries_visited = 0; + int fd_children_found = 0; + hbool_t found; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(pf_entry_ptr); + HDassert(pf_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(pf_entry_ptr->type); + HDassert(pf_entry_ptr->type->id == H5AC_PREFETCHED_ENTRY_ID); + HDassert(pf_entry_ptr->prefetched); + HDassert(pf_entry_ptr->fd_child_count > 0); + HDassert(fd_children); + + /* Scan each entry on the index list */ + entry_ptr = cache_ptr->il_head; + while(entry_ptr != NULL) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + + /* Here we look at entry_ptr->flush_dep_nparents and not + * entry_ptr->fd_parent_count as it is possible that some + * or all of the prefetched flush dependency child relationships + * have already been destroyed. + */ + if(entry_ptr->prefetched && (entry_ptr->flush_dep_nparents > 0)) { + unsigned u; /* Local index variable */ + + /* Re-init */ + u = 0; + found = FALSE; + + /* Sanity checks */ + HDassert(entry_ptr->type); + HDassert(entry_ptr->type->id == H5AC_PREFETCHED_ENTRY_ID); + HDassert(entry_ptr->fd_parent_count >= entry_ptr->flush_dep_nparents); + HDassert(entry_ptr->fd_parent_addrs); + HDassert(entry_ptr->flush_dep_parent); + + /* Look for correct entry */ + while(!found && (u < entry_ptr->fd_parent_count)) { + /* Sanity check entry */ + HDassert(entry_ptr->flush_dep_parent[u]); + HDassert(entry_ptr->flush_dep_parent[u]->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + + /* Correct entry? */ + if(pf_entry_ptr == entry_ptr->flush_dep_parent[u]) + found = TRUE; + + u++; + } /* end while */ + + if(found) { + HDassert(NULL == fd_children[fd_children_found]); + + /* Remove flush dependency */ + fd_children[fd_children_found] = entry_ptr; + fd_children_found++; + if(H5C_destroy_flush_dependency(pf_entry_ptr, entry_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "can't destroy pf entry child flush dependency") + +#ifndef NDEBUG + /* Sanity check -- verify that the address of the parent + * appears in entry_ptr->fd_parent_addrs. Must do a search, + * as with flush dependency creates and destroys, + * entry_ptr->fd_parent_addrs and entry_ptr->flush_dep_parent + * can list parents in different order. + */ + found = FALSE; + u = 0; + while(!found && u < entry_ptr->fd_parent_count) { + if(pf_entry_ptr->addr == entry_ptr->fd_parent_addrs[u]) + found = TRUE; + u++; + } /* end while */ + HDassert(found); +#endif /* NDEBUG */ + } /* end if */ + } /* end if */ + + entries_visited++; + entry_ptr = entry_ptr->il_next; + } /* end while */ + + /* Post-op sanity checks */ + HDassert(NULL == fd_children[fd_children_found]); + HDassert((unsigned)fd_children_found == pf_entry_ptr->fd_child_count); + HDassert(entries_visited == cache_ptr->index_len); + HDassert(!pf_entry_ptr->is_pinned); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__destroy_pf_entry_child_flush_deps() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__encode_cache_image_header() + * + * Purpose: Encode the metadata cache image buffer header in the + * supplied buffer. Updates buffer pointer to the first byte + * after the header image in the buffer, or unchanged on failure. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 8/6/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__encode_cache_image_header(const H5F_t *f, const H5C_t *cache_ptr, + uint8_t **buf) +{ + size_t actual_header_len; + size_t expected_header_len; + uint8_t flags = 0; + uint8_t * p; /* Pointer into cache image buffer */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->close_warning_received); + HDassert(cache_ptr->image_ctl.generate_image); + HDassert(cache_ptr->index_len == 0); + HDassert(cache_ptr->image_data_len > 0); + HDassert(cache_ptr->image_data_len <= cache_ptr->image_len); + HDassert(buf); + HDassert(*buf); + + /* Set pointer into buffer */ + p = *buf; + + /* write signature */ + HDmemcpy(p, H5C__MDCI_BLOCK_SIGNATURE, (size_t)H5C__MDCI_BLOCK_SIGNATURE_LEN); + p += H5C__MDCI_BLOCK_SIGNATURE_LEN; + + /* write version */ + *p++ = (uint8_t)H5C__MDCI_BLOCK_VERSION_0; + + /* setup and write flags */ + + /* at present we don't support saving resize status */ + HDassert(!cache_ptr->image_ctl.save_resize_status); + if(cache_ptr->image_ctl.save_resize_status) + flags |= H5C__MDCI_HEADER_HAVE_RESIZE_STATUS; + + *p++ = flags; + + /* Encode image data length */ + /* this must be true at present */ + HDassert(cache_ptr->image_len == cache_ptr->image_data_len); + H5F_ENCODE_LENGTH(f, p, cache_ptr->image_data_len); + + /* write num entries */ + UINT32ENCODE(p, cache_ptr->num_entries_in_image); + + /* verify expected length of header */ + actual_header_len = (size_t)(p - *buf); + expected_header_len = H5C__cache_image_block_header_size(f); + if(actual_header_len != expected_header_len) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad header image len") + + /* Update buffer pointer */ + *buf = p; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__encode_cache_image_header() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__encode_cache_image_entry() + * + * Purpose: Encode the metadata cache image buffer header in the + * supplied buffer. Updates buffer pointer to the first byte + * after the entry in the buffer, or unchanged on failure. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 8/6/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__encode_cache_image_entry(H5F_t *f, H5C_t *cache_ptr, uint8_t **buf, + unsigned entry_num) +{ + H5C_image_entry_t * ie_ptr; /* Pointer to entry to encode */ + uint8_t flags = 0; /* Flags for entry */ + uint8_t * p; /* Pointer into cache image buffer */ + unsigned u; /* Local index value */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(cache_ptr == f->shared->cache); + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->close_warning_received); + HDassert(cache_ptr->image_ctl.generate_image); + HDassert(cache_ptr->index_len == 0); + HDassert(buf); + HDassert(*buf); + HDassert(entry_num < cache_ptr->num_entries_in_image); + ie_ptr = &((cache_ptr->image_entries)[entry_num]); + HDassert(ie_ptr->magic == H5C_IMAGE_ENTRY_T_MAGIC); + + /* Get pointer to buffer to encode into */ + p = *buf; + + /* Encode type */ + if((ie_ptr->type_id < 0) || (ie_ptr->type_id > 255)) + HGOTO_ERROR(H5E_CACHE, H5E_BADRANGE, FAIL, "type_id out of range.") + *p++ = (uint8_t)(ie_ptr->type_id); + + /* Compose and encode flags */ + if(ie_ptr->is_dirty) + flags |= H5C__MDCI_ENTRY_DIRTY_FLAG; + if(ie_ptr->lru_rank > 0) + flags |= H5C__MDCI_ENTRY_IN_LRU_FLAG; + if(ie_ptr->fd_child_count > 0) + flags |= H5C__MDCI_ENTRY_IS_FD_PARENT_FLAG; + if(ie_ptr->fd_parent_count > 0) + flags |= H5C__MDCI_ENTRY_IS_FD_CHILD_FLAG; + *p++ = flags; + + /* Encode ring */ + *p++ = (uint8_t)(ie_ptr->ring); + + /* Encode age */ + *p++ = (uint8_t)(ie_ptr->age); + + /* Validate and encode dependency child count */ + if(ie_ptr->fd_child_count > H5C__MDCI_MAX_FD_CHILDREN) + HGOTO_ERROR(H5E_CACHE, H5E_BADRANGE, FAIL, "fd_child_count out of range") + UINT16ENCODE(p, (uint16_t)(ie_ptr->fd_child_count)); + + /* Validate and encode dirty dependency child count */ + if(ie_ptr->fd_dirty_child_count > H5C__MDCI_MAX_FD_CHILDREN) + HGOTO_ERROR(H5E_CACHE, H5E_BADRANGE, FAIL, "fd_dirty_child_count out of range") + UINT16ENCODE(p, (uint16_t)(ie_ptr->fd_dirty_child_count)); + + /* Validate and encode dependency parent count */ + if(ie_ptr->fd_parent_count > H5C__MDCI_MAX_FD_PARENTS) + HGOTO_ERROR(H5E_CACHE, H5E_BADRANGE, FAIL, "fd_parent_count out of rang.") + UINT16ENCODE(p, (uint16_t)(ie_ptr->fd_parent_count)); + + /* Encode index in LRU */ + INT32ENCODE(p, ie_ptr->lru_rank); + + /* Encode entry offset */ + H5F_addr_encode(f, &p, ie_ptr->addr); + + /* Encode entry length */ + H5F_ENCODE_LENGTH(f, p, ie_ptr->size); + + /* Verify expected length of entry image */ + if((size_t)(p - *buf) != H5C__cache_image_block_entry_header_size(f)) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad entry image len") + + /* Encode dependency parent offsets -- if any */ + for(u = 0; u < ie_ptr->fd_parent_count; u++) + H5F_addr_encode(f, &p, ie_ptr->fd_parent_addrs[u]); + + /* Copy entry image */ + HDmemcpy(p, ie_ptr->image_ptr, ie_ptr->size); + p += ie_ptr->size; + + /* Update buffer pointer */ + *buf = p; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__encode_cache_image_entry() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__prep_for_file_close__compute_fd_heights + * + * Purpose: Recent modifications to flush dependency support in the + * metadata cache have removed the notion of flush dependency + * height. This is a problem for the cache image feature, + * as flush dependency height is used to order entries in the + * cache image so that flush dependency parents appear before + * flush dependency children. (Recall that the flush dependency + * height of an entry in a flush dependency relationship is the + * length of the longest path from the entry to a leaf entry -- + * that is an entry with flush dependency parents, but no + * flush dependency children. With the introduction of the + * possibility of multiple flush dependency parents, we have + * a flush partial dependency latice, not a flush dependency + * tree. But since the partial latice is acyclic, the concept + * of flush dependency height still makes sense. + * + * The purpose of this function is to compute the flush + * dependency height of all entries that appear in the cache + * image. + * + * At present, entries are included or excluded from the + * cache image depending upon the ring in which they reside. + * Thus there is no chance that one side of a flush dependency + * will be in the cache image, and the other side not. + * + * However, once we start placing a limit on the size of the + * cache image, or start excluding prefetched entries from + * the cache image if they haven't been accessed in some + * number of file close / open cycles, this will no longer + * be the case. + * + * In particular, if a flush dependency child is dirty, and + * one of its flush dependency parents is dirty and not in + * the cache image, then the flush dependency child cannot + * be in the cache image without violating flush ordering. + * + * Observe that a clean flush dependency child can be either + * in or out of the cache image without effect on flush + * dependencies. + * + * Similarly, a flush dependency parent can always be part + * of a cache image, regardless of whether it is clean or + * dirty -- but remember that a flush dependency parent can + * also be a flush dependency child. + * + * Finally, note that for purposes of the cache image, flush + * dependency height ends when a flush dependecy relation + * passes off the cache image. + * + * On exit, the flush dependency height of each entry in the + * cache image should be calculated and stored in the cache + * entry. Entries will be removed from the cache image if + * necessary to maintain flush ordering. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 9/6/16 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__prep_for_file_close__compute_fd_heights(const H5C_t *cache_ptr) +{ + H5C_cache_entry_t * entry_ptr; + H5C_cache_entry_t * parent_ptr; + unsigned entries_removed_from_image = 0; + unsigned external_parent_fd_refs_removed = 0; + unsigned external_child_fd_refs_removed = 0; + hbool_t done = FALSE; + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* sanity checks */ + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + + /* Remove from the cache image all dirty entries that are + * flush dependency children of dirty entries that are not in the + * cache image. Must do this, as if we fail to do so, the parent + * will be written to file before the child. Since it is possible + * that the child will have dirty children of its own, this may take + * multiple passes through the index list. + */ + done = FALSE; + while(!done) { + done = TRUE; + entry_ptr = cache_ptr->il_head; + while(entry_ptr != NULL) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + + /* Should this entry be in the image */ + if(entry_ptr->image_dirty && entry_ptr->include_in_image && + (entry_ptr->fd_parent_count > 0)) { + HDassert(entry_ptr->flush_dep_parent != NULL); + for(u = 0; u < entry_ptr->flush_dep_nparents; u++ ) { + parent_ptr = entry_ptr->flush_dep_parent[u]; + + /* Sanity check parent */ + HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(entry_ptr->ring == parent_ptr->ring); + + if(parent_ptr->is_dirty && !parent_ptr->include_in_image && + entry_ptr->include_in_image) { + + /* Must remove child from image -- only do this once */ + entries_removed_from_image++; + entry_ptr->include_in_image = FALSE; + } /* end if */ + } /* for */ + } /* end if */ + + entry_ptr = entry_ptr->il_next; + } /* while ( entry_ptr != NULL ) */ + } /* while ( ! done ) */ + + /* at present, entries are included in the cache image if they reside + * in a specified set of rings. Thus it should be impossible for + * entries_removed_from_image to be positive. Assert that this is + * so. Note that this will change when we start aging entries out + * of the cache image. + */ + HDassert(entries_removed_from_image == 0); + + /* Next, remove from entries in the cache image, references to + * flush dependency parents or children that are not in the cache image. + */ + entry_ptr = cache_ptr->il_head; + while(entry_ptr != NULL) { + if(!entry_ptr->include_in_image && entry_ptr->flush_dep_nparents > 0) { + HDassert(entry_ptr->flush_dep_parent != NULL); + + for(u = 0; u < entry_ptr->flush_dep_nparents; u++ ) { + parent_ptr = entry_ptr->flush_dep_parent[u]; + + /* Sanity check parent */ + HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(entry_ptr->ring == parent_ptr->ring); + + if(parent_ptr->include_in_image) { + /* Must remove reference to child */ + HDassert(parent_ptr->fd_child_count > 0); + parent_ptr->fd_child_count--; + + if(entry_ptr->is_dirty) { + HDassert(parent_ptr->fd_dirty_child_count > 0); + parent_ptr->fd_dirty_child_count--; + } /* end if */ + + external_child_fd_refs_removed++; + } /* end if */ + } /* for */ + } /* end if */ + else if(entry_ptr->include_in_image && entry_ptr->flush_dep_nparents > 0) { + /* Sanity checks */ + HDassert(entry_ptr->flush_dep_parent != NULL); + HDassert(entry_ptr->flush_dep_nparents == entry_ptr->fd_parent_count); + HDassert(entry_ptr->fd_parent_addrs); + + for(u = 0; u < entry_ptr->flush_dep_nparents; u++ ) { + parent_ptr = entry_ptr->flush_dep_parent[u]; + + /* Sanity check parent */ + HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(entry_ptr->ring == parent_ptr->ring); + + if(!parent_ptr->include_in_image) { + /* Must remove reference to parent */ + HDassert(entry_ptr->fd_parent_count > 0); + parent_ptr->fd_child_count--; + + HDassert(parent_ptr->addr == entry_ptr->fd_parent_addrs[u]); + + entry_ptr->fd_parent_addrs[u] = HADDR_UNDEF; + external_parent_fd_refs_removed++; + } /* end if */ + } /* for */ + + /* Touch up fd_parent_addrs array if necessary */ + if(entry_ptr->fd_parent_count == 0) { + H5MM_xfree(entry_ptr->fd_parent_addrs); + entry_ptr->fd_parent_addrs = NULL; + } /* end if */ + else if(entry_ptr->flush_dep_nparents > entry_ptr->fd_parent_count) { + haddr_t * old_fd_parent_addrs = entry_ptr->fd_parent_addrs; + unsigned v; + + if(NULL == (entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_calloc(sizeof(haddr_t) * (size_t)(entry_ptr->fd_parent_addrs)))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for fd parent addr array") + + v = 0; + for(u = 0; u < entry_ptr->flush_dep_nparents; u++) { + if(old_fd_parent_addrs[u] != HADDR_UNDEF) { + entry_ptr->fd_parent_addrs[v] = old_fd_parent_addrs[u]; + v++; + } /* end if */ + } /* end for */ + + HDassert(v == entry_ptr->fd_parent_count); + } /* end else-if */ + } /* end else-if */ + + entry_ptr = entry_ptr->il_next; + } /* while (entry_ptr != NULL) */ + + /* At present, no extenal parent or child flush dependency links + * should exist -- hence the following assertions. This will change + * if we support ageout of entries in the cache image. + */ + HDassert(external_child_fd_refs_removed == 0); + HDassert(external_parent_fd_refs_removed == 0); + + /* At this point we should have removed all flush dependencies that + * cross cache image boundaries. Now compute the flush dependency + * heights for all entries in the image. + * + * Until I can think of a better way, do this via a depth first + * search implemented via a recursive function call. + * + * Note that entry_ptr->image_fd_height has already been initialized to 0 + * for all entries that may appear in the cache image. + */ + entry_ptr = cache_ptr->il_head; + while(entry_ptr != NULL ) { + if(entry_ptr->include_in_image && entry_ptr->fd_child_count == 0 && + entry_ptr->fd_parent_count > 0) { + for(u = 0; u < entry_ptr->fd_parent_count; u++ ) { + parent_ptr = entry_ptr->flush_dep_parent[u]; + + HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + if(parent_ptr->include_in_image && parent_ptr->image_fd_height <= 0) + H5C__prep_for_file_close__compute_fd_heights_real(parent_ptr, 1); + } /* end for */ + } /* end if */ + + entry_ptr = entry_ptr->il_next; + } /* while (entry_ptr != NULL) */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__prep_for_file_close__compute_fd_heights() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__prep_for_file_close__compute_fd_heights_real + * + * Purpose: H5C__prep_for_file_close__compute_fd_heights() prepares + * for the computation of flush dependency heights of all + * entries in the cache image, this function actually does + * it. + * + * The basic observation behind this function is as follows: + * + * Suppose you have an entry E with a flush dependency + * height of X. Then the parents of E must all have + * flush dependency X + 1 or greater. + * + * Use this observation to compute flush dependency height + * of all entries in the cache image via the following + * recursive algorithm: + * + * 1) On entry, set the flush dependency height of the + * supplied cache entry to the supplied value. + * + * 2) Examine all the flush dependency parents of the + * supplied entry. + * + * If the parent is in the cache image, and has flush + * dependency height less than or equal to the flush + * dependency height of the current entry, call the + * recursive routine on the parent with flush dependency + * height equal to the flush dependency height of the + * child plus 1. + * + * Otherwise do nothing. + * + * Observe that if the flush dependency height of all entries + * in the image is initialized to zero, and if this recursive + * function is called with flush dependency height 0 on all + * entries in the cache image with FD parents in the image, + * but without FD children in the image, the correct flush + * dependency height should be set for all entries in the + * cache image. + * + * Return: void + * + * Programmer: John Mainzer + * 9/6/16 + * + *------------------------------------------------------------------------- + */ +static void +H5C__prep_for_file_close__compute_fd_heights_real(H5C_cache_entry_t *entry_ptr, + uint32_t fd_height) +{ + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(entry_ptr); + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(entry_ptr->include_in_image); + HDassert((entry_ptr->image_fd_height == 0) || (entry_ptr->image_fd_height < fd_height)); + HDassert(((fd_height == 0) && (entry_ptr->fd_child_count == 0)) || ((fd_height > 0) && (entry_ptr->fd_child_count > 0))); + + entry_ptr->image_fd_height = fd_height; + if(entry_ptr->flush_dep_nparents > 0) { + unsigned u; + + HDassert(entry_ptr->flush_dep_parent); + for(u = 0; u < entry_ptr->fd_parent_count; u++) { + H5C_cache_entry_t *parent_ptr; + + parent_ptr = entry_ptr->flush_dep_parent[u]; + HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + + if(parent_ptr->include_in_image && parent_ptr->image_fd_height <= fd_height) + H5C__prep_for_file_close__compute_fd_heights_real(parent_ptr, fd_height + 1); + } /* end for */ + } /* end if */ + + FUNC_LEAVE_NOAPI_VOID +} /* H5C__prep_for_file_close__compute_fd_heights_real() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__prep_for_file_close__setup_image_entries_array + * + * Purpose: Allocate space for the image_entries array, and load + * each instance of H5C_image_entry_t in the array with + * the data necessary to construct the metadata cache image. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 8/4/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__prep_for_file_close__setup_image_entries_array(H5C_t *cache_ptr) +{ + H5C_cache_entry_t * entry_ptr; + H5C_image_entry_t * image_entries = NULL; + uint32_t entries_visited = 0; + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->close_warning_received); + HDassert(cache_ptr->pl_len == 0); + HDassert(cache_ptr->num_entries_in_image > 0); + HDassert(cache_ptr->image_entries == NULL); + + /* Allocate and initialize image_entries array */ + if(NULL == (image_entries = (H5C_image_entry_t *)H5MM_malloc(sizeof(H5C_image_entry_t) * (size_t)(cache_ptr->num_entries_in_image + 1)))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for image_entries") + + for(u = 0; u <= cache_ptr->num_entries_in_image; u++) { + image_entries[u].magic = H5C_IMAGE_ENTRY_T_MAGIC; + image_entries[u].addr = HADDR_UNDEF; + image_entries[u].size = 0; + image_entries[u].ring = H5C_RING_UNDEFINED; + image_entries[u].age = 0; + image_entries[u].type_id = -1; + image_entries[u].lru_rank = 0; + image_entries[u].is_dirty = FALSE; + image_entries[u].image_fd_height = 0; + image_entries[u].fd_parent_count = 0; + image_entries[u].fd_parent_addrs = NULL; + image_entries[u].fd_child_count = 0; + image_entries[u].fd_dirty_child_count = 0; + image_entries[u].image_ptr = NULL; + } /* end for */ + + /* Scan each entry on the index list and populate the image_entries array */ + u = 0; + entry_ptr = cache_ptr->il_head; + while(entry_ptr != NULL) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + + if(entry_ptr->include_in_image) { + /* Since we have already serialized the cache, the following + * should hold. + */ + HDassert(entry_ptr->image_up_to_date); + HDassert(entry_ptr->image_ptr); + HDassert(entry_ptr->type); + + image_entries[u].addr = entry_ptr->addr; + image_entries[u].size = entry_ptr->size; + image_entries[u].ring = entry_ptr->ring; + + /* When a prefetched entry is included in the image, store + * its underlying type id in the image entry, not + * H5AC_PREFETCHED_ENTRY_ID. In passing, also increment + * the age (up to H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX). + */ + if(entry_ptr->type->id == H5AC_PREFETCHED_ENTRY_ID) { + image_entries[u].type_id = entry_ptr->prefetch_type_id; + image_entries[u].age = entry_ptr->age + 1; + + if(image_entries[u].age > H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX) + image_entries[u].age = H5AC__CACHE_IMAGE__ENTRY_AGEOUT__MAX; + } /* end if */ + else { + image_entries[u].type_id = entry_ptr->type->id; + image_entries[u].age = 0; + } /* end else */ + + image_entries[u].lru_rank = entry_ptr->lru_rank; + image_entries[u].is_dirty = entry_ptr->is_dirty; + image_entries[u].image_fd_height = entry_ptr->image_fd_height; + image_entries[u].fd_parent_count = entry_ptr->fd_parent_count; + image_entries[u].fd_parent_addrs = entry_ptr->fd_parent_addrs; + image_entries[u].fd_child_count = entry_ptr->fd_child_count; + image_entries[u].fd_dirty_child_count = + entry_ptr->fd_dirty_child_count; + image_entries[u].image_ptr = entry_ptr->image_ptr; + + /* Null out entry_ptr->fd_parent_addrs and set + * entry_ptr->fd_parent_count to zero so that ownership of the + * flush dependency parents address array is transferred to the + * image entry. + */ + entry_ptr->fd_parent_count = 0; + entry_ptr->fd_parent_addrs = NULL; + + u++; + + HDassert(u <= cache_ptr->num_entries_in_image); + } /* end if */ + + entries_visited++; + + entry_ptr = entry_ptr->il_next; + } /* end while */ + + /* Sanity checks */ + HDassert(entries_visited == cache_ptr->index_len); + HDassert(u == cache_ptr->num_entries_in_image); + + HDassert(image_entries[u].fd_parent_addrs == NULL); + HDassert(image_entries[u].image_ptr == NULL); + + cache_ptr->image_entries = image_entries; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__prep_for_file_close__setup_image_entries_array() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__prep_for_file_close__scan_entries + * + * Purpose: Scan all entries in the metadata cache, and store all + * entry specific data required for construction of the + * metadata cache image block and likely to be discarded + * or modified during the cache flush on file close. + * + * In particular, make note of: + * entry rank in LRU + * whether the entry is dirty + * base address of entry flush dependency parent, + * if it exists. + * number of flush dependency children, if any. + * + * Also, determine which entries are to be included in the + * metadata cache image. At present, all entries other than + * the superblock, the superblock extension object header and + * its associated chunks (if any) are included. + * + * Finally, compute the size of the metadata cache image + * block. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 7/21/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__prep_for_file_close__scan_entries(const H5F_t *f, H5C_t *cache_ptr) +{ + H5C_cache_entry_t * entry_ptr; + hbool_t include_in_image; + unsigned entries_visited = 0; + int lru_rank = 1; + uint32_t num_entries_tentatively_in_image = 0; + uint32_t num_entries_in_image = 0; + size_t image_len; + size_t entry_header_len; + size_t fd_parents_list_len; + int i; + unsigned j; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->sblock); + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->close_warning_received); + HDassert(cache_ptr->pl_len == 0); + + /* Initialize image len to the size of the metadata cache image block + * header. + */ + image_len = H5C__cache_image_block_header_size(f); + entry_header_len = H5C__cache_image_block_entry_header_size(f); + + /* Scan each entry on the index list */ + entry_ptr = cache_ptr->il_head; + while(entry_ptr != NULL) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + + /* Since we have already serialized the cache, the following + * should hold. + */ + HDassert(entry_ptr->image_up_to_date); + HDassert(entry_ptr->image_ptr); + + /* Initially, we mark all entries in the rings included + * in the cache image as being included in the in the + * image. Depending on circumstances, we may exclude some + * of these entries later. + */ + if(entry_ptr->ring > H5C_MAX_RING_IN_IMAGE) + include_in_image = FALSE; + else + include_in_image = TRUE; + entry_ptr->include_in_image = include_in_image; + + if(include_in_image) { + entry_ptr->lru_rank = -1; + entry_ptr->image_dirty = entry_ptr->is_dirty; + entry_ptr->image_fd_height = 0; /* will compute this later */ + + /* Initially, include all flush dependency parents in the + * the list of flush dependencies to be stored in the + * image. We may remove some or all of these later. + */ + if(entry_ptr->flush_dep_nparents > 0) { + /* The parents addresses array may already exist -- reallocate + * as needed. + */ + if(entry_ptr->flush_dep_nparents == entry_ptr->fd_parent_count ) { + /* parent addresses array should already be allocated + * and of the correct size. + */ + HDassert(entry_ptr->fd_parent_addrs); + } /* end if */ + else if(entry_ptr->fd_parent_count > 0) { + HDassert(entry_ptr->fd_parent_addrs); + entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_xfree(entry_ptr->fd_parent_addrs); + } /* end else-if */ + else { + HDassert(entry_ptr->fd_parent_count == 0); + HDassert(entry_ptr->fd_parent_addrs == NULL); + } /* end else */ + + entry_ptr->fd_parent_count = entry_ptr->flush_dep_nparents; + if(NULL == entry_ptr->fd_parent_addrs) + if(NULL == (entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_malloc(sizeof(haddr_t) * (size_t)(entry_ptr->fd_parent_count)))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for fd parent addrs buffer") + + for(i = 0; i < (int)(entry_ptr->fd_parent_count); i++) { + entry_ptr->fd_parent_addrs[i] = entry_ptr->flush_dep_parent[i]->addr; + HDassert(H5F_addr_defined(entry_ptr->fd_parent_addrs[i])); + } /* end for */ + } /* end if */ + else if(entry_ptr->fd_parent_count > 0) { + HDassert(entry_ptr->fd_parent_addrs); + entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_xfree(entry_ptr->fd_parent_addrs); + } /* end else-if */ + else + HDassert(entry_ptr->fd_parent_addrs == NULL); + + /* Initially, all flush dependency children are included int + * the count of flush dependency child relationships to be + * represented in the cache image. Some or all of these + * may be dropped from the image later. + */ + if(entry_ptr->flush_dep_nchildren > 0) { + if(!entry_ptr->is_pinned) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "encountered unpinned fd parent?!?") + + entry_ptr->fd_child_count = entry_ptr->flush_dep_nchildren; + entry_ptr->fd_dirty_child_count = entry_ptr->flush_dep_ndirty_children; + } /* end if */ + + num_entries_tentatively_in_image++; + } /* end if */ + + entries_visited++; + entry_ptr = entry_ptr->il_next; + } /* end while */ + HDassert(entries_visited == cache_ptr->index_len); + + /* Now compute the flush dependency heights of all flush dependency + * relationships to be represented in the image. + * + * If all entries in the target rings are included in the + * image, the flush dependency heights are simply the heights + * of all flush dependencies in the target rings. + * + * However, if we restrict appearance in the cache image either + * by number of entries in the image, restrictions on the number + * of times a prefetched entry can appear in an image, or image + * size, it is possible that flush dependency parents or children + * of entries that are in the image may not be included in the + * the image. In this case, we must prune all flush dependency + * relationships that cross the image boundary, and all exclude + * from the image all dirty flush dependency children that have + * a dirty flush dependency parent that is not in the image. + * This is necessary to preserve the required flush ordering. + * + * These details are tended to by the following call to + * H5C__prep_for_file_close__compute_fd_heights(). Because the + * exact contents of the image cannot be known until after this + * call, computation of the image size is delayed. + */ + if(H5C__prep_for_file_close__compute_fd_heights(cache_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "computation of flush dependency heights failed?!?") + + /* At this point, all entries that will appear in the cache + * image should be marked correctly. Compute the size of the + * cache image. + */ + entries_visited = 0; + entry_ptr = cache_ptr->il_head; + while(entry_ptr != NULL) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + + if(entry_ptr->include_in_image) { + if(entry_ptr->fd_parent_count > 0) + fd_parents_list_len = (size_t)(H5F_SIZEOF_ADDR(f) * entry_ptr->fd_parent_count); + else + fd_parents_list_len = (size_t)0; + + image_len += entry_header_len + fd_parents_list_len + entry_ptr->size; + num_entries_in_image++; + } /* end if */ + + entries_visited++; + entry_ptr = entry_ptr->il_next; + } /* end while */ + HDassert(entries_visited == cache_ptr->index_len); + HDassert(num_entries_in_image <= num_entries_tentatively_in_image); + + j = 0; + for(i = H5C_MAX_RING_IN_IMAGE + 1; i <= H5C_RING_SB; i++) + j += cache_ptr->index_ring_len[i]; + + /* This will change */ + HDassert(entries_visited == (num_entries_tentatively_in_image + j)); + + cache_ptr->num_entries_in_image = num_entries_in_image; + entries_visited = 0; + + /* Now scan the LRU list to set the lru_rank fields of all entries + * on the LRU. + * + * Note that we start with rank 1, and increment by 1 with each + * entry on the LRU. + * + * Note that manually pinned entryies will have lru_rank -1, + * and no flush dependency. Putting these entries at the head of + * the reconstructed LRU should be appropriate. + */ + entry_ptr = cache_ptr->LRU_head_ptr; + while(entry_ptr != NULL) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(entry_ptr->type != NULL); + + /* to avoid confusion, don't set lru_rank on epoch markers. + * Note that we still increment the lru_rank, so that the holes + * in the sequence of entries on the LRU will indicate the + * locations of epoch markers (if any) when we reconstruct + * the LRU. + * + * Do not set lru_rank or increment lru_rank for entries + * that will not be included in the cache image. + */ + if(entry_ptr->type->id == H5AC_EPOCH_MARKER_ID) + lru_rank++; + else if(entry_ptr->include_in_image) { + entry_ptr->lru_rank = lru_rank; + lru_rank++; + } /* end else-if */ + + entries_visited++; + entry_ptr = entry_ptr->next; + } /* end while */ + HDassert(entries_visited == cache_ptr->LRU_list_len); + + image_len += H5F_SIZEOF_CHKSUM; + cache_ptr->image_data_len = image_len; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__prep_for_file_close__scan_entries() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__reconstruct_cache_contents() + * + * Purpose: Scan the image_entries array, and create a prefetched + * cache entry for every entry in the array. Insert the + * prefetched entries in the index and the LRU, and + * reconstruct any flush dependencies. Order the entries + * in the LRU as indicated by the stored lru_ranks. + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 8/14/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__reconstruct_cache_contents(H5F_t *f, hid_t dxpl_id, H5C_t *cache_ptr) +{ + H5C_cache_entry_t * pf_entry_ptr; /* Pointer to prefetched entry */ + H5C_cache_entry_t * parent_ptr; /* Pointer to parent of prefetched entry */ + unsigned u, v; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(cache_ptr == f->shared->cache); + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->image_buffer); + HDassert(cache_ptr->image_len > 0); + HDassert(cache_ptr->image_entries != NULL); + HDassert(cache_ptr->num_entries_in_image > 0); + + /* Reconstruct entries in image */ + for(u = 0; u < cache_ptr->num_entries_in_image; u++) { + /* Create the prefetched entry described by the ith + * entry in cache_ptr->image_entrise. + */ + if(NULL == (pf_entry_ptr = H5C__reconstruct_cache_entry(cache_ptr, u))) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "reconstruction of cache entry failed") + + /* Note that we make no checks on available cache space before + * inserting the reconstructed entry into the metadata cache. + * + * This is OK since the cache must be almost empty at the beginning + * of the process, and since we check cache size at the end of the + * reconstruction process. + */ + + /* Insert the prefetched entry in the index */ + H5C__INSERT_IN_INDEX(cache_ptr, pf_entry_ptr, FAIL) + + /* If dirty, insert the entry into the slist. */ + if(pf_entry_ptr->is_dirty) + H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, pf_entry_ptr, FAIL) + + /* Append the entry to the LRU */ + H5C__UPDATE_RP_FOR_INSERT_APPEND(cache_ptr, pf_entry_ptr, FAIL) + + H5C__UPDATE_STATS_FOR_PREFETCH(cache_ptr, pf_entry_ptr->is_dirty) + + /* If the prefetched entry is the child in one or more flush + * dependency relationships, recreate those flush dependencies. + */ + for(v = 0; v < pf_entry_ptr->fd_parent_count; v++) { + /* Sanity checks */ + HDassert(pf_entry_ptr->fd_parent_addrs); + HDassert(H5F_addr_defined(pf_entry_ptr->fd_parent_addrs[v])); + + /* Find the parent entry */ + parent_ptr = NULL; + H5C__SEARCH_INDEX(cache_ptr, pf_entry_ptr->fd_parent_addrs[v], parent_ptr, FAIL) + if(parent_ptr == NULL) + HGOTO_ERROR(H5E_CACHE, H5E_NOTFOUND, FAIL, "fd parent not in cache?!?") + + /* Sanity checks */ + HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(parent_ptr->addr == pf_entry_ptr->fd_parent_addrs[v]); + HDassert(parent_ptr->lru_rank == -1); + + /* Must protect parent entry to set up a flush dependency. + * Do this now, and then uprotect when done. + */ + H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, parent_ptr, FAIL) + parent_ptr->is_protected = TRUE; + + /* Setup the flush dependency */ + if(H5C_create_flush_dependency(parent_ptr, pf_entry_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "Can't restore flush dependency") + + /* And now unprotect */ + H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, parent_ptr, FAIL) + parent_ptr->is_protected = FALSE; + } /* end for */ + } /* end for */ + +#ifndef NDEBUG + /* Scan the image_entries array, and verify that each entry has + * the expected flush dependency status. + */ + for(u = 0; u < cache_ptr->num_entries_in_image; u++) { + H5C_image_entry_t * ie_ptr; + + ie_ptr = &(cache_ptr->image_entries[u]); + HDassert(ie_ptr->magic == H5C_IMAGE_ENTRY_T_MAGIC); + + /* Find the prefetched entry */ + pf_entry_ptr = NULL; + H5C__SEARCH_INDEX(cache_ptr, ie_ptr->addr, pf_entry_ptr, FAIL); + + HDassert(pf_entry_ptr); + HDassert(pf_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(pf_entry_ptr->prefetched); + HDassert(ie_ptr->fd_parent_count == pf_entry_ptr->fd_parent_count); + HDassert(pf_entry_ptr->fd_parent_count == pf_entry_ptr->flush_dep_nparents); + HDassert(ie_ptr->lru_rank == pf_entry_ptr->lru_rank); + + for(v = 0; v < pf_entry_ptr->fd_parent_count; v++) { + parent_ptr = pf_entry_ptr->flush_dep_parent[v]; + HDassert(parent_ptr); + HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(pf_entry_ptr->fd_parent_addrs); + HDassert(pf_entry_ptr->fd_parent_addrs[v] == parent_ptr->addr); + HDassert(parent_ptr->flush_dep_nchildren > 0); + } /* end for */ + + HDassert(ie_ptr->fd_child_count == pf_entry_ptr->fd_child_count); + HDassert(pf_entry_ptr->fd_child_count == pf_entry_ptr->flush_dep_nchildren); + HDassert(pf_entry_ptr->fd_dirty_child_count == pf_entry_ptr->flush_dep_ndirty_children); + } /* end for */ + + /* Scan the LRU, and verify the expected ordering of the + * prefetched entries. + */ + { + int lru_rank_holes = 0; + H5C_cache_entry_t *entry_ptr; + int i; /* Local index variable */ + + i = -1; + entry_ptr = cache_ptr->LRU_head_ptr; + while(entry_ptr != NULL) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(entry_ptr->type != NULL); + + if(entry_ptr->prefetched) { + HDassert(i <= entry_ptr->lru_rank); + HDassert((entry_ptr->lru_rank <= 2) || + (entry_ptr->lru_rank == i + 1) || + (entry_ptr->lru_rank == i + 2)); + + if((entry_ptr->lru_rank <= 2) && (entry_ptr->lru_rank == i + 2)) + lru_rank_holes++; + + i = entry_ptr->lru_rank; + } /* end if */ + + entry_ptr = entry_ptr->next; + } /* end while */ + + /* Holes of size 1 appear in the LRU ranking due to epoch + * markers. They are left in to allow re-insertion of the + * epoch markers on reconstruction of the cache -- thus + * the following sanity check will have to be revised when + * we add code to store and restore adaptive resize status. + */ + HDassert(lru_rank_holes <= H5C__MAX_EPOCH_MARKERS); + } /* end block */ +#endif /* NDEBUG */ + + /* Check to see if the cache is oversize, and evict entries as + * necessary to remain within limits. + */ + if(cache_ptr->index_size >= cache_ptr->max_cache_size) { + /* cache is oversized -- call H5C__make_space_in_cache() with zero + * space needed to repair the situation if possible. + */ + hbool_t write_permitted = FALSE; + + if(cache_ptr->check_write_permitted != NULL) { + if((cache_ptr->check_write_permitted)(f, &write_permitted) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, FAIL, "Can't get write_permitted") + } /* end if */ + else + write_permitted = cache_ptr->write_permitted; + + if(H5C__make_space_in_cache(f, dxpl_id, 0, write_permitted) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, FAIL, "H5C__make_space_in_cache failed") + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__reconstruct_cache_contents() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__reconstruct_cache_entry() + * + * Purpose: Allocate a prefetched metadata cache entry and initialize + * it from the indicated entry in the image_entries array. + * + * Return a pointer to the newly allocated cache entry, + * or NULL on failure. + * + * Return: Pointer to the new instance of H5C_cache_entry on success, + * or NULL on failure. + * + * Programmer: John Mainzer + * 8/14/15 + * + *------------------------------------------------------------------------- + */ +static H5C_cache_entry_t * +H5C__reconstruct_cache_entry(H5C_t *cache_ptr, unsigned index) +{ + H5C_cache_entry_t *pf_entry_ptr = NULL; /* Reconstructed cache entry */ + H5C_image_entry_t *ie_ptr; + H5C_cache_entry_t *ret_value = NULL; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->image_entries != NULL); + HDassert(cache_ptr->num_entries_in_image > 0); + HDassert(index < cache_ptr->num_entries_in_image); + ie_ptr = &((cache_ptr->image_entries)[index]); + HDassert(ie_ptr->magic == H5C_IMAGE_ENTRY_T_MAGIC); + HDassert(H5F_addr_defined(ie_ptr->addr)); + HDassert(ie_ptr->size > 0); + HDassert(ie_ptr->image_ptr); + + /* Allocate space for the prefetched cache entry */ + if(NULL == (pf_entry_ptr = H5FL_CALLOC(H5C_cache_entry_t))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed for prefetched cache entry") + + /* Initialize the prefetched entry from the entry image */ + /* (Only need to set non-zero/NULL/FALSE fields, due to calloc() above) */ + pf_entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC; + pf_entry_ptr->cache_ptr = cache_ptr; + pf_entry_ptr->addr = ie_ptr->addr; + pf_entry_ptr->size = ie_ptr->size; + pf_entry_ptr->ring = ie_ptr->ring; + pf_entry_ptr->age = ie_ptr->age; + pf_entry_ptr->image_ptr = ie_ptr->image_ptr; + pf_entry_ptr->image_up_to_date = TRUE; + pf_entry_ptr->type = H5AC_PREFETCHED_ENTRY; + + /* Force dirty entries to clean if the file read only -- must do + * this as otherwise the cache will attempt to write them on file + * close. Since the file is R/O, the metadata cache image superblock + * extension message and the cache image block will not be removed. + * Hence no danger in this. + */ + pf_entry_ptr->is_dirty = ie_ptr->is_dirty && cache_ptr->delete_image; + + /* Initialize cache image related fields */ + pf_entry_ptr->lru_rank = ie_ptr->lru_rank; + pf_entry_ptr->fd_parent_count = ie_ptr->fd_parent_count; + pf_entry_ptr->fd_parent_addrs = ie_ptr->fd_parent_addrs; + pf_entry_ptr->fd_child_count = ie_ptr->fd_child_count; + pf_entry_ptr->fd_dirty_child_count = ie_ptr->fd_dirty_child_count; + pf_entry_ptr->prefetched = TRUE; + pf_entry_ptr->prefetch_type_id = ie_ptr->type_id; + pf_entry_ptr->age = ie_ptr->age; + + /* Array of addresses of flush dependency parents is now transferred to + * the prefetched entry. Thus set ie_ptr->fd_parent_addrs to NULL. + */ + if(pf_entry_ptr->fd_parent_count > 0) { + HDassert(ie_ptr->fd_parent_addrs); + ie_ptr->fd_parent_addrs = NULL; + } /* end if */ + else + HDassert(ie_ptr->fd_parent_addrs == NULL); + + /* On disk image of entry is now transferred to the prefetched entry. + * Thus set ie_ptr->image_ptr to NULL. + */ + ie_ptr->image_ptr = NULL; + + /* Sanity checks */ + HDassert(pf_entry_ptr->size > 0 && pf_entry_ptr->size < H5C_MAX_ENTRY_SIZE); + + ret_value = pf_entry_ptr; + +done: + if(NULL == ret_value && pf_entry_ptr) + pf_entry_ptr = H5FL_FREE(H5C_cache_entry_t, pf_entry_ptr); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__reconstruct_cache_entry() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__serialize_cache + * + * Purpose: Serialize (i.e. construct an on disk image) for all entries + * in the metadata cache including clean entries. + * + * Note that flush dependencies and "flush me last" flags + * must be observed in the serialization process. + * + * Note also that entries may be loaded, flushed, evicted, + * expunged, relocated, resized, or removed from the cache + * during this process, just as these actions may occur during + * a regular flush. + * + * However, we are given that the cache will contain no protected + * entries on entry to this routine (although entries may be + * briefly protected and then unprotected during the serialize + * process). + * + * The objective of this routine is serialize all entries and + * to force all entries into their actual locations on disk. + * + * The initial need for this routine is to settle all entries + * in the cache prior to construction of the metadata cache + * image so that the size of the cache image can be calculated. + * However, I gather that other uses for the routine are + * under consideration. + * + * Return: Non-negative on success/Negative on failure or if there was + * a request to flush all items and something was protected. + * + * Programmer: John Mainzer + * 7/22/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__serialize_cache(H5F_t *f, hid_t dxpl_id) +{ +#if H5C_DO_SANITY_CHECKS + int i; + uint32_t index_len = 0; + size_t index_size = (size_t)0; + size_t clean_index_size = (size_t)0; + size_t dirty_index_size = (size_t)0; + size_t slist_size = (size_t)0; + uint32_t slist_len = 0; +#endif /* H5C_DO_SANITY_CHECKS */ + H5C_ring_t ring; + H5C_t * cache_ptr; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + cache_ptr = f->shared->cache; + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->slist_ptr); + +#if H5C_DO_SANITY_CHECKS + HDassert(cache_ptr->index_ring_len[H5C_RING_UNDEFINED] == 0); + HDassert(cache_ptr->index_ring_size[H5C_RING_UNDEFINED] == (size_t)0); + HDassert(cache_ptr->clean_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0); + HDassert(cache_ptr->dirty_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0); + HDassert(cache_ptr->slist_ring_len[H5C_RING_UNDEFINED] == 0); + HDassert(cache_ptr->slist_ring_size[H5C_RING_UNDEFINED] == (size_t)0); + + for(i = H5C_RING_USER; i < H5C_RING_NTYPES; i++) { + index_len += cache_ptr->index_ring_len[i]; + index_size += cache_ptr->index_ring_size[i]; + clean_index_size += cache_ptr->clean_index_ring_size[i]; + dirty_index_size += cache_ptr->dirty_index_ring_size[i]; + + slist_len += cache_ptr->slist_ring_len[i]; + slist_size += cache_ptr->slist_ring_size[i]; + } /* end for */ + + HDassert(cache_ptr->index_len == index_len); + HDassert(cache_ptr->index_size == index_size); + HDassert(cache_ptr->clean_index_size == clean_index_size); + HDassert(cache_ptr->dirty_index_size == dirty_index_size); + HDassert(cache_ptr->slist_len == slist_len); + HDassert(cache_ptr->slist_size == slist_size); +#endif /* H5C_DO_SANITY_CHECKS */ + +#if H5C_DO_EXTREME_SANITY_CHECKS + if((H5C_validate_protected_entry_list(cache_ptr) < 0) || + (H5C_validate_pinned_entry_list(cache_ptr) < 0) || + (H5C_validate_lru_list(cache_ptr) < 0)) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry.\n") +#endif /* H5C_DO_EXTREME_SANITY_CHECKS */ + +#ifndef NDEBUG + /* if this is a debug build, set the serialization_count field of + * each entry in the cache to zero before we start the serialization. + * This allows us to detect the case in which any entry is serialized + * more than once (a performance issues), and more importantly, the + * case is which any flush depencency parent is serializes more than + * once (a correctness issue). + */ + { + H5C_cache_entry_t * scan_ptr = NULL; + + scan_ptr = cache_ptr->il_head; + while(scan_ptr != NULL) { + HDassert(scan_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + scan_ptr->serialization_count = 0; + scan_ptr = scan_ptr->il_next; + } /* end while */ + } /* end block */ +#endif /* NDEBUG */ + + /* set cache_ptr->serialization_in_progress to TRUE, and back + * to FALSE at the end of the function. Must maintain this flag + * to support H5C_get_serialization_in_progress(), which is in + * turn required to support sanity checking in some cache + * clients. + */ + HDassert(!cache_ptr->serialization_in_progress); + cache_ptr->serialization_in_progress = TRUE; + + /* Serialize each ring, starting from the outermost ring and + * working inward. + */ + ring = H5C_RING_USER; + while(ring < H5C_RING_NTYPES) { + HDassert(cache_ptr->close_warning_received); + switch(ring) { + case H5C_RING_USER: + break; + + case H5C_RING_RDFSM: + if(!cache_ptr->rdfsm_settled) { + hbool_t fsm_settled = FALSE; /* Whether the FSM was actually settled */ + + /* Settle raw data FSM */ + if(H5MF_settle_raw_data_fsm(f, dxpl_id, &fsm_settled) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "RD FSM settle failed") + + /* Only set the flag if the FSM was actually settled */ + if(fsm_settled) + cache_ptr->rdfsm_settled = TRUE; + } /* end if */ + break; + + case H5C_RING_MDFSM: + if(!cache_ptr->mdfsm_settled) { + hbool_t fsm_settled = FALSE; /* Whether the FSM was actually settled */ + + /* Settle metadata FSM */ + if(H5MF_settle_meta_data_fsm(f, dxpl_id, &fsm_settled) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "MD FSM settle failed") + + /* Only set the flag if the FSM was actually settled */ + if(fsm_settled) + cache_ptr->mdfsm_settled = TRUE; + } /* end if */ + break; + + case H5C_RING_SBE: + case H5C_RING_SB: + break; + + default: + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown ring?!?!") + break; + } /* end switch */ + + if(H5C__serialize_ring(f, dxpl_id, ring) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "serialize ring failed") + + ring++; + } /* end while */ + +#ifndef NDEBUG + /* Verify that no entry has been serialized more than once. + * FD parents with multiple serializations should have been caught + * elsewhere, so no specific check for them here. + */ + { + H5C_cache_entry_t * scan_ptr = NULL; + + scan_ptr = cache_ptr->il_head; + while(scan_ptr != NULL) { + HDassert(scan_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(scan_ptr->serialization_count <= 1); + + scan_ptr = scan_ptr->il_next; + } /* end while */ + } /* end block */ +#endif /* NDEBUG */ + +done: + cache_ptr->serialization_in_progress = FALSE; + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__serialize_cache() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__serialize_ring + * + * Purpose: Serialize the entries contained in the specified cache and + * ring. All entries in rings outside the specified ring + * must have been serialized on entry. + * + * If the cache contains protected entries in the specified + * ring, the function will fail, as protected entries cannot + * be serialized. However all unprotected entries in the + * target ring should be serialized before the function + * returns failure. + * + * If flush dependencies appear in the target ring, the + * function makes repeated passes through the index list + * serializing entries in flush dependency order. + * + * All entries outside the H5C_RING_SBE are marked for + * inclusion in the cache image. Entries in H5C_RING_SBE + * and below are marked for exclusion from the image. + * + * Return: Non-negative on success/Negative on failure or if there was + * a request to flush all items and something was protected. + * + * Programmer: John Mainzer + * 9/11/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__serialize_ring(H5F_t *f, hid_t dxpl_id, H5C_ring_t ring) +{ + hbool_t done = FALSE; + hbool_t restart_list_scan = FALSE; + H5C_t * cache_ptr; + H5C_cache_entry_t * entry_ptr; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + cache_ptr = f->shared->cache; + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(ring > H5C_RING_UNDEFINED); + HDassert(ring < H5C_RING_NTYPES); + + HDassert(cache_ptr->serialization_in_progress); + + /* The objective here is to serialize all entries in the cache ring + * in flush dependency order. + * + * The basic algorithm is to scan the cache index list looking for + * unserialized entries that are either not in a flush dependency + * relationship, or which have no unserialized children. Any such + * entry is serialized and its flush dependency parents (if any) are + * informed -- allowing them to decrement their userialized child counts. + * + * However, this algorithm is complicated by the ability + * of client serialization callbacks to perform operations on + * on the cache which can result in the insertion, deletion, + * relocation, resize, dirty, flush, eviction, or removal (via the + * take ownership flag) of entries. Changes in the flush dependency + * structure are also possible. + * + * On the other hand, the algorithm is simplified by the fact that + * we are serializing, not flushing. Thus, as long as all entries + * are serialized correctly, it doesn't matter if we have to go back + * and serialize an entry a second time. + * + * These possible actions result in the following modfications to + * tha basic algorithm: + * + * 1) In the event of an entry expunge, eviction or removal, we must + * restart the scan as it is possible that the next entry in our + * scan is no longer in the cache. Were we to examine this entry, + * we would be accessing deallocated memory. + * + * 2) A resize, dirty, or insertion of an entry may result in the + * the increment of a flush dependency parent's dirty and/or + * unserialized child count. In the context of serializing the + * the cache, this is a non-issue, as even if we have already + * serialized the parent, it will be marked dirty and its image + * marked out of date if appropriate when the child is serialized. + * + * However, this is a major issue for a flush, as were this to happen + * in a flush, it would violate the invarient that the flush dependency + * feature is intended to enforce. As the metadata cache has no + * control over the behavior of cache clients, it has no way of + * preventing this behaviour. However, it should detect it if at all + * possible. + * + * Do this by maintaining a count of the number of times each entry is + * serialized during a cache serialization. If any flush dependency + * parent is serialized more than once, throw an assertion failure. + * + * 3) An entry relocation will typically change the location of the + * entry in the index list. This shouldn't cause problems as we + * will scan the index list until we make a complete pass without + * finding anything to serialize -- making relocations of either + * the current or next entries irrelevant. + * + * Note that since a relocation may result in our skipping part of + * the index list, we must always do at least one more pass through + * the index list after an entry relocation. + * + * 4) Changes in the flush dependency structure are possible on + * entry insertion, load, expunge, evict, or remove. Destruction + * of a flush dependency has no effect, as it can only relax the + * flush dependencies. Creation of a flush dependency can create + * an unserialized child of a flush dependency parent where all + * flush dependency children were previously serialized. Should + * this child dirty the flush dependency parent when it is serialized, + * the parent will be re-serialized. + * + * Per the discussion of 2) above, this is a non issue for cache + * serialization, and a major problem for cache flush. Using the + * same detection mechanism, throw an assertion failure if this + * condition appears. + * + * Observe that either eviction or removal of entries as a result of + * a serialization is not a problem as long as the flush depencency + * tree does not change beyond the removal of a leaf. + */ + while(!done) { + done = TRUE; /* set to FALSE if any activity in inner loop */ + entry_ptr = cache_ptr->il_head; + while(entry_ptr != NULL) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + + /* Verify that either the entry is already serialized, or + * that it is assigned to either the target or an inner + * ring. + */ + HDassert((entry_ptr->ring >= ring) || (entry_ptr->image_up_to_date)); + + /* Skip flush me last entries or inner ring entries */ + if(!entry_ptr->flush_me_last && entry_ptr->ring == ring) { + + /* if we encounter an unserialized entry in the current + * ring that is not marked flush me last, we are not done. + */ + if(!entry_ptr->image_up_to_date) + done = FALSE; + + /* Serialize the entry if its image is not up to date + * and it has no unserialized flush dependency children. + */ + if(!entry_ptr->image_up_to_date && entry_ptr->flush_dep_nunser_children == 0) { + HDassert(entry_ptr->serialization_count == 0); + + /* Serialize the entry */ + if(H5C__serialize_single_entry(f, dxpl_id, cache_ptr, entry_ptr, &restart_list_scan) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "entry serialization failed") + + HDassert(entry_ptr->flush_dep_nunser_children == 0); + HDassert(entry_ptr->serialization_count == 0); + +#ifndef NDEBUG + entry_ptr->serialization_count++; +#endif /* NDEBUG */ + } /* end if */ + +#if H5C_COLLECT_CACHE_STATS + if(restart_list_scan) + H5C__UPDATE_STATS_FOR_INDEX_SCAN_RESTART(cache_ptr); +#endif /* H5C_COLLECT_CACHE_STATS */ + } /* end if */ + + if(restart_list_scan) { + restart_list_scan = FALSE; + entry_ptr = cache_ptr->il_head; + } /* end if */ + else + entry_ptr = entry_ptr->il_next; + } /* while ( entry_ptr != NULL ) */ + } /* while ( ! done ) */ + + + /* At this point, all entries not marked "flush me last" and in + * the current ring or outside it should be serialized and have up + * to date images. Scan the index list again to serialize the + * "flush me last" entries (if they are in the current ring) and to + * verify that all other entries have up to date images. + */ + entry_ptr = cache_ptr->il_head; + while(entry_ptr != NULL) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(entry_ptr->ring > H5C_RING_UNDEFINED); + HDassert(entry_ptr->ring < H5C_RING_NTYPES); + HDassert((entry_ptr->ring >= ring) || (entry_ptr->image_up_to_date)); + + if(entry_ptr->ring == ring) { + if(entry_ptr->flush_me_last) { + if(!entry_ptr->image_up_to_date) { + HDassert(entry_ptr->serialization_count == 0); + HDassert(entry_ptr->flush_dep_nunser_children == 0); + + /* Serialize the entry */ + if(H5C__serialize_single_entry(f, dxpl_id, cache_ptr, entry_ptr, &restart_list_scan) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "entry serialization failed") + else if(restart_list_scan) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "flush_me_last entry serialization triggered restart") + + HDassert(entry_ptr->flush_dep_nunser_children == 0); + HDassert(entry_ptr->serialization_count == 0); +#ifndef NDEBUG + entry_ptr->serialization_count++; +#endif /* NDEBUG */ + } /* end if */ + } /* end if */ + else { + HDassert(entry_ptr->image_up_to_date); + HDassert(entry_ptr->serialization_count <= 1); + HDassert(entry_ptr->flush_dep_nunser_children == 0); + } /* end else */ + } /* if ( entry_ptr->ring == ring ) */ + + entry_ptr = entry_ptr->il_next; + } /* while ( entry_ptr != NULL ) */ + +done: + HDassert(cache_ptr->serialization_in_progress); + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__serialize_ring() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__serialize_single_entry + * + * Purpose: Serialize the cache entry pointed to by the entry_ptr + * parameter. + * + * Note: This routine is very similar to H5C__generate_image + * and changes to one should probably be reflected in the other. + * Ideally, one should be eliminated. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer, 7/24/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__serialize_single_entry(H5F_t *f, hid_t dxpl_id, H5C_t *cache_ptr, + H5C_cache_entry_t *entry_ptr, hbool_t *restart_list_scan_ptr) +{ + unsigned serialize_flags = H5C__SERIALIZE_NO_FLAGS_SET; + haddr_t new_addr = HADDR_UNDEF; + haddr_t old_addr = HADDR_UNDEF; + size_t new_len = 0; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(entry_ptr); + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(!entry_ptr->prefetched); + HDassert(!entry_ptr->image_up_to_date); + HDassert(entry_ptr->is_dirty); + HDassert(!entry_ptr->is_protected); + HDassert(!entry_ptr->flush_in_progress); + HDassert(entry_ptr->type); + HDassert(restart_list_scan_ptr); + HDassert(*restart_list_scan_ptr == FALSE); + + /* Set entry_ptr->flush_in_progress to TRUE so the the target entry + * will not be evicted out from under us. Must set it back to FALSE + * when we are done. + */ + entry_ptr->flush_in_progress = TRUE; + + /* Allocate buffer for the entry image if required. */ + if(NULL == entry_ptr->image_ptr) { + HDassert(entry_ptr->size > 0); + if(NULL == (entry_ptr->image_ptr = H5MM_malloc(entry_ptr->size + H5C_IMAGE_EXTRA_SPACE)) ) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for on disk image buffer") +#if H5C_DO_MEMORY_SANITY_CHECKS + HDmemcpy(((uint8_t *)entry_ptr->image_ptr) + image_size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + } /* end if */ + + /* Serialize the entry. Note that the entry need not be dirty. */ + + /* Reset cache_ptr->slist_changed so we can detect slist + * modifications in the pre_serialize call. + */ + cache_ptr->slist_changed = FALSE; + + /* Make note of the entry's current address */ + old_addr = entry_ptr->addr; + + /* Reset the counters so that we can detect insertions, loads, + * moves, and flush dependency height changes caused by the pre_serialize + * and serialize calls. + */ + cache_ptr->entries_loaded_counter = 0; + cache_ptr->entries_inserted_counter = 0; + cache_ptr->entries_relocated_counter = 0; + + /* Call client's pre-serialize callback, if there's one */ + if(entry_ptr->type->pre_serialize && + (entry_ptr->type->pre_serialize)(f, dxpl_id, (void *)entry_ptr, entry_ptr->addr, entry_ptr->size, &new_addr, &new_len, &serialize_flags) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to pre-serialize entry") + + /* Check for any flags set in the pre-serialize callback */ + if(serialize_flags != H5C__SERIALIZE_NO_FLAGS_SET) { + + /* Check for unexpected flags from serialize callback */ + if(serialize_flags & ~(H5C__SERIALIZE_RESIZED_FLAG | H5C__SERIALIZE_MOVED_FLAG)) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unknown serialize flag(s)") + +#ifdef H5_HAVE_PARALLEL + /* In the parallel case, resizes and moves in the serialize + * operation can cause problems. If they occur, scream and die. + * + * At present, in the parallel case, the aux_ptr will only be + * set if there is more than one process. Thus we can use this + * to detect the parallel case. + * + * This works for now, but if we start using the aux_ptr for + * other purposes, we will have to change this test accordingly. + * + * NB: While this test detects entryies that attempt + * to resize or move themselves during a flush + * in the parallel case, it will not detect an + * entry that dirties, resizes, and/or moves + * other entries during its flush. + * + * From what Quincey tells me, this test is + * sufficient for now, as any flush routine that + * does the latter will also do the former. + * + * If that ceases to be the case, further + * tests will be necessary. + */ + if(cache_ptr->aux_ptr != NULL) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "resize/move in serialize occured in parallel case.") +#endif /* H5_HAVE_PARALLEL */ + + /* Resize the buffer if required */ + if(serialize_flags & H5C__SERIALIZE_RESIZED_FLAG) { + /* Sanity check */ + HDassert(new_len > 0); + + /* Allocate a new image buffer */ + if(NULL == (entry_ptr->image_ptr = H5MM_realloc(entry_ptr->image_ptr, new_len + H5C_IMAGE_EXTRA_SPACE))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for on disk image buffer") +#if H5C_DO_MEMORY_SANITY_CHECKS + HDmemcpy(((uint8_t *)entry_ptr->image_ptr) + new_len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + + /* Update the entry and the cache data structures for a resize. */ + H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_len) + + /* Update the hash table for the size change */ + H5C__UPDATE_INDEX_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, new_len, entry_ptr, !(entry_ptr->is_dirty)); + + /* The entry can't be protected since we are + * in the process of serializing the cache. Thus we must + * update the replacement policy data structures for the + * size change. The macro deals with the pinned case. + */ + H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_len); + + /* It should be in the skip list, update the skip list for the + * size change. + */ + HDassert(entry_ptr->is_dirty); + HDassert(entry_ptr->in_slist); + H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, new_len) + + /* Finally, update the entry for its new size */ + entry_ptr->size = new_len; + } /* end if */ + + /* If required, update the entry and the cache data structures + * for a move + */ + if(serialize_flags & H5C__SERIALIZE_MOVED_FLAG) { + /* Since the entry has moved, it is probably no longer in + * the same place in its list. Thus at a minimum, we must set + * *restart_list_scan_ptr to TRUE. + */ + *restart_list_scan_ptr = TRUE; + + /* Update stats and the entries relocated counter */ + H5C__UPDATE_STATS_FOR_MOVE(cache_ptr, entry_ptr) + + /* We must update cache data structures for the change in address */ + if(entry_ptr->addr == old_addr) { + /* Delete the entry from the hash table and the slist */ + H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr, FAIL) + H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, FALSE) + + /* Update the entry for its new address */ + entry_ptr->addr = new_addr; + + /* And then reinsert in the index and slist (if appropriate) */ + H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL) + H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) + } /* end if */ + else /* Move is already done for us -- just do sanity checks */ + HDassert(entry_ptr->addr == new_addr); + } /* end if */ + } /* end if ( serialize_flags != H5C__SERIALIZE_NO_FLAGS_SET ) */ + + /* Reset cache_ptr->slist_changed so we can detect slist + * modifications in the serialize call. + */ + cache_ptr->slist_changed = FALSE; + + /* Serialize object into buffer */ + if(entry_ptr->type->serialize(f, entry_ptr->image_ptr, entry_ptr->size, (void *)entry_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to serialize entry") +#if H5C_DO_MEMORY_SANITY_CHECKS + HDassert(0 == HDmemcmp(((uint8_t *)entry_ptr->image_ptr) + image_len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE)); +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + entry_ptr->image_up_to_date = TRUE; + + /* Propagate the fact that the entry is serialized up the + * flush dependency chain if appropriate. Since the image must + * have been out of date for this function to have been called + * (see assertion on entry), no need to check that -- only check + * for flush dependency parents. + */ + HDassert(entry_ptr->flush_dep_nunser_children == 0); + if(entry_ptr->flush_dep_nparents > 0) + if(H5C__mark_flush_dep_serialized(entry_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate flush dep serialized flag") + + /* Reset the flush_in progress flag */ + entry_ptr->flush_in_progress = FALSE; + + /* Set *restart_fd_scan_ptr to TRUE if appropriate, and if we + * haven't already done so. + */ + if(!(*restart_list_scan_ptr)) + if((cache_ptr->entries_loaded_counter > 0) || (cache_ptr->entries_inserted_counter > 0) || + (cache_ptr->entries_relocated_counter > 0)) + *restart_list_scan_ptr = TRUE; + +done: + HDassert((ret_value != SUCCEED) || (!entry_ptr->flush_in_progress)); + HDassert((ret_value != SUCCEED) || (entry_ptr->image_up_to_date)); + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__serialize_single_entry() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__write_cache_image_superblock_msg + * + * Purpose: Write the cache image superblock extension message, + * creating if specified. + * + * In general, the size and location of the cache image block + * will be unknow at the time that the cache image superblock + * message is created. A subsequent call to this routine will + * be used to write the correct data. + * + * Return: Non-negative on success/Negative on failure. + * + * Programmer: John Mainzer, 7/4/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__write_cache_image_superblock_msg(H5F_t *f, hid_t dxpl_id, hbool_t create) +{ + H5C_t * cache_ptr; + H5O_mdci_t mdci_msg; /* metadata cache image message */ + /* to insert in the superblock */ + /* extension. */ + unsigned mesg_flags = H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->cache); + cache_ptr = f->shared->cache; + HDassert(cache_ptr); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->close_warning_received); + + /* Write data into the metadata cache image superblock extension message. + * Note that this data will be bogus when we first create the message. + * We will overwrite this data later in a second call to this function. + */ + mdci_msg.addr = cache_ptr->image_addr; +#ifdef H5_HAVE_PARALLEL + if(cache_ptr->aux_ptr) { /* we have multiple processes */ + H5AC_aux_t * aux_ptr; + + aux_ptr = (H5AC_aux_t *)cache_ptr->aux_ptr; + HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC); + mdci_msg.size = aux_ptr->p0_image_len; + } /* end if */ + else +#endif /* H5_HAVE_PARALLEL */ + mdci_msg.size = cache_ptr->image_len; + + /* Write metadata cache image message to superblock extension */ + if(H5F_super_ext_write_msg(f, dxpl_id, H5O_MDCI_MSG_ID, &mdci_msg, create, mesg_flags) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_WRITEERROR, FAIL, "can't write metadata cache image message to superblock extension") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__write_cache_image_superblock_msg() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__write_cache_image + * + * Purpose: Write the supplied metadata cache image to the specified + * location in file. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 8/26/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__write_cache_image(H5F_t *f, hid_t dxpl_id, const H5C_t *cache_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(f); + HDassert(cache_ptr); + HDassert(H5F_addr_defined(cache_ptr->image_addr)); + HDassert(cache_ptr->image_len > 0); + HDassert(cache_ptr->image_buffer); + +#ifdef H5_HAVE_PARALLEL +{ + H5AC_aux_t *aux_ptr = (H5AC_aux_t *)cache_ptr->aux_ptr; + + if((NULL == aux_ptr) || (aux_ptr->mpi_rank == 0)) { + HDassert((NULL == aux_ptr) || (aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC)); +#endif /* H5_HAVE_PARALLEL */ + + /* Write the buffer (if serial access, or rank 0 for parallel access) */ + if(H5F_block_write(f, H5FD_MEM_SUPER, cache_ptr->image_addr, cache_ptr->image_len, dxpl_id, cache_ptr->image_buffer) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't write metadata cache image block to file.") +#ifdef H5_HAVE_PARALLEL + } /* end if */ +} /* end block */ +#endif /* H5_HAVE_PARALLEL */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__write_cache_image() */ + diff --git a/src/H5Cprefetched.c b/src/H5Cprefetched.c new file mode 100644 index 0000000..9b11006 --- /dev/null +++ b/src/H5Cprefetched.c @@ -0,0 +1,352 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Cprefetched.c + * December 28 2016 + * Quincey Koziol + * + * Purpose: Metadata cache prefetched entry callbacks. + * + *------------------------------------------------------------------------- + */ + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5ACprivate.h" /* Metadata cache */ +#include "H5FLprivate.h" /* Free Lists */ +#include "H5MMprivate.h" /* Memory management */ + + +/****************/ +/* Local Macros */ +/****************/ + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + +/**************************************************************************** + * + * Declarations for prefetched cache entry callbacks. + * + ****************************************************************************/ +static herr_t H5C__prefetched_entry_get_initial_load_size(void *udata_ptr, + size_t *image_len_ptr); +static herr_t H5C__prefetched_entry_get_final_load_size(const void *image_ptr, + size_t image_len, void *udata_ptr, size_t *actual_len_ptr); +static htri_t H5C__prefetched_entry_verify_chksum(const void *image_ptr, + size_t len, void *udata_ptr); +static void * H5C__prefetched_entry_deserialize(const void *image_ptr, + size_t len, void *udata, hbool_t *dirty_ptr); +static herr_t H5C__prefetched_entry_image_len(const void *thing, + size_t *image_len_ptr); +static herr_t H5C__prefetched_entry_pre_serialize(H5F_t *f, + hid_t dxpl_id, void *thing, haddr_t addr, size_t len, + haddr_t *new_addr_ptr, size_t *new_len_ptr, unsigned *flags_ptr); +static herr_t H5C__prefetched_entry_serialize(const H5F_t *f, void *image_ptr, + size_t len, void *thing); +static herr_t H5C__prefetched_entry_notify(H5C_notify_action_t action, + void *thing); +static herr_t H5C__prefetched_entry_free_icr(void *thing); +static herr_t H5C__prefetched_entry_fsf_size(const void *thing, + size_t *fsf_size_ptr); + + +/*********************/ +/* Package Variables */ +/*********************/ + +/* Declare external the free list for H5C_cache_entry_t's */ +H5FL_EXTERN(H5C_cache_entry_t); + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + + +const H5AC_class_t H5AC_PREFETCHED_ENTRY[1] = {{ + /* id = */ H5AC_PREFETCHED_ENTRY_ID, + /* name = */ "prefetched entry", + /* mem_type = */ H5FD_MEM_DEFAULT, /* value doesn't matter */ + /* flags = */ H5AC__CLASS_NO_FLAGS_SET, + /* get_initial_load_size = */ H5C__prefetched_entry_get_initial_load_size, + /* get_final_load_size = */ H5C__prefetched_entry_get_final_load_size, + /* verify_chksum = */ H5C__prefetched_entry_verify_chksum, + /* deserialize = */ H5C__prefetched_entry_deserialize, + /* image_len = */ H5C__prefetched_entry_image_len, + /* pre_serialize = */ H5C__prefetched_entry_pre_serialize, + /* serialize = */ H5C__prefetched_entry_serialize, + /* notify = */ H5C__prefetched_entry_notify, + /* free_icr = */ H5C__prefetched_entry_free_icr, + /* fsf_size = */ H5C__prefetched_entry_fsf_size, +}}; + + + +/*************************************************************************** + * With two exceptions, these functions should never be called, and thus + * there is little point in documenting them separately as they all simply + * throw an error. + * + * See header comments for the two exceptions (free_icr and notify). + * + * JRM - 8/13/15 + * + ***************************************************************************/ + +static herr_t +H5C__prefetched_entry_get_initial_load_size(void H5_ATTR_UNUSED *udata_ptr, + size_t H5_ATTR_UNUSED *image_len_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__prefetched_entry_get_initial_load_size() */ + +static herr_t +H5C__prefetched_entry_get_final_load_size(const void H5_ATTR_UNUSED *image_ptr, + size_t H5_ATTR_UNUSED image_len, void H5_ATTR_UNUSED *udata_ptr, + size_t H5_ATTR_UNUSED *actual_len_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__prefetched_entry_get_final_load_size() */ + +static htri_t +H5C__prefetched_entry_verify_chksum(const void H5_ATTR_UNUSED *image_ptr, + size_t H5_ATTR_UNUSED len, void H5_ATTR_UNUSED *udata_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__prefetched_verify_chksum() */ + + +static void * +H5C__prefetched_entry_deserialize(const void H5_ATTR_UNUSED * image_ptr, + size_t H5_ATTR_UNUSED len, void H5_ATTR_UNUSED * udata, + hbool_t H5_ATTR_UNUSED * dirty_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(NULL) +} /* end H5C__prefetched_entry_deserialize() */ + + +static herr_t +H5C__prefetched_entry_image_len(const void H5_ATTR_UNUSED *thing, + size_t H5_ATTR_UNUSED *image_len_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__prefetched_entry_image_len() */ + + +static herr_t +H5C__prefetched_entry_pre_serialize(H5F_t H5_ATTR_UNUSED *f, + hid_t H5_ATTR_UNUSED dxpl_id, void H5_ATTR_UNUSED *thing, + haddr_t H5_ATTR_UNUSED addr, size_t H5_ATTR_UNUSED len, + haddr_t H5_ATTR_UNUSED *new_addr_ptr, + size_t H5_ATTR_UNUSED *new_len_ptr, + unsigned H5_ATTR_UNUSED *flags_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__prefetched_entry_pre_serialize() */ + + +static herr_t +H5C__prefetched_entry_serialize(const H5F_t H5_ATTR_UNUSED *f, + void H5_ATTR_UNUSED *image_ptr, + size_t H5_ATTR_UNUSED len, void H5_ATTR_UNUSED *thing) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__prefetched_entry_serialize() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__prefetched_entry_notify + * + * Purpose: On H5AC_NOTIFY_ACTION_BEFORE_EVICT, check to see if the + * target entry is a child in a flush dependency relationship. + * If it is, destroy that flush dependency relationship. + * + * Ignore on all other notifications. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 8/13/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__prefetched_entry_notify(H5C_notify_action_t action, void *_thing) +{ + H5C_cache_entry_t * entry_ptr = (H5C_cache_entry_t *)_thing; + unsigned u; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(entry_ptr); + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(entry_ptr->prefetched); + + switch(action) { + case H5C_NOTIFY_ACTION_AFTER_INSERT: + case H5C_NOTIFY_ACTION_AFTER_LOAD: + case H5C_NOTIFY_ACTION_AFTER_FLUSH: + case H5C_NOTIFY_ACTION_ENTRY_DIRTIED: + case H5C_NOTIFY_ACTION_ENTRY_CLEANED: + case H5C_NOTIFY_ACTION_CHILD_DIRTIED: + case H5C_NOTIFY_ACTION_CHILD_CLEANED: + case H5C_NOTIFY_ACTION_CHILD_UNSERIALIZED: + case H5C_NOTIFY_ACTION_CHILD_SERIALIZED: + /* do nothing */ + break; + + case H5C_NOTIFY_ACTION_BEFORE_EVICT: + for(u = 0; u < entry_ptr->flush_dep_nparents; u++) { + H5C_cache_entry_t * parent_ptr; + + /* Sanity checks */ + HDassert(entry_ptr->flush_dep_parent); + parent_ptr = entry_ptr->flush_dep_parent[u]; + HDassert(parent_ptr); + HDassert(parent_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(parent_ptr->flush_dep_nchildren > 0); + + /* Destroy flush dependency with flush dependency parent */ + if(H5C_destroy_flush_dependency(parent_ptr, entry_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "unable to destroy prefetched entry flush dependency") + + if(parent_ptr->prefetched) { + /* In prefetched entries, the fd_child_count field is + * used in sanity checks elsewhere. Thus update this + * field to reflect the destruction of the flush + * dependency relationship. + */ + HDassert(parent_ptr->fd_child_count > 0); + (parent_ptr->fd_child_count)--; + } /* end if */ + } /* end for */ + break; + + default: + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown action from metadata cache") + break; + } /* end switch */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5C__prefetched_entry_notify() */ + + +/*------------------------------------------------------------------------- + * Function: H5C__prefetched_entry_free_icr + * + * Purpose: Free the in core representation of the prefetched entry. + * Verify that the image buffer associated with the entry + * has been either transferred or freed. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 8/13/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__prefetched_entry_free_icr(void *_thing) +{ + H5C_cache_entry_t *entry_ptr = (H5C_cache_entry_t *)_thing; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(entry_ptr); + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(entry_ptr->prefetched); + + /* Release array for flush dependency parent addresses */ + if(entry_ptr->fd_parent_addrs != NULL) { + HDassert(entry_ptr->fd_parent_count > 0); + entry_ptr->fd_parent_addrs = (haddr_t *)H5MM_xfree((void *)entry_ptr->fd_parent_addrs); + } /* end if */ + else + HDassert(entry_ptr->fd_parent_count == 0); + + if(entry_ptr->image_ptr != NULL) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "prefetched entry image buffer still attatched?") + + entry_ptr = H5FL_FREE(H5C_cache_entry_t, entry_ptr); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5C__prefetched_entry_free_icr() */ + + +static herr_t +H5C__prefetched_entry_fsf_size(const void H5_ATTR_UNUSED *thing, + size_t H5_ATTR_UNUSED *fsf_size_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__prefetched_entry_fsf_size() */ + diff --git a/src/H5Ocache_image.c b/src/H5Ocache_image.c new file mode 100644 index 0000000..65f6aa2 --- /dev/null +++ b/src/H5Ocache_image.c @@ -0,0 +1,337 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Ocache_image.c + * June 21, 2015 + * John Mainzer + * + * Purpose: A message indicating that a metadata cache image block + * of the indicated length exists at the specified offset + * in the HDF5 file. + * + * The mdci_msg only appears in the superblock extension. + * + *------------------------------------------------------------------------- + */ + +#include "H5Omodule.h" /* This source code file is part of the H5O module */ + + +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free Lists */ +#include "H5Opkg.h" /* Object headers */ +#include "H5MFprivate.h" /* File space management */ + +/* Callbacks for message class */ +static void *H5O__mdci_decode(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, + unsigned mesg_flags, unsigned *ioflags, const uint8_t *p); +static herr_t H5O__mdci_encode(H5F_t *f, hbool_t disable_shared, + uint8_t *p, const void *_mesg); +static void *H5O__mdci_copy(const void *_mesg, void *_dest); +static size_t H5O__mdci_size(const H5F_t *f, hbool_t disable_shared, + const void *_mesg); +static herr_t H5O__mdci_free(void *mesg); +static herr_t H5O__mdci_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, + void *_mesg); +static herr_t H5O__mdci_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, + FILE *stream, int indent, int fwidth); + +/* This message derives from H5O message class */ +const H5O_msg_class_t H5O_MSG_MDCI[1] = {{ + H5O_MDCI_MSG_ID, /* message id number */ + "mdci", /* message name for debugging */ + sizeof(H5O_mdci_t), /* native message size */ + 0, /* messages are sharable? */ + H5O__mdci_decode, /* decode message */ + H5O__mdci_encode, /* encode message */ + H5O__mdci_copy, /* copy method */ + H5O__mdci_size, /* size of mdc image message */ + NULL, /* reset method */ + H5O__mdci_free, /* free method */ + H5O__mdci_delete, /* file delete method */ + NULL, /* link method */ + NULL, /* set share method */ + NULL, /* can share method */ + NULL, /* pre copy native value to file */ + NULL, /* copy native value to file */ + NULL, /* post copy native value to file */ + NULL, /* get creation index */ + NULL, /* set creation index */ + H5O__mdci_debug /* debugging */ +}}; + +/* Only one version of the metadata cache image message at present */ +#define H5O_MDCI_VERSION_0 0 + +/* Declare the free list for H5O_mdci_t's */ +H5FL_DEFINE(H5O_mdci_t); + + + +/*------------------------------------------------------------------------- + * Function: H5O__mdci_decode + * + * Purpose: Decode a metadata cache image message and return a + * pointer to a newly allocated H5O_mdci_t struct. + * + * Return: Success: Ptr to new message in native struct. + * Failure: NULL + * + * Programmer: John Mainzer + * 6/22/15 + * + *------------------------------------------------------------------------- + */ +static void * +H5O__mdci_decode(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, + H5O_t H5_ATTR_UNUSED *open_oh, unsigned H5_ATTR_UNUSED mesg_flags, + unsigned H5_ATTR_UNUSED *ioflags, const uint8_t *p) +{ + H5O_mdci_t *mesg; /* Native message */ + void *ret_value = NULL; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(f); + HDassert(p); + + /* Version of message */ + if(*p++ != H5O_MDCI_VERSION_0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message") + + /* Allocate space for message */ + if(NULL == (mesg = (H5O_mdci_t *)H5FL_MALLOC(H5O_mdci_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for metadata cache image message") + + /* Decode */ + H5F_addr_decode(f, &p, &(mesg->addr)); + H5F_DECODE_LENGTH(f, p, mesg->size); + + /* Set return value */ + ret_value = (void *)mesg; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__mdci_decode() */ + + +/*------------------------------------------------------------------------- + * Function: H5O__mdci_encode + * + * Purpose: Encode metadata cache image message + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 6/22/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O__mdci_encode(H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, + uint8_t *p, const void *_mesg) +{ + const H5O_mdci_t *mesg = (const H5O_mdci_t *)_mesg; + + FUNC_ENTER_STATIC_NOERR + + /* Sanity check */ + HDassert(f); + HDassert(p); + HDassert(mesg); + + /* encode */ + *p++ = H5O_MDCI_VERSION_0; + H5F_addr_encode(f, &p, mesg->addr); + H5F_ENCODE_LENGTH(f, p, mesg->size); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O__mdci_encode() */ + + +/*------------------------------------------------------------------------- + * Function: H5O__mdci_copy + * + * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if + * necessary. + * + * Return: Success: Ptr to _DEST + * Failure: NULL + * + * Programmer: John Mainzer + * 6/22/15 + * + *------------------------------------------------------------------------- + */ +static void * +H5O__mdci_copy(const void *_mesg, void *_dest) +{ + const H5O_mdci_t *mesg = (const H5O_mdci_t *)_mesg; + H5O_mdci_t *dest = (H5O_mdci_t *) _dest; + void *ret_value = NULL; /* Return value */ + + FUNC_ENTER_STATIC + + /* check args */ + HDassert(mesg); + if(!dest && NULL == (dest = H5FL_MALLOC(H5O_mdci_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* copy */ + *dest = *mesg; + + /* Set return value */ + ret_value = dest; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_mdci__copy() */ + + +/*------------------------------------------------------------------------- + * Function: H5O__mdci_size + * + * Purpose: Returns the size of the raw message in bytes not counting + * the message type or size fields, but only the data fields. + * This function doesn't take into account alignment. + * + * Return: Success: Message data size in bytes without alignment. + * + * Failure: zero + * + * Programmer: John Mainzer + * 6/22/15 + * + *------------------------------------------------------------------------- + */ +static size_t +H5O__mdci_size(const H5F_t *f, hbool_t H5_ATTR_UNUSED disable_shared, + const void H5_ATTR_UNUSED *_mesg) +{ + size_t ret_value = 0; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Set return value */ + ret_value = (size_t)( 1 + /* Version number */ + H5F_SIZEOF_ADDR(f) + /* addr of metadata cache */ + /* image block */ + H5F_SIZEOF_SIZE(f) ); /* length of metadata cache */ + /* image block */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__mdci_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5O__mdci_free + * + * Purpose: Free the message + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 6/22/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O__mdci_free(void *mesg) +{ + FUNC_ENTER_STATIC_NOERR + + HDassert(mesg); + + mesg = H5FL_FREE(H5O_mdci_t, mesg); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O__mdci_free() */ + + +/*------------------------------------------------------------------------- + * Function: H5O__mdci_delete + * + * Purpose: Free file space referenced by message + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, March 19, 2003 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O__mdci_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg) +{ + H5O_mdci_t *mesg = (H5O_mdci_t *)_mesg; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* check args */ + HDassert(f); + HDassert(open_oh); + HDassert(mesg); + + /* Free file space for cache image */ + if(H5F_addr_defined(mesg->addr)) + if(H5MF_xfree(f, H5FD_MEM_SUPER, dxpl_id, mesg->addr, mesg->size) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free file space for cache image block") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__mdci_delete() */ + + +/*------------------------------------------------------------------------- + * Function: H5O__mdci_debug + * + * Purpose: Prints debugging info. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 6/22/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O__mdci_debug(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, + const void *_mesg, FILE * stream, int indent, int fwidth) +{ + const H5O_mdci_t *mdci = (const H5O_mdci_t *) _mesg; + + FUNC_ENTER_STATIC_NOERR + + /* check args */ + HDassert(f); + HDassert(mdci); + HDassert(stream); + HDassert(indent >= 0); + HDassert(fwidth >= 0); + + HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth, + "Metadata Cache Image Block address:", mdci->addr); + + HDfprintf(stream, "%*s%-*s %Hu\n", indent, "", fwidth, + "Metadata Cache Image Block size in bytes:", mdci->size); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O__mdci_debug() */ + diff --git a/test/cache_image.c b/test/cache_image.c new file mode 100644 index 0000000..c91914d --- /dev/null +++ b/test/cache_image.c @@ -0,0 +1,6490 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Programmer: John Mainzer + * 7/13/15 + * + * This file contains tests specific to the cache image + * feature implemented in H5C.c + */ +#include "cache_common.h" +#include "genall5.h" + +/* global variable declarations: */ + + +const char *FILENAMES[] = { + "cache_image_test", + NULL +}; + +/* local utility function declarations */ +static void create_datasets(hid_t file_id, int min_dset, int max_dset); +static void delete_datasets(hid_t file_id, int min_dset, int max_dset); +static void open_hdf5_file(hbool_t create_file, hbool_t mdci_sbem_expected, + hbool_t read_only, hbool_t set_mdci_fapl, hbool_t config_fsm, + const char *hdf_file_name, unsigned cache_image_flags, + hid_t *file_id_ptr, H5F_t **file_ptr_ptr, H5C_t **cache_ptr_ptr); +static void attempt_swmr_open_hdf5_file(hbool_t create_file, + hbool_t set_mdci_fapl, const char *hdf_file_name); +static void verify_datasets(hid_t file_id, int min_dset, int max_dset); + +/* local test function declarations */ +static unsigned check_cache_image_ctl_flow_1(void); +static unsigned check_cache_image_ctl_flow_2(void); +static unsigned check_cache_image_ctl_flow_3(void); +static unsigned check_cache_image_ctl_flow_4(void); +static unsigned check_cache_image_ctl_flow_5(void); +static unsigned check_cache_image_ctl_flow_6(void); + +static unsigned cache_image_smoke_check_1(void); +static unsigned cache_image_smoke_check_2(void); +static unsigned cache_image_smoke_check_3(void); +static unsigned cache_image_smoke_check_4(void); +static unsigned cache_image_smoke_check_5(void); +static unsigned cache_image_smoke_check_6(void); + +static unsigned cache_image_api_error_check_1(void); +static unsigned cache_image_api_error_check_2(void); +static unsigned cache_image_api_error_check_3(void); + + +/****************************************************************************/ +/***************************** Utility Functions ****************************/ +/****************************************************************************/ + +/*------------------------------------------------------------------------- + * Function: create_datasets() + * + * Purpose: If pass is TRUE on entry, create the specified datasets + * in the indicated file. + * + * Datasets and their contents must be well known, as we + * will verify that they contain the expected data later. + * + * On failure, set pass to FALSE, and set failure_mssg + * to point to an appropriate failure message. + * + * Do nothing if pass is FALSE on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 7/15/15 + * + *------------------------------------------------------------------------- + */ + +#define CHUNK_SIZE 10 +#define DSET_SIZE (40 * CHUNK_SIZE) +#define MAX_NUM_DSETS 256 + +static void +create_datasets(hid_t file_id, int min_dset, int max_dset) +{ + const char * fcn_name = "create_datasets()"; + char dset_name[64]; + hbool_t show_progress = FALSE; + hbool_t valid_chunk; + hbool_t verbose = FALSE; + int cp = 0; + int i, j, k, l, m; + int data_chunk[CHUNK_SIZE][CHUNK_SIZE]; + herr_t status; + hid_t dataspace_id = -1; + hid_t filespace_ids[MAX_NUM_DSETS]; + hid_t memspace_id = -1; + hid_t dataset_ids[MAX_NUM_DSETS]; + hid_t properties = -1; + hsize_t dims[2]; + hsize_t a_size[2]; + hsize_t offset[2]; + hsize_t chunk_size[2]; + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + HDassert(0 <= min_dset); + HDassert(min_dset <= max_dset); + HDassert(max_dset < MAX_NUM_DSETS); + + /* create the datasets */ + + if ( pass ) { + + i = min_dset; + + while ( ( pass ) && ( i <= max_dset ) ) + { + /* create a dataspace for the chunked dataset */ + dims[0] = DSET_SIZE; + dims[1] = DSET_SIZE; + dataspace_id = H5Screate_simple(2, dims, NULL); + + if ( dataspace_id < 0 ) { + + pass = FALSE; + failure_mssg = "H5Screate_simple() failed."; + } + + /* set the dataset creation plist to specify that the raw data is + * to be partioned into 10X10 element chunks. + */ + + if ( pass ) { + + chunk_size[0] = CHUNK_SIZE; + chunk_size[1] = CHUNK_SIZE; + properties = H5Pcreate(H5P_DATASET_CREATE); + + if ( properties < 0 ) { + + pass = FALSE; + failure_mssg = "H5Pcreate() failed."; + } + } + + if ( pass ) { + + if ( H5Pset_chunk(properties, 2, chunk_size) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Pset_chunk() failed."; + } + } + + /* create the dataset */ + if ( pass ) { + + sprintf(dset_name, "/dset%03d", i); + dataset_ids[i] = H5Dcreate2(file_id, dset_name, H5T_STD_I32BE, + dataspace_id, H5P_DEFAULT, + properties, H5P_DEFAULT); + + if ( dataset_ids[i] < 0 ) { + + pass = FALSE; + failure_mssg = "H5Dcreate() failed."; + } + } + + /* get the file space ID */ + if ( pass ) { + + filespace_ids[i] = H5Dget_space(dataset_ids[i]); + + if ( filespace_ids[i] < 0 ) { + + pass = FALSE; + failure_mssg = "H5Dget_space() failed."; + } + } + + i++; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* create the mem space to be used to read and write chunks */ + if ( pass ) { + + dims[0] = CHUNK_SIZE; + dims[1] = CHUNK_SIZE; + memspace_id = H5Screate_simple(2, dims, NULL); + + if ( memspace_id < 0 ) { + + pass = FALSE; + failure_mssg = "H5Screate_simple() failed."; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* select in memory hyperslab */ + if ( pass ) { + + offset[0] = 0; /*offset of hyperslab in memory*/ + offset[1] = 0; + a_size[0] = CHUNK_SIZE; /*size of hyperslab*/ + a_size[1] = CHUNK_SIZE; + status = H5Sselect_hyperslab(memspace_id, H5S_SELECT_SET, offset, NULL, + a_size, NULL); + + if ( status < 0 ) { + + pass = FALSE; + failure_mssg = "H5Sselect_hyperslab() failed."; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* initialize all datasets on a round robin basis */ + i = 0; + while ( ( pass ) && ( i < DSET_SIZE ) ) + { + j = 0; + while ( ( pass ) && ( j < DSET_SIZE ) ) + { + m = min_dset; + while ( ( pass ) && ( m <= max_dset ) ) + { + /* initialize the slab */ + for ( k = 0; k < CHUNK_SIZE; k++ ) + { + for ( l = 0; l < CHUNK_SIZE; l++ ) + { + data_chunk[k][l] = (DSET_SIZE * DSET_SIZE * m) + + (DSET_SIZE * (i + k)) + j + l; + } + } + + /* select on disk hyperslab */ + offset[0] = (hsize_t)i; /*offset of hyperslab in file*/ + offset[1] = (hsize_t)j; + a_size[0] = CHUNK_SIZE; /*size of hyperslab*/ + a_size[1] = CHUNK_SIZE; + status = H5Sselect_hyperslab(filespace_ids[m], H5S_SELECT_SET, + offset, NULL, a_size, NULL); + + if ( status < 0 ) { + + pass = FALSE; + failure_mssg = "disk H5Sselect_hyperslab() failed."; + } + + /* write the chunk to file */ + status = H5Dwrite(dataset_ids[m], H5T_NATIVE_INT, memspace_id, + filespace_ids[m], H5P_DEFAULT, data_chunk); + + if ( status < 0 ) { + + pass = FALSE; + failure_mssg = "H5Dwrite() failed."; + } + m++; + } + j += CHUNK_SIZE; + } + + i += CHUNK_SIZE; + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* read data from datasets and validate it */ + i = 0; + while ( ( pass ) && ( i < DSET_SIZE ) ) + { + j = 0; + while ( ( pass ) && ( j < DSET_SIZE ) ) + { + m = min_dset; + while ( ( pass ) && ( m <= max_dset ) ) + { + + /* select on disk hyperslab */ + offset[0] = (hsize_t)i; /* offset of hyperslab in file */ + offset[1] = (hsize_t)j; + a_size[0] = CHUNK_SIZE; /* size of hyperslab */ + a_size[1] = CHUNK_SIZE; + status = H5Sselect_hyperslab(filespace_ids[m], H5S_SELECT_SET, + offset, NULL, a_size, NULL); + + if ( status < 0 ) { + + pass = FALSE; + failure_mssg = "disk hyperslab create failed."; + } + + /* read the chunk from file */ + if ( pass ) { + + status = H5Dread(dataset_ids[m], H5T_NATIVE_INT, + memspace_id, filespace_ids[m], + H5P_DEFAULT, data_chunk); + + if ( status < 0 ) { + + pass = FALSE; + failure_mssg = "disk hyperslab create failed."; + } + } + + /* validate the slab */ + if ( pass ) { + + valid_chunk = TRUE; + for ( k = 0; k < CHUNK_SIZE; k++ ) + { + for ( l = 0; l < CHUNK_SIZE; l++ ) + { + if ( data_chunk[k][l] + != + ((DSET_SIZE * DSET_SIZE * m) + + (DSET_SIZE * (i + k)) + j + l) ) { + + valid_chunk = FALSE; + + if ( verbose ) { + + HDfprintf(stdout, + "data_chunk[%0d][%0d] = %0d, expect %0d.\n", + k, l, data_chunk[k][l], + ((DSET_SIZE * DSET_SIZE * m) + + (DSET_SIZE * (i + k)) + j + l)); + HDfprintf(stdout, + "m = %d, i = %d, j = %d, k = %d, l = %d\n", + m, i, j, k, l); + } + } + } + } + + if ( ! valid_chunk ) { + + pass = FALSE; + failure_mssg = "slab validation failed."; + + if ( verbose ) { + + fprintf(stdout, + "Chunk (%0d, %0d) in /dset%03d is invalid.\n", + i, j, m); + } + } + } + m++; + } + j += CHUNK_SIZE; + } + i += CHUNK_SIZE; + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* close the file spaces */ + i = min_dset; + while ( ( pass ) && ( i <= max_dset ) ) + { + if ( H5Sclose(filespace_ids[i]) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Sclose() failed."; + } + i++; + } + + + /* close the datasets */ + i = min_dset; + while ( ( pass ) && ( i <= max_dset ) ) + { + if ( H5Dclose(dataset_ids[i]) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Dclose() failed."; + } + i++; + } + + /* close the mem space */ + if ( pass ) { + + if ( H5Sclose(memspace_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Sclose(memspace_id) failed."; + } + } + + return; + +} /* create_datasets() */ + + +/*------------------------------------------------------------------------- + * Function: delete_datasets() + * + * Purpose: If pass is TRUE on entry, verify and then delete the + * dataset(s) indicated by min_dset and max_dset in the + * indicated file. + * + * Datasets and their contents must be well know, as we + * will verify that they contain the expected data later. + * + * On failure, set pass to FALSE, and set failure_mssg + * to point to an appropriate failure message. + * + * Do nothing if pass is FALSE on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 10/31/16 + * + *------------------------------------------------------------------------- + */ + +static void +delete_datasets(hid_t file_id, int min_dset, int max_dset) +{ + const char * fcn_name = "delete_datasets()"; + char dset_name[64]; + hbool_t show_progress = FALSE; + int cp = 0; + int i; + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + HDassert(0 <= min_dset); + HDassert(min_dset <= max_dset); + HDassert(max_dset < MAX_NUM_DSETS); + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* first, verify the contents of the target dataset(s) */ + verify_datasets(file_id, min_dset, max_dset); + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* now delete the target datasets */ + if ( pass ) { + + i = min_dset; + + while ( ( pass ) && ( i <= max_dset ) ) + { + sprintf(dset_name, "/dset%03d", i); + + if ( H5Ldelete(file_id, dset_name, H5P_DEFAULT) < 0) { + + pass = FALSE; + failure_mssg = "H5Ldelete() failed."; + } + + i++; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + return; + +} /* delete_datasets() */ + + +/*------------------------------------------------------------------------- + * Function: open_hdf5_file() + * + * Purpose: If pass is true on entry, create or open the specified HDF5 + * and test to see if it has a metadata cache image superblock + * extension message. + * + * Set pass to FALSE and issue a suitable failure + * message if either the file contains a metadata cache image + * superblock extension and mdci_sbem_expected is TRUE, or + * vise versa. + * + * If mdci_sbem_expected is TRUE, also verify that the metadata + * cache has been advised of this. + * + * If read_only is TRUE, open the file read only. Otherwise + * open the file read/write. + * + * If set_mdci_fapl is TRUE, set the metadata cache image + * FAPL entry when opening the file, and verify that the + * metadata cache is notified. + * + * If config_fsm is TRUE, setup the persistant free space + * manager. Note that this flag may only be set if + * create_file is also TRUE. + * + * Return pointers to the cache data structure and file data + * structures. + * + * On failure, set pass to FALSE, and set failure_mssg + * to point to an appropriate failure message. + * + * Do nothing if pass is FALSE on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 7/14/15 + * + *------------------------------------------------------------------------- + */ + +static void +open_hdf5_file(hbool_t create_file, hbool_t mdci_sbem_expected, + hbool_t read_only, hbool_t set_mdci_fapl, hbool_t config_fsm, + const char *hdf_file_name, unsigned cache_image_flags, + hid_t *file_id_ptr, H5F_t ** file_ptr_ptr, H5C_t ** cache_ptr_ptr) +{ + const char * fcn_name = "open_hdf5_file()"; + hbool_t show_progress = FALSE; + hbool_t verbose = FALSE; + int cp = 0; + hid_t fapl_id = -1; + hid_t fcpl_id = -1; + hid_t file_id = -1; + herr_t result; + H5F_t * file_ptr = NULL; + H5C_t * cache_ptr = NULL; + H5C_cache_image_ctl_t image_ctl; + H5AC_cache_image_config_t cache_image_config = { + H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION, + TRUE, + FALSE, + H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE}; + + if ( pass ) + { + /* opening the file both read only and with a cache image + * requested is a contradiction. We resolve it by ignoring + * the cache image request silently. + */ + if ( ( create_file && mdci_sbem_expected ) || + ( create_file && read_only ) || + ( config_fsm && !create_file ) || + ( hdf_file_name == NULL ) || + ( ( set_mdci_fapl ) && ( cache_image_flags == 0 ) ) || + ( ( set_mdci_fapl ) && + ( (cache_image_flags & ~H5C_CI__ALL_FLAGS) != 0 ) ) || + ( file_id_ptr == NULL ) || + ( file_ptr_ptr == NULL ) || + ( cache_ptr_ptr == NULL ) ) { + + failure_mssg = + "Bad param(s) on entry to open_hdf5_file().\n"; + pass = FALSE; + } else if ( verbose ) { + + HDfprintf(stdout, "%s: HDF file name = \"%s\".\n", + fcn_name, hdf_file_name); + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* create a file access propertly list. */ + if ( pass ) { + + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + + if ( fapl_id < 0 ) { + + pass = FALSE; + failure_mssg = "H5Pcreate() failed.\n"; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* call H5Pset_libver_bounds() on the fapl_id */ + if ( pass ) { + + if ( H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Pset_libver_bounds() failed.\n"; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* get metadata cache image config -- verify that it is the default */ + if ( pass ) { + + result = H5Pget_mdc_image_config(fapl_id, &cache_image_config); + + if ( result < 0 ) { + + pass = FALSE; + failure_mssg = "H5Pget_mdc_image_config() failed.\n"; + } + + if ( ( cache_image_config.version != + H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION ) || + ( cache_image_config.generate_image != FALSE ) || + ( cache_image_config.save_resize_status != FALSE ) || + ( cache_image_config.entry_ageout != + H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE ) ) { + + pass = FALSE; + failure_mssg = "Unexpected default cache image config.\n"; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* set metadata cache image fapl entry if indicated */ + if ( ( pass ) && ( set_mdci_fapl ) ) { + + /* set cache image config fields to taste */ + cache_image_config.generate_image = TRUE; + cache_image_config.save_resize_status = FALSE; + cache_image_config.entry_ageout = H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE; + + result = H5Pset_mdc_image_config(fapl_id, &cache_image_config); + + if ( result < 0 ) { + + pass = FALSE; + failure_mssg = "H5Pset_mdc_image_config() failed.\n"; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* setup the persistant free space manager if indicated */ + if ( ( pass ) && ( config_fsm ) ) { + + fcpl_id = H5Pcreate(H5P_FILE_CREATE); + + if ( fcpl_id <= 0 ) { + + pass = FALSE; + failure_mssg = "H5Pcreate(H5P_FILE_CREATE) failed."; + } + } + + if ( ( pass ) && ( config_fsm ) ) { + + if ( H5Pset_file_space(fcpl_id, H5F_FILE_SPACE_ALL_PERSIST, 1) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Pset_file_space() failed."; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* open the file */ + if ( pass ) { + + if ( create_file ) { + + if ( fcpl_id != -1 ) + + file_id = H5Fcreate(hdf_file_name, H5F_ACC_TRUNC, fcpl_id, fapl_id); + else + + file_id = H5Fcreate(hdf_file_name, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + + } else { + + if ( read_only ) + + file_id = H5Fopen(hdf_file_name, H5F_ACC_RDONLY, fapl_id); + + else + + file_id = H5Fopen(hdf_file_name, H5F_ACC_RDWR, fapl_id); + } + + if ( file_id < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fcreate() or H5Fopen() failed.\n"; + + } else { + + file_ptr = (struct H5F_t *)H5I_object_verify(file_id, H5I_FILE); + + if ( file_ptr == NULL ) { + + pass = FALSE; + failure_mssg = "Can't get file_ptr."; + + if ( verbose ) { + HDfprintf(stdout, "%s: Can't get file_ptr.\n", fcn_name); + } + } + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* get a pointer to the files internal data structure and then + * to the cache structure + */ + if ( pass ) { + + if ( file_ptr->shared->cache == NULL ) { + + pass = FALSE; + failure_mssg = "can't get cache pointer(1).\n"; + + } else { + + cache_ptr = file_ptr->shared->cache; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* verify expected metadata cache status */ + + /* get the cache image control structure from the cache, and verify + * that it contains the expected values. + * + * Then set the flags in this structure to the specified value. + */ + if ( pass ) { + + if ( H5C_get_cache_image_config(cache_ptr, &image_ctl) < 0 ) { + + pass = FALSE; + failure_mssg = "error returned by H5C_get_cache_image_config()."; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + if ( pass ) { + + if ( set_mdci_fapl ) { + + if ( read_only ) { + + if ( ( image_ctl.version != + H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION ) || + ( image_ctl.generate_image != FALSE ) || + ( image_ctl.save_resize_status != FALSE ) || + ( image_ctl.entry_ageout != + H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE ) || + ( image_ctl.flags != H5C_CI__ALL_FLAGS ) ) { + + pass = FALSE; + failure_mssg = "Unexpected image_ctl values(1).\n"; + } + } else { + + if ( ( image_ctl.version != + H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION ) || + ( image_ctl.generate_image != TRUE ) || + ( image_ctl.save_resize_status != FALSE ) || + ( image_ctl.entry_ageout != + H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE ) || + ( image_ctl.flags != H5C_CI__ALL_FLAGS ) ) { + + pass = FALSE; + failure_mssg = "Unexpected image_ctl values(2).\n"; + } + } + } else { + + if ( ( image_ctl.version != + H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION ) || + ( image_ctl.generate_image != FALSE ) || + ( image_ctl.save_resize_status != FALSE ) || + ( image_ctl.entry_ageout != + H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE ) || + ( image_ctl.flags != H5C_CI__ALL_FLAGS ) ) { + + pass = FALSE; + failure_mssg = "Unexpected image_ctl values(3).\n"; + } + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + if ( ( pass ) && ( set_mdci_fapl ) ) { + + image_ctl.flags = cache_image_flags; + + if ( H5C_set_cache_image_config(file_ptr, cache_ptr, &image_ctl) < 0 ) { + + pass = FALSE; + failure_mssg = "error returned by H5C_set_cache_image_config()."; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + if ( pass ) { + + if ( cache_ptr->close_warning_received == TRUE ) { + + pass = FALSE; + failure_mssg = "Unexpected value of close_warning_received.\n"; + } + + if ( mdci_sbem_expected ) { + + if ( read_only ) { + + if ( ( cache_ptr->load_image != TRUE ) || + ( cache_ptr->delete_image != FALSE ) ) { + + pass = FALSE; + failure_mssg = "mdci sb extension message not present?\n"; + } + } else { + + if ( ( cache_ptr->load_image != TRUE ) || + ( cache_ptr->delete_image != TRUE ) ) { + + pass = FALSE; + failure_mssg = "mdci sb extension message not present?\n"; + } + } + } else { + + if ( ( cache_ptr->load_image == TRUE ) || + ( cache_ptr->delete_image == TRUE ) ) { + + pass = FALSE; + failure_mssg = "mdci sb extension message present?\n"; + } + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + if ( pass ) { + + *file_id_ptr = file_id; + *file_ptr_ptr = file_ptr; + *cache_ptr_ptr = cache_ptr; + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d -- exiting.\n", fcn_name, cp++); + + return; + +} /* open_hdf5_file() */ + + +/*------------------------------------------------------------------------- + * Function: attempt_swmr_open_hdf5_file() + * + * Purpose: If pass is true on entry, attempt to create or open the + * specified HDF5 file with SWMR, and also with cache image + * creation if requested. + * + * In all cases, the attempted open or create should fail. + * + * Do nothing if pass is FALSE on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 7/14/15 + * + *------------------------------------------------------------------------- + */ + +static void +attempt_swmr_open_hdf5_file(const hbool_t create_file, + const hbool_t set_mdci_fapl, + const char * hdf_file_name) +{ + const char * fcn_name = "attempt_swmr_open_hdf5_file()"; + hbool_t show_progress = FALSE; + int cp = 0; + hid_t fapl_id = -1; + hid_t file_id = -1; + herr_t result; + H5AC_cache_image_config_t cache_image_config = { + H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION, + TRUE, + FALSE, + H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE}; + + /* create a file access propertly list. */ + if ( pass ) { + + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + + if ( fapl_id < 0 ) { + + pass = FALSE; + failure_mssg = "H5Pcreate() failed.\n"; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* call H5Pset_libver_bounds() on the fapl_id */ + if ( pass ) { + + if ( H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) + < 0 ) { + + pass = FALSE; + failure_mssg = "H5Pset_libver_bounds() failed.\n"; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* set metadata cache image fapl entry if indicated */ + if ( ( pass ) && ( set_mdci_fapl ) ) { + + /* set cache image config fields to taste */ + cache_image_config.generate_image = TRUE; + cache_image_config.save_resize_status = FALSE; + cache_image_config.entry_ageout = H5AC__CACHE_IMAGE__ENTRY_AGEOUT__NONE; + + result = H5Pset_mdc_image_config(fapl_id, &cache_image_config); + + if ( result < 0 ) { + + pass = FALSE; + failure_mssg = "H5Pset_mdc_image_config() failed.\n"; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* open the file */ + if ( pass ) { + + if ( create_file ) { + + H5E_BEGIN_TRY { + file_id = H5Fcreate(hdf_file_name, H5F_ACC_TRUNC | H5F_ACC_SWMR_WRITE, + H5P_DEFAULT, fapl_id); + } H5E_END_TRY; + } else { + + H5E_BEGIN_TRY { + file_id = H5Fopen(hdf_file_name, H5F_ACC_RDWR | H5F_ACC_SWMR_WRITE, fapl_id); + } H5E_END_TRY; + } + + if ( file_id >= 0 ) { + + pass = FALSE; + failure_mssg = "SWMR H5Fcreate() or H5Fopen() succeeded.\n"; + + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + return; + +} /* attempt_swmr_open_hdf5_file() */ + + +/*------------------------------------------------------------------------- + * Function: verify_datasets() + * + * Purpose: If pass is TRUE on entry, verify that the datasets in the + * file exist and contain the expected data. + * + * Note that these datasets were created by + * create_datasets() above. Thus any changes in that + * function must be reflected in this function, and + * vise-versa. + * + * On failure, set pass to FALSE, and set failure_mssg + * to point to an appropriate failure message. + * + * Do nothing if pass is FALSE on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 7/15/15 + * + *------------------------------------------------------------------------- + */ + +static void +verify_datasets(hid_t file_id, int min_dset, int max_dset) +{ + const char * fcn_name = "verify_datasets()"; + char dset_name[64]; + hbool_t show_progress = FALSE; + hbool_t valid_chunk; + hbool_t verbose = FALSE; + int cp = 0; + int i, j, k, l, m; + int data_chunk[CHUNK_SIZE][CHUNK_SIZE]; + herr_t status; + hid_t filespace_ids[MAX_NUM_DSETS]; + hid_t memspace_id = -1; + hid_t dataset_ids[MAX_NUM_DSETS]; + hsize_t dims[2]; + hsize_t a_size[2]; + hsize_t offset[2]; + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + HDassert(0 <= min_dset); + HDassert(min_dset <= max_dset); + HDassert(max_dset < MAX_NUM_DSETS); + + /* open the datasets */ + + if ( pass ) { + + i = min_dset; + + while ( ( pass ) && ( i <= max_dset ) ) + { + /* open the dataset */ + if ( pass ) { + + sprintf(dset_name, "/dset%03d", i); + dataset_ids[i] = H5Dopen2(file_id, dset_name, H5P_DEFAULT); + + if ( dataset_ids[i] < 0 ) { + + pass = FALSE; + failure_mssg = "H5Dopen2() failed."; + } + } + + /* get the file space ID */ + if ( pass ) { + + filespace_ids[i] = H5Dget_space(dataset_ids[i]); + + if ( filespace_ids[i] < 0 ) { + + pass = FALSE; + failure_mssg = "H5Dget_space() failed."; + } + } + + i++; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* create the mem space to be used to read and write chunks */ + if ( pass ) { + + dims[0] = CHUNK_SIZE; + dims[1] = CHUNK_SIZE; + memspace_id = H5Screate_simple(2, dims, NULL); + + if ( memspace_id < 0 ) { + + pass = FALSE; + failure_mssg = "H5Screate_simple() failed."; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* select in memory hyperslab */ + if ( pass ) { + + offset[0] = 0; /*offset of hyperslab in memory*/ + offset[1] = 0; + a_size[0] = CHUNK_SIZE; /*size of hyperslab*/ + a_size[1] = CHUNK_SIZE; + status = H5Sselect_hyperslab(memspace_id, H5S_SELECT_SET, offset, NULL, + a_size, NULL); + + if ( status < 0 ) { + + pass = FALSE; + failure_mssg = "H5Sselect_hyperslab() failed."; + } + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + + /* read data from datasets and validate it */ + i = 0; + while ( ( pass ) && ( i < DSET_SIZE ) ) + { + j = 0; + while ( ( pass ) && ( j < DSET_SIZE ) ) + { + m = min_dset; + while ( ( pass ) && ( m <= max_dset ) ) + { + + /* select on disk hyperslab */ + offset[0] = (hsize_t)i; /* offset of hyperslab in file */ + offset[1] = (hsize_t)j; + a_size[0] = CHUNK_SIZE; /* size of hyperslab */ + a_size[1] = CHUNK_SIZE; + status = H5Sselect_hyperslab(filespace_ids[m], H5S_SELECT_SET, + offset, NULL, a_size, NULL); + + if ( status < 0 ) { + + pass = FALSE; + failure_mssg = "disk hyperslab create failed."; + } + + /* read the chunk from file */ + if ( pass ) { + + status = H5Dread(dataset_ids[m], H5T_NATIVE_INT, + memspace_id, filespace_ids[m], + H5P_DEFAULT, data_chunk); + + if ( status < 0 ) { + + pass = FALSE; + failure_mssg = "disk hyperslab create failed."; + } + } + + /* validate the slab */ + if ( pass ) { + + valid_chunk = TRUE; + for ( k = 0; k < CHUNK_SIZE; k++ ) + { + for ( l = 0; l < CHUNK_SIZE; l++ ) + { + if ( data_chunk[k][l] + != + ((DSET_SIZE * DSET_SIZE * m) + + (DSET_SIZE * (i + k)) + j + l) ) { + + valid_chunk = FALSE; + + if ( verbose ) { + + HDfprintf(stdout, + "data_chunk[%0d][%0d] = %0d, expect %0d.\n", + k, l, data_chunk[k][l], + ((DSET_SIZE * DSET_SIZE * m) + + (DSET_SIZE * (i + k)) + j + l)); + HDfprintf(stdout, + "m = %d, i = %d, j = %d, k = %d, l = %d\n", + m, i, j, k, l); + } + } + } + } + + if ( ! valid_chunk ) { + + pass = FALSE; + failure_mssg = "slab validation failed."; + + if ( verbose ) { + + fprintf(stdout, + "Chunk (%0d, %0d) in /dset%03d is invalid.\n", + i, j, m); + } + } + } + m++; + } + j += CHUNK_SIZE; + } + i += CHUNK_SIZE; + } + + if ( show_progress ) HDfprintf(stdout, "%s: cp = %d.\n", fcn_name, cp++); + + /* close the file spaces */ + i = min_dset; + while ( ( pass ) && ( i <= max_dset ) ) + { + if ( H5Sclose(filespace_ids[i]) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Sclose() failed."; + } + i++; + } + + + /* close the datasets */ + i = min_dset; + while ( ( pass ) && ( i <= max_dset ) ) + { + if ( H5Dclose(dataset_ids[i]) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Dclose() failed."; + } + i++; + } + + /* close the mem space */ + if ( pass ) { + + if ( H5Sclose(memspace_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Sclose(memspace_id) failed."; + } + } + + return; + +} /* verify_datasets() */ + + +/****************************************************************************/ +/******************************* Test Functions *****************************/ +/****************************************************************************/ + +/*------------------------------------------------------------------------- + * Function: check_cache_image_ctl_flow_1() + * + * Purpose: This test is one of a sequence of control flow tests intended + * to verify that control flow for the cache image feature works + * as expected. + * + * This test is an initial smoke check, so the sequence of + * operations is relatively simple. In particular, we are + * testing: + * + * i) Creation of file with cache image FAPL entry set + * and insertion of metadata cache image superblock + * message on file close. + * + * ii) Open of file with metadata cache image superblock + * message, transmission of message to metadata cache, + * and deletion of superblock message prior to close. + * + * Note that in all cases we are performing operations on the + * file. While this is the typical case, we must repeat this + * test without operations on the file. + * + * 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + * + * 2) Create some datasets in the file. + * + * 3) Close the file. + * + * 4) Open the file. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * 5) Open a dataset. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + * + * 6) Close the file. + * + * 7) Open the file. + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + * + * 8) Close the file. + * + * 9) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 7/15/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +check_cache_image_ctl_flow_1(void) +{ + const char * fcn_name = "check_cache_image_ctl_flow_1()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image control flow test 1"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing creation of metadata cache image super block + * extension message only. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__GEN_MDCI_SBE_MESG, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Create some datasets in the file. */ + + if ( pass ) { + + create_datasets(file_id, 0, 5); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Open the file. + * + * Verify that the metadata cache is instructed to load the + * metadata cache image, and that the supplied address and length + * are HADDR_UNDEF and zero respectively. Note that these values + * indicate that the metadata image block doesn't exist. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Open and close a dataset. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + + if ( pass ) { + + /* think on how to verify that the superblock extension has been + * deleted, and if it is necessary to verify this directly. + */ + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Open the file. + * + * Verify that the file doesn't contain a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 8) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Delete the file */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* check_cache_image_ctl_flow_1() */ + + +/*------------------------------------------------------------------------- + * Function: check_cache_image_ctl_flow_2() + * + * Purpose: This test is one of a sequence of control flow tests intended + * to verify that control flow for the cache image feature works + * as expected. + * + * This test is an initial smoke check, so the sequence of + * operations is relatively simple. In particular, we are + * testing: + * + * i) Creation of file with cache image FAPL entry set + * and insertion of metadata cache image superblock + * message on file close. + * + * ii) Open of file with metadata cache image superblock + * message, transmission of message to metadata cache, + * and deletion of superblock message prior to close. + * + * Note that unlike the previous test, no operations are performed + * on the file. As a result of this, the metadata cache image + * message is not processed until the metadata cache receives + * the file close warning. (Under normal circumstances, it is + * processed as part of the first protect operation after the + * superblock is loaded.) + * + * In this particular test, we preform the following operations: + * + * 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + * + * 2) Close the file. + * + * 3) Open the file. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * 6) Close the file. + * + * 7) Open the file. + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + * + * 8) Close the file. + * + * 9) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 7/15/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +check_cache_image_ctl_flow_2(void) +{ + const char * fcn_name = "check_cache_image_ctl_flow_2()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image control flow test 2"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing creation of metadata cache image super block + * extension message only. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__GEN_MDCI_SBE_MESG, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Open the file. + * + * Verify that the metadata cache is instructed to load the + * metadata cache image, and that the supplied address and length + * are HADDR_UNDEF and zero respectively. Note that these values + * indicate that the metadata image block doesn't exist. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Open the file. + * + * Verify that the file doesn't contain a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Delete the file */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* check_cache_image_ctl_flow_2() */ + + +/*------------------------------------------------------------------------- + * Function: check_cache_image_ctl_flow_3() + * + * Purpose: This test is one of a sequence of control flow tests intended + * to verify that control flow for the cache image feature works + * as expected. + * + * The objectives of this test are to: + * + * i) Test operation of the metadata cache image FAPL + * entry set on open of an existing file. This + * should result in the insertion of a metadata + * cache image superblock message on file close. + * + * ii) Test operation of the metadata cache image super + * block extension message when it appears in a file + * that is opened READ ONLY. + * + * Note that in all cases we are performing operations on the + * file between file open and close. While this is the + * typical case, we must repeat this test without operations + * on the file. + * + * 1) Create a HDF5 file WITHOUT the cache image FAPL entry. + * + * Verify that the cache is NOT informed of the cache image + * FAPL entry. + * + * 2) Close the file. + * + * 3) Open the file WITH the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + * + * 4) Create some datasets. + * + * 5) Close the file. + * + * 6) Open the file READ ONLY. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * 7) Verify the contents of the datasets. + * + * 8) Close the file. + * + * 9) Open the file READ/WRITE. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * 10) Verify the contents of the datasets. + * + * 11) Close the file. + * + * 12) Open the file + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + * + * 13) Close the file. + * + * 14) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 7/16/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +check_cache_image_ctl_flow_3(void) +{ + const char * fcn_name = "check_cache_image_ctl_flow_3()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image control flow test 3"); + + pass = TRUE; + + if ( show_progress ) /* 0 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) /* 1 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* 1) Create a HDF5 file WITHOUT the cache image FAPL entry. + * + * Verify that the cache is NOT informed of the cache image + * FAPL entry. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 2 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 3 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Open the file WITH the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing creation of metadata cache image super block + * extension message only. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__GEN_MDCI_SBE_MESG, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 4 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Create some datasets. */ + + if ( pass ) { + + create_datasets(file_id, 0, 5); + } + + if ( show_progress ) /* 5 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 6 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Open the file READ ONLY. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ TRUE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 7 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Verify the contents of the datasets. */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + + if ( show_progress ) /* 8 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 8) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 9 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Open the file READ/WRITE. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 10 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 10) Verify the contents of the datasets. */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + + if ( show_progress ) /* 11 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 11) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 12 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 12) Open the file + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 13 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 13) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 14 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 14) Delete the file. */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* check_cache_image_ctl_flow_3() */ + + +/*------------------------------------------------------------------------- + * Function: check_cache_image_ctl_flow_4() + * + * Purpose: This test is one of a sequence of control flow tests intended + * to verify that control flow for the cache image feature works + * as expected. + * + * The objectives of this test are to: + * + * i) Test operation of the metadata cache image FAPL + * entry set on open of an existing file. This + * should result in the insertion of a metadata + * cache image superblock message on file close. + * + * ii) Test operation of the metadata cache image super + * block extension message when it appears in a file + * that is opened READ ONLY. + * + * In this test we avoid all file access beyond file open + * and close. + * + * 1) Create a HDF5 file WITHOUT the cache image FAPL entry. + * + * Verify that the cache is NOT informed of the cache image + * FAPL entry. + * + * 2) Close the file. + * + * 3) Open the file WITH the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + * + * 4) Close the file. + * + * 5) Open the file READ ONLY. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * 6) Close the file. + * + * 7) Open the file READ/WRITE. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * 8) Close the file. + * + * 9) Open the file + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + * + * 10) Close the file. + * + * 11) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 7/16/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +check_cache_image_ctl_flow_4(void) +{ + const char * fcn_name = "check_cache_image_ctl_flow_4()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image control flow test 4"); + + pass = TRUE; + + if ( show_progress ) /* 0 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) /* 1 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* 1) Create a HDF5 file WITHOUT the cache image FAPL entry. + * + * Verify that the cache is NOT informed of the cache image + * FAPL entry. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 2 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 3 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Open the file WITH the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing creation of metadata cache image super block + * extension message only. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__GEN_MDCI_SBE_MESG, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 4 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 5 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Open the file READ ONLY. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ TRUE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 6 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 7 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Open the file READ/WRITE. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 8 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 8) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 9 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Open the file + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 10 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 10) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 11 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 11) Delete the file. */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* check_cache_image_ctl_flow_4() */ + + +/*------------------------------------------------------------------------- + * Function: check_cache_image_ctl_flow_5() + * + * Purpose: This test is one of a sequence of control flow tests intended + * to verify that control flow for the cache image feature works + * as expected. + * + * The objective of this test is verify correct control flow + * when a file with a metadata cache image superblock extension + * message is opened with the metadata cache image FAPL entry. + * + * Note that in all cases we are performing operations on the + * file between file open and close. While this is the + * typical case, we must repeat this test without operations + * on the file. + * + * 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + * + * 2) Create some datasets. + * + * 3) Close the file. + * + * 4) Open the file WITH the cache image FAPL entry. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + * + * 5) Verify the contents of the datasets. + * + * 6) Close the file. + * + * 7) Open the file. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * 8) Verify the contents of the datasets. + * + * 9) Close the file. + * + * 10) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 7/17/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +check_cache_image_ctl_flow_5(void) +{ + const char * fcn_name = "check_cache_image_ctl_flow_5()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image control flow test 5"); + + pass = TRUE; + + if ( show_progress ) /* 0 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) /* 1 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__GEN_MDCI_SBE_MESG, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 2 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Create some datasets. */ + + if ( pass ) { + + create_datasets(file_id, 0, 5); + } + + if ( show_progress ) /* 3 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 4 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Open the file WITH the cache image FAPL entry. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__GEN_MDCI_SBE_MESG, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 5 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* 5) Verify the contents of the datasets. */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + + if ( show_progress ) /* 6 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 7 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Open the file. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 8 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* 8) Verify the contents of the datasets. */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + + if ( show_progress ) /* 9 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 10 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 10) Delete the file. */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* check_cache_image_ctl_flow_5() */ + + +/*------------------------------------------------------------------------- + * Function: check_cache_image_ctl_flow_6() + * + * Purpose: This test is one of a sequence of control flow tests intended + * to verify that control flow for the cache image feature works + * as expected. + * + * The objective of this test is verify correct control flow + * when a file with a metadata cache image superblock extension + * message is opened with the metadata cache image FAPL entry. + * + * In this test we avoid all file activity other than open + * and close. + * + * 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + * + * 2) Close the file. + * + * 3) Open the file WITH the cache image FAPL entry. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + * + * 4) Close the file. + * + * 5) Open the file. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * 6) Close the file. + * + * 7) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 7/17/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +check_cache_image_ctl_flow_6(void) +{ + const char * fcn_name = "check_cache_image_ctl_flow_6()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image control flow test 6"); + + pass = TRUE; + + if ( show_progress ) /* 0 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) /* 1 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__GEN_MDCI_SBE_MESG, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 2 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 3 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Open the file WITH the cache image FAPL entry. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set flags forcing creation of metadata cache image + * super block extension message only. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__GEN_MDCI_SBE_MESG, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 4 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 5 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Open the file. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image, and that the + * supplied address and length are HADDR_UNDEF and + * zero respectively. Note that these values indicate + * that the metadata image block doesn't exist. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) /* 6 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) /* 7 */ + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Delete the file. */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* check_cache_image_ctl_flow_6() */ + + +/*------------------------------------------------------------------------- + * Function: cache_image_smoke_check_1() + * + * Purpose: This test is one of a sequence of tests intended + * to exercise the cache image feature verifying that it + * works more or less correctly in common cases. + * + * This test is an initial smoke check, so the sequence of + * operations is relatively simple. In particular, we are + * testing: + * + * i) Creation of file with metadata cache image + * superblock extension message and cache image + * block. + * + * ii) Open of file with metadata cache image superblock + * extension message and cache image block. + * Deserialization and removal of both, insertion + * of prefetched cache entries, and deserialization + * of prefetched cache entries as they are protected. + * + * iii) Subsequent write of file without metadata cache + * image. + * + * iv) Open and close of file with metadata cache image + * image requested, but with no operations on the + * file. + * + * To do this: + * + * 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set all cache image flags, forcing full functionality. + * + * 2) Create some datasets in the file. + * + * 3) Close the file. + * + * 4) Open the file. + * + * Verify that the metadata cache is instructed + * to load the metadata cache image. + * + * 5) Open a dataset. + * + * Verify that it contains the expected data + * + * 6) Close the file. + * + * 7) Open the file. + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + * + * 8) Open a dataset. + * + * Verify that it contains the expected data. + * + * 9) Close the file. + * + * 10) Open the file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set all cache image flags, forcing full functionality. + * + * 11) Close the file. Since there has been no access to + * any entries that would be included in the cache image, + * there should be no cache image. + * + * 12) Open the file. + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + * + * 13) Open a dataset. + * + * Verify that it contains the expected data. + * + * 14) Close the file. + * + * 15) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 8/17/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +cache_image_smoke_check_1(void) +{ + const char * fcn_name = "cache_image_smoke_check_1()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image smoke check 1"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing full function of the cache image feature. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Create some datasets in the file. */ + + if ( pass ) { + + create_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Open the file. + * + * Verify that the metadata cache is instructed to load the + * metadata cache image, and that the supplied address and length + * are HADDR_UNDEF and zero respectively. Note that these values + * indicate that the metadata image block doesn't exist. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Open and close a dataset. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 1 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block not loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Open the file. + * + * Verify that the file doesn't contain a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 8) Open and close a dataset. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 10) Open the file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 11) Close the file. Since there has been no access to + * any entries that would be included in the cache image, + * there should be no cache image. + */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 12) Open the file. + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 13) Open a dataset. + * + * Verify that it contains the expected data. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(3)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 14) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 15) Delete the file */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* cache_image_smoke_check_1() */ + + +/*------------------------------------------------------------------------- + * Function: cache_image_smoke_check_2() + * + * Purpose: This test is one of a sequence of tests intended + * to exercise the cache image feature verifying that it + * works more or less correctly in common cases. + * + * This test is an initial smoke check, so the sequence of + * operations is relatively simple. In particular, we are + * testing: + * + * i) Creation of file with metadata cache image + * superblock extension message and cache image + * block. + * + * ii) Open of file with metadata cache image superblock + * extension message and cache image block. Write + * of prefetched entries to file on file close. + * + * To do this: + * + * 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set all cache image flags, forcing full functionality. + * + * 2) Create some datasets in the file. + * + * 3) Close the file. + * + * 4) Open the file. + * + * 5) Close the file. + * + * 6) Open the file. + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + * + * 7) Open a dataset. + * + * Verify that it contains the expected data. + * + * 8) Close the file. + * + * 9) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 8/18/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +cache_image_smoke_check_2(void) +{ + const char * fcn_name = "cache_image_smoke_check_2()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image smoke check 2"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing full function of the cache image feature. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ TRUE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Create some datasets in the file. */ + + if ( pass ) { + + create_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Open the file. + * + * Verify that the metadata cache is instructed to load the + * metadata cache image. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + /* can't verify that metadata cache image has been loaded directly, + * as in this cache, the load will not happen until close, and thus + * the images_created stat will not be readily available as it is + * incremented just before the cache is shut down. + */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Open the file. + * + * Verify that the file doesn't contain a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Open and close a dataset. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 8) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Delete the file */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* cache_image_smoke_check_2() */ + + +/*------------------------------------------------------------------------- + * Function: cache_image_smoke_check_3() + * + * Purpose: This test is one of a sequence of tests intended + * to exercise the cache image feature verifying that it + * works more or less correctly in common cases. + * + * This test is an initial smoke check, so the sequence of + * operations is relatively simple. In particular, we are + * testing: + * + * i) Creation of file with metadata cache image + * superblock extension message and cache image + * block. + * + * ii) Read only open and close of file with metadata + * cache image superblock extension message and + * cache image block. + * + * iii) Subsequent R/W open and close of file with metadata + * cache image superblock extension message and + * cache image block. + * + * To do this: + * + * 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set all cache image flags, forcing full functionality. + * + * 2) Create some datasets in the file. + * + * 3) Close the file. + * + * 4) Open the file read only. + * + * Verify that the file contains a metadata cache + * image superblock extension message. + * + * 5 Open a dataset. + * + * Verify that it contains the expected data. + * + * 6) Close the file. + * + * 7) Open the file. + * + * Verify that the file contains a metadata cache + * image superblock extension message. + * + * 8 Open a dataset. + * + * Verify that it contains the expected data. + * + * 9) Close the file. + * + * 10) Open the file. + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + * + * 11) Open a dataset. + * + * Verify that it contains the expected data. + * + * 12) Close the file. + * + * 13) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 8/18/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +cache_image_smoke_check_3(void) +{ + const char * fcn_name = "cache_image_smoke_check_3()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image smoke check 3"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing full function of the cache image feature. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ TRUE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Create some datasets in the file. */ + + if ( pass ) { + + create_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Open the file read only. + * + * Verify that the metadata cache is instructed to load the + * metadata cache image. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ TRUE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Open and close a dataset. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded == 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block not loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Open the file. + * + * Verify that the file contains a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 8) Open and close a dataset. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded == 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block not loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + + /* 10) Open the file. + * + * Verify that the file doesn't contain a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 11) Open and close a dataset. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 12) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 13) Delete the file */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* cache_image_smoke_check_3() */ + + +/*------------------------------------------------------------------------- + * Function: cache_image_smoke_check_4() + * + * Purpose: This test attempts to mimic the typical "poor man's + * parallel use case in which the file is passed between + * processes, each of which open the file, write some data, + * close the file, and then pass control on to the next + * process. + * + * In this case, we only write one dataset per process. + * + * Cycle of operation + * + * 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set all cache image flags, forcing full functionality. + * + * 2) Create and write a dataset in the file. + * + * 3) Close the file. + * + * 4) Open the file with the cache image FAPL entry. + * + * Verify that the file contains a metadata cache + * image superblock extension message. + * + * 5 Create and write a new dataset + * + * 6) Close the file. + * + * If sufficient datasets have been created, continue to + * 7). Otherwise goto 4) + * + * 7) Open the file. + * + * Verify that the file contains a metadata cache + * image superblock extension message. + * + * 8) Open all datasets that have been created, and + * verify that they contain the expected data. + * + * 9) Close the file. + * + * 10) Open the file. + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + * + * 11) Open all datasets that have been created, and + * verify that they contain the expected data. + * + * Verify that it contains the expected data. + * + * 12) Close the file. + * + * 13) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 8/18/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +cache_image_smoke_check_4(void) +{ + const char * fcn_name = "cache_image_smoke_check_4()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + int min_dset = 0; + int max_dset = 0; + + TESTING("metadata cache image smoke check 4"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing full function of the cache image feature. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ TRUE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Create a dataset in the file. */ + + if ( pass ) { + + create_datasets(file_id, min_dset++, max_dset++); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + while ( ( pass ) && ( max_dset < MAX_NUM_DSETS ) ) + { + + /* 4) Open the file. + * + * Verify that the metadata cache is instructed to load the + * metadata cache image. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s:L1 cp = %d, max_dset = %d, pass = %d.\n", + fcn_name, cp, max_dset, pass); + + + /* 5) Create a dataset in the file. */ + + if ( pass ) { + + create_datasets(file_id, min_dset++, max_dset++); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded == 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block not loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s:L2 cp = %d, max_dset = %d, pass = %d.\n", + fcn_name, cp + 1, max_dset, pass); + + + /* 6) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s:L3 cp = %d, max_dset = %d, pass = %d.\n", + fcn_name, cp + 2, max_dset, pass); + } /* end while */ + cp += 3; + + + /* 7) Open the file. + * + * Verify that the file contains a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 8) Open and close all datasets. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, max_dset - 1); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded == 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block not loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + + /* 10) Open the file. + * + * Verify that the file doesn't contain a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 11) Open and close all datasets. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, max_dset - 1); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 12) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 13) Delete the file */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* cache_image_smoke_check_4() */ + + +/*------------------------------------------------------------------------- + * Function: cache_image_smoke_check_5() + * + * Purpose: This test attempts to mimic the typical "poor man's + * parallel use case in which the file is passed between + * processes, each of which open the file, write some data, + * close the file, and then pass control on to the next + * process. + * + * In this case, we create one group for each process, and + * populate it with a "zoo" of HDF5 objects selected to + * (ideally) exercise all HDF5 on disk data structures. + * + * Cycle of operation + * + * 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set all cache image flags, forcing full functionality. + * + * 2) Create a process specific group. + * + * 3) Construct a "zoo" in the above group, and validate it. + * + * 4) Close the file. + * + * 5) Open the file with the cache image FAPL entry. + * + * Verify that the file contains a metadata cache + * image superblock extension message. + * + * 6) Validate the "zoo" created in the previous file open. + * + * 7) Create a process specific group for this file open + * + * 8) Construct a "zoo" in the above group, and validate it. + * + * 9) Close the file. + * + * If sufficient zoos have been created, continue to + * 10). Otherwise goto 5) + * + * 10) Open the file. + * + * Verify that the file contains a metadata cache + * image superblock extension message. + * + * 11) Validate all the zoos. + * + * 12) Close the file. + * + * 13) Open the file. + * + * Verify that the file doesn't contain a metadata cache + * image superblock extension message. + * + * 14) Validate all the zoos. + * + * 15) Close the file. + * + * 16) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 9/15/15 + * + *------------------------------------------------------------------------- + */ + +#define MAX_NUM_GROUPS 128 + +static unsigned +cache_image_smoke_check_5(void) +{ + const char * fcn_name = "cache_image_smoke_check_5()"; + char filename[512]; + char process_group_name[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + hid_t proc_gid = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + int i; + int min_group = 0; + int max_group = 0; + + TESTING("metadata cache image smoke check 5"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing full function of the cache image feature. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ TRUE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Create a process specific group. */ + if ( pass ) { + + sprintf(process_group_name, "/process_%d", min_group); + + proc_gid = H5Gcreate2(file_id, process_group_name, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + + if ( proc_gid < 0 ) { + + pass = FALSE; + failure_mssg = "H5Gcreate2() failed (1).\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Construct a "zoo" in the above group, and validate it. */ + if ( pass ) + create_zoo(file_id, process_group_name, min_group); + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Close the file. */ + + if ( pass ) { + + if ( H5Gclose(proc_gid) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Gclose(proc_gid) failed. (1)"; + } + } + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + while ( ( pass ) && ( max_group < MAX_NUM_GROUPS ) ) + { + + /* 5) Open the file. + * + * Verify that the metadata cache is instructed to load the + * metadata cache image. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s:L1 cp = %d, max_group = %d, pass = %d.\n", + fcn_name, cp, max_group, pass); + + + /* 6) Validate the "zoo" created in the previous file open. */ + if ( pass ) + validate_zoo(file_id, process_group_name, max_group); + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded == 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block not loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s:L2 cp = %d, max_group = %d, pass = %d.\n", + fcn_name, cp + 1, max_group, pass); + + + /* 7) Create a process specific group for this file open */ + if ( pass ) { + + max_group++; + sprintf(process_group_name, "/process_%d", max_group); + + proc_gid = H5Gcreate2(file_id, process_group_name, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + + if ( proc_gid < 0 ) { + + pass = FALSE; + failure_mssg = "H5Gcreate2() failed (2).\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s:L3 cp = %d, max_group = %d, pass = %d.\n", + fcn_name, cp + 2, max_group, pass); + + + /* 8) Construct a "zoo" in the above group, and validate it. */ + if ( pass ) + create_zoo(file_id, process_group_name, max_group); + + if ( show_progress ) + HDfprintf(stdout, "%s:L4 cp = %d, max_group = %d, pass = %d.\n", + fcn_name, cp + 3, max_group, pass); + + + /* 9) Close the file. */ + + if ( pass ) { + + if ( H5Gclose(proc_gid) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Gclose(process_gid) failed. (2)"; + } + } + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s:L5 cp = %d, max_group = %d, pass = %d.\n", + fcn_name, cp + 4, max_group, pass); + } /* end while */ + cp += 5; + + + + /* 10) Open the file. + * + * Verify that the file contains a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 11) Validate all the zoos. */ + i = min_group; + while ( ( pass ) && ( i <= max_group ) ) { + + sprintf(process_group_name, "/process_%d", i); + validate_zoo(file_id, process_group_name, i++); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded == 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block not loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 12) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + + /* 13) Open the file. + * + * Verify that the file doesn't contain a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 14) Validate all the zoos. + * + * Verify that the metadata cache image superblock + * extension message has been deleted. + */ + i = min_group; + while ( ( pass ) && ( i <= max_group ) ) { + + sprintf(process_group_name, "/process_%d", i); + validate_zoo(file_id, process_group_name, i++); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 15) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 16) Delete the file */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* cache_image_smoke_check_5() */ + + +/*------------------------------------------------------------------------- + * Function: cache_image_smoke_check_6() + * + * Purpose: As the free space manager metadata is now included in the + * cache image, a smoke check to verify generally correct + * behaviour of the persistent free space managers seems + * prudent. + * + * The basic idea of this test is to construct a long + * sequence of dataset creations and deletions, all separated + * by file open/close cycles with cache image enabled. If the + * perisistant free space managers are performing as expected, + * the size of the file should stabilize. + * + * To implement this, proceed as outlined in the cycle of + * operation below: + * + * Cycle of operation + * + * 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image + * FAPL entry. + * + * Set all cache image flags, forcing full functionality. + * + * 2) Create and write a dataset in the file. + * + * 3) Close the file. + * + * 4) Open the file with the cache image FAPL entry. + * + * Verify that the file contains a metadata cache + * image superblock extension message. + * + * 5) Create and write a new dataset. + * + * 6) Verify and delete the old dataset. + * + * 7) Close the file. + * + * If sufficient datasets have been created, and then + * deleteded continue to 8). Otherwise goto 4) + * + * 8) Open the file. + * + * Verify that the file contains a metadata cache + * image superblock extension message. + * + * 9) Verify the last dataset created. + * + * 10) Close the file. + * + * 11) Open the file. + * + * 12) Verify and delete the last dataset. + * + * Verify that a metadata cache image is not loaded. + * + * 13) Close the file. + * + * 14) Get the size of the file. Verify that it is less + * than 1 KB. Without deletions and persistant free + * space managers, size size is about 167 MB, so this + * is sufficient to verify that the persistant free + * space managers are more or less doing their job. + * + * 15) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 10/31/16 + * + *------------------------------------------------------------------------- + */ + +static unsigned +cache_image_smoke_check_6(void) +{ + const char * fcn_name = "cache_image_smoke_check_6()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + h5_stat_size_t file_size; + int cp = 0; + int min_dset = 0; + int max_dset = 0; + + TESTING("metadata cache image smoke check 6"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with the cache image FAPL entry. + * + * Verify that the cache is informed of the cache image FAPL entry. + * + * Set flags forcing full function of the cache image feature. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ TRUE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Create a dataset in the file. */ + + if ( pass ) { + + create_datasets(file_id, min_dset++, max_dset++); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + while ( ( pass ) && ( max_dset < MAX_NUM_DSETS ) ) + { + + /* 4) Open the file. + * + * Verify that the metadata cache is instructed to load the + * metadata cache image. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s:L1 cp = %d, max_dset = %d, pass = %d.\n", + fcn_name, cp, max_dset, pass); + + + /* 5) Create a dataset in the file. */ + + if ( pass ) { + + create_datasets(file_id, min_dset++, max_dset++); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded == 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block not loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s:L2 cp = %d, max_dset = %d, pass = %d.\n", + fcn_name, cp + 1, max_dset, pass); + + + /* 6) Verify and delete the old dataset. */ + if ( pass ) { + + delete_datasets(file_id, min_dset - 2, max_dset - 2); + } + + if ( show_progress ) + HDfprintf(stdout, "%s:L3 cp = %d, max_dset = %d, pass = %d.\n", + fcn_name, cp + 2, max_dset, pass); + + + /* 7) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s:L4 cp = %d, max_dset = %d, pass = %d.\n", + fcn_name, cp + 3, max_dset, pass); + } /* end while */ + cp += 4; + + + /* 8) Open the file. + * + * Verify that the file contains a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Verify the last dataset created. */ + + if ( pass ) { + + verify_datasets(file_id, min_dset - 1, max_dset - 1); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded == 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block not loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 10) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + + /* 11) Open the file. + * + * Verify that the file doesn't contain a metadata cache image + * superblock extension message. + */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 12) Verify and delete the last dataset. + * + * Verify that a metadata cache image is not loaded. + */ + + if ( pass ) { + + delete_datasets(file_id, min_dset - 1, max_dset - 1); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + + /* 13) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 14) Get the size of the file. Verify that it is less + * than 1 KB. Without deletions and persistant free + * space managers, size size is about 167 MB, so this + * is sufficient to verify that the persistant free + * space managers are more or less doing their job. + */ + if((file_size = h5_get_file_size(filename, H5P_DEFAULT)) < 0) { + + pass = FALSE; + failure_mssg = "h5_get_file_size() failed.\n"; + + } else if ( file_size > 1024 ) { + + pass = FALSE; + failure_mssg = "unexpectedly large file size.\n"; + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 15) Delete the file */ + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* cache_image_smoke_check_6() */ + + +/*------------------------------------------------------------------------- + * Function: cache_image_api_error_check_1() + * + * Purpose: This test is one of a sequence of tests intended + * to verify correct management of API errors. + * + * The object of this test is to verify that a file without + * a pre-existing cache image that is opened both read only + * and with a cache image requested is handle correctly + * (the cache image request should be ignored silently). + * + * The test is set up as follows: + * + * 1) Create a HDF5 file. + * + * 2) Create some datasets in the file. + * + * 3) Close the file. + * + * 4) Open the file read only with a cache image FAPL entry + * requested. + * + * 5) Open a dataset. + * + * Verify that it contains the expected data + * + * Verify that the cache image was not loaded. + * + * 6) Close the file. + * + * 7) Open the file read only. + * + * 8) Open a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was not loaded. + * + * 9) Close the file. + * + * 10) Open the file read write. + * + * 11) Open a dataset. + * + * Verify that it contains the expected data. + * + * 12) Close the file. + * + * 13) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 9/25/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +cache_image_api_error_check_1(void) +{ + const char * fcn_name = "cache_image_api_error_check_1()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image api error check 1"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ TRUE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Create some datasets in the file. */ + + if ( pass ) { + + create_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Open the file read only with a cache image FAPL entry requested. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ TRUE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Open and close a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was not loaded. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Open the file read only. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ TRUE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 8) Open and close a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was not loaded. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(3)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 10) Open the file read / write. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* 11) Open and close a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was not loaded. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(4)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 12) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 13) Delete the file */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* cache_image_api_error_check_1() */ + + +/*------------------------------------------------------------------------- + * Function: cache_image_api_error_check_2() + * + * Purpose: This test is one of a sequence of tests intended + * to verify correct management of API errors. + * + * The object of this test is to verify that a file with + * a pre-existing cache image that is opened both read only + * and with a cache image requested is handled correctly + * (the cache image request should be ignored silently). + * + * The test is set up as follows: + * + * 1) Create a HDF5 file with a cache image requested.. + * + * 2) Create some datasets in the file. + * + * 3) Close the file. + * + * 4) Open the file read only with a cache image FAPL entry + * requested. + * + * 5) Open a dataset. + * + * Verify that it contains the expected data + * + * Verify that the cache image was loaded. + * + * 6) Close the file. + * + * 7) Open the file read only. + * + * 8) Open a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was loaded. + * + * 9) Close the file. + * + * 10) Open the file read write. + * + * 11) Open a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was loaded. + * + * 12) Close the file. + * + * 13) Open the file read write. + * + * 14) Open a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was NOT loaded. + * + * 15) Close the file. + * + * 16) Delete the file. + * + * Return: void + * + * Programmer: John Mainzer + * 9/25/15 + * + *------------------------------------------------------------------------- + */ + +static unsigned +cache_image_api_error_check_2(void) +{ + const char * fcn_name = "cache_image_api_error_check_2()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image api error check 2"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with a cache image requested. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ TRUE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Create some datasets in the file. */ + + if ( pass ) { + + create_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Open the file read only with a cache image FAPL entry requested. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ TRUE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Open and close a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was loaded. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 1 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block was not loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Open the file read only. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ TRUE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ 0, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 8) Open and close a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was loaded. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 1 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block was not loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 10) Open the file read / write. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ TRUE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* 11) Open and close a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was loaded. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 1 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block was not loaded(3)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 12) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 13) Open the file read / write. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ FALSE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ FALSE, + /* config_fsm */ FALSE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + /* 14) Open and close a dataset. + * + * Verify that it contains the expected data. + * + * Verify that the cache image was not loaded. + */ + + if ( pass ) { + + verify_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block was loaded(2)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 15) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 13) Delete the file */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* cache_image_api_error_check_2() */ + + +/*------------------------------------------------------------------------- + * Function: cache_image_api_error_check_3() + * + * Purpose: This test is one of a sequence of tests intended + * to verify correct management of API errors. + * + * At present, SWMR and cache image may not be active + * at the same time. The purpose of this test is to + * verify that attempts to run SWMR and cache image + * at the same time will fail. + * + * The test is set up as follows: + * + * 1) Create a HDF5 file with a cache image requested.. + * + * 2) Try to start SWMR write -- should fail. + * + * 3) Discard the file if necessary + * + * 4) Attempt to create a HDF5 file with SWMR write + * access and cache image requested -- should fail. + * + * 5) Discard the file if necessary + * + * 6) Create a HDF5 file with a cache image requested. + * + * 7) Create some datasets in the file. + * + * 8) Close the file. + * + * 9) Attempt to open the file with SWMR write access -- + * should fail. + * + * 10) Discard the file if necessary. + * + * Return: void + * + * Programmer: John Mainzer + * 12/29/16 + * + *------------------------------------------------------------------------- + */ + +static unsigned +cache_image_api_error_check_3(void) +{ + const char * fcn_name = "cache_image_api_error_check_3()"; + char filename[512]; + hbool_t show_progress = FALSE; + hid_t file_id = -1; + H5F_t *file_ptr = NULL; + H5C_t *cache_ptr = NULL; + int cp = 0; + + TESTING("metadata cache image api error check 3"); + + pass = TRUE; + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* setup the file name */ + if ( pass ) { + + if ( h5_fixname(FILENAMES[0], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass = FALSE; + failure_mssg = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 1) Create a HDF5 file with a cache image requested. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ TRUE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 2) Try to start SWMR write -- should fail. */ + + if ( pass ) { + + H5E_BEGIN_TRY { + if ( H5Fstart_swmr_write(file_id) == SUCCEED ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(1)."; + } + } H5E_END_TRY; + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 3) Discard the file if necessary */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 4) Attempt to create a HDF5 file with SWMR write + * access and cache image requested -- should fail. + */ + + attempt_swmr_open_hdf5_file(/* create_file */ TRUE, + /* set_mdci_fapl */ TRUE, + /* hdf_file_name */ filename); + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 5) Discard the file if necessary */ + + if ( pass ) { + + /* file probably doesn't exist, so don't + * error check the remove call. + */ + HDremove(filename); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 6) Create a HDF5 file with a cache image requested. */ + + if ( pass ) { + + open_hdf5_file(/* create_file */ TRUE, + /* mdci_sbem_expected */ FALSE, + /* read_only */ FALSE, + /* set_mdci_fapl */ TRUE, + /* config_fsm */ TRUE, + /* hdf_file_name */ filename, + /* cache_image_flags */ H5C_CI__ALL_FLAGS, + /* file_id_ptr */ &file_id, + /* file_ptr_ptr */ &file_ptr, + /* cache_ptr_ptr */ &cache_ptr); + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 7) Create some datasets in the file. */ + + if ( pass ) { + + create_datasets(file_id, 0, 5); + } + +#if H5C_COLLECT_CACHE_STATS + if ( pass ) { + + if ( cache_ptr->images_loaded != 0 ) { + + pass = FALSE; + failure_mssg = "metadata cache image block loaded(1)."; + } + } +#endif /* H5C_COLLECT_CACHE_STATS */ + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 8) Close the file. */ + + if ( pass ) { + + if ( H5Fclose(file_id) < 0 ) { + + pass = FALSE; + failure_mssg = "H5Fclose() failed.\n"; + + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 9) Attempt to open the file with SWMR write access -- should fail. */ + + attempt_swmr_open_hdf5_file(/* create_file */ FALSE, + /* set_mdci_fapl */ TRUE, + /* hdf_file_name */ filename); + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + /* 10) Discard the file if necessary. */ + + if ( pass ) { + + if ( HDremove(filename) < 0 ) { + + pass = FALSE; + failure_mssg = "HDremove() failed.\n"; + } + } + + if ( show_progress ) + HDfprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + + + if ( pass ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass ) + HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n", + FUNC, failure_mssg); + + return !pass; + +} /* cache_image_api_error_check_3() */ + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Run tests on the cache code contained in H5C.c + * + * Return: Success: + * + * Failure: + * + * Programmer: John Mainzer + * 6/24/04 + * + *------------------------------------------------------------------------- + */ +int +main(void) +{ + unsigned nerrs = 0; + int express_test; + + H5open(); + + express_test = GetTestExpress(); + + printf("=========================================\n"); + printf("Cache image tests\n"); + printf(" express_test = %d\n", express_test); + printf("=========================================\n"); + + nerrs += check_cache_image_ctl_flow_1(); + nerrs += check_cache_image_ctl_flow_2(); + nerrs += check_cache_image_ctl_flow_3(); + nerrs += check_cache_image_ctl_flow_4(); + nerrs += check_cache_image_ctl_flow_5(); + nerrs += check_cache_image_ctl_flow_6(); + + nerrs += cache_image_smoke_check_1(); + nerrs += cache_image_smoke_check_2(); + nerrs += cache_image_smoke_check_3(); + nerrs += cache_image_smoke_check_4(); + nerrs += cache_image_smoke_check_5(); + nerrs += cache_image_smoke_check_6(); + + nerrs += cache_image_api_error_check_1(); + nerrs += cache_image_api_error_check_2(); + nerrs += cache_image_api_error_check_3(); + + return(nerrs > 0); + +} /* main() */ + + diff --git a/test/genall5.c b/test/genall5.c new file mode 100644 index 0000000..1d92e96 --- /dev/null +++ b/test/genall5.c @@ -0,0 +1,3893 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Programmer: John Mainzer + * 9/23/15 + * + * This file contains a heavily edited and functionaly reduce + * version of the test code first written by Quincey in a file + * of the same name. + */ + +#include +#include +#include +#include +#include "hdf5.h" +#include "cache_common.h" +#include "genall5.h" + +#define DSET_DIMS (1024 * 1024) +#define DSET_SMALL_DIMS (64 * 1024) +#define DSET_CHUNK_DIMS 1024 +#define DSET_COMPACT_DIMS 4096 + + +/*------------------------------------------------------------------------- + * Function: ns_grp_0 + * + * Purpose: Create an empty "new style" group at the specified location + * in the specified file. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + +void +ns_grp_0(hid_t fid, const char *group_name) +{ + hid_t gid = -1; + hid_t gcpl = -1; + herr_t ret; + + if ( pass ) { + + gcpl = H5Pcreate(H5P_GROUP_CREATE); + + if ( gcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_0: H5Pcreate() failed"; + } + assert(gcpl > 0); + } + + if ( pass ) { + + ret = H5Pset_link_creation_order(gcpl, H5P_CRT_ORDER_TRACKED); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_0: H5Pset_link_creation_order() failed"; + } + assert(ret >= 0); + } + + if ( pass ) { + + gid = H5Gcreate2(fid, group_name, H5P_DEFAULT, gcpl, H5P_DEFAULT); + + if ( gid <= 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_0: H5Gcreate2() failed"; + } + assert(gid > 0); + } + + if ( pass ) { + + ret = H5Pclose(gcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_0: H5Pclose(gcpl) failed"; + } + assert(ret >= 0); + } + + if ( pass ) { + + ret = H5Gclose(gid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_0: H5Gclose(gid) failed"; + } + assert(ret >= 0); + } + + return; + +} /* ns_grp_0 */ + + +/*------------------------------------------------------------------------- + * Function: vrfy_ns_grp_0 + * + * Purpose: verify an empty "new style" group at the specified location + * in the specified file. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + +void vrfy_ns_grp_0(hid_t fid, const char *group_name) +{ + hid_t gid = -1; + hid_t gcpl = -1; + H5G_info_t grp_info; + unsigned crt_order_flags = 0; + herr_t ret; + + if ( pass ) { + + gid = H5Gopen2(fid, group_name, H5P_DEFAULT); + + if ( gid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_0: H5Gopen2() failed"; + } + HDassert(gid > 0); + } + + if ( pass ) { + + gcpl = H5Gget_create_plist(gid); + + if ( gcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_0: H5Gget_create_plist() failed"; + } + HDassert(gcpl > 0); + } + + if ( pass ) { + + ret = H5Pget_link_creation_order(gcpl, &crt_order_flags); + + if ( gcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_0: H5Pget_link_creation_order() failed"; + } + else if ( H5P_CRT_ORDER_TRACKED != crt_order_flags ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_0: H5P_CRT_ORDER_TRACKED != crt_order_flags"; + } + HDassert(ret >= 0); + HDassert(H5P_CRT_ORDER_TRACKED == crt_order_flags); + } + + if ( pass ) { + + ret = H5Pclose(gcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_0: H5Pclose() failed"; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + memset(&grp_info, 0, sizeof(grp_info)); + ret = H5Gget_info(gid, &grp_info); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_0: H5Gget_info() failed"; + } + else if ( H5G_STORAGE_TYPE_COMPACT != grp_info.storage_type ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_0: H5G_STORAGE_TYPE_COMPACT != grp_info.storage_type"; + } + else if ( 0 != grp_info.nlinks ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_0: 0 != grp_info.nlinks"; + } + else if ( 0 != grp_info.max_corder ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_0: 0 != grp_info.max_corder"; + } + else if ( FALSE != grp_info.mounted ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_0: FALSE != grp_info.mounted"; + } + + HDassert(ret >= 0); + HDassert(H5G_STORAGE_TYPE_COMPACT == grp_info.storage_type); + HDassert(0 == grp_info.nlinks); + HDassert(0 == grp_info.max_corder); + HDassert(false == grp_info.mounted); + } + + if ( pass ) { + + ret = H5Gclose(gid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_0: H5Gclose() failed"; + } + HDassert(ret >= 0); + } + + return; + +} /* vrfy_ns_grp_0() */ + + +/*------------------------------------------------------------------------- + * Function: ns_grp_c + * + * Purpose: Create a compact "new style" group, with 'nlinks' + * soft/hard/external links in it in the specified file. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + +void +ns_grp_c(hid_t fid, const char *group_name, unsigned nlinks) +{ + hid_t gid = -1; + hid_t gcpl = -1; + unsigned max_compact; + unsigned u; + herr_t ret; + + if ( pass ) { + + gcpl = H5Pcreate(H5P_GROUP_CREATE); + + if ( gcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: H5Pcreate(H5P_GROUP_CREATE) failed"; + } + HDassert(gcpl > 0); + } + + if ( pass ) { + + ret = H5Pset_link_creation_order(gcpl, H5P_CRT_ORDER_TRACKED); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: H5Pset_link_creation_order() failed"; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + gid = H5Gcreate2(fid, group_name, H5P_DEFAULT, gcpl, H5P_DEFAULT); + + if ( gid <= 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: H5Gcreate2() failed"; + } + HDassert(gid > 0); + } + + if ( pass ) { + + max_compact = 0; + ret = H5Pget_link_phase_change(gcpl, &max_compact, NULL); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: H5Pget_link_phase_change() failed"; + } + else if ( nlinks <= 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: nlinks <= 0"; + } + else if ( nlinks >= max_compact ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: nlinks >= max_compact"; + } + + HDassert(ret >= 0); + HDassert(nlinks > 0); + HDassert(nlinks < max_compact); + } + + u = 0; + while ( ( pass ) && ( u < nlinks ) ) { + + char linkname[16]; + + sprintf(linkname, "%u", u); + + if(0 == (u % 3)) { + + ret = H5Lcreate_soft(group_name, gid, linkname, H5P_DEFAULT, + H5P_DEFAULT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: H5Lcreate_soft() failed"; + } + HDassert(ret >= 0); + } /* end if */ + else if(1 == (u % 3)) { + + ret = H5Lcreate_hard(fid, "/", gid, linkname, H5P_DEFAULT, + H5P_DEFAULT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: H5Lcreate_hard() failed"; + } + HDassert(ret >= 0); + } /* end else-if */ + else { + + HDassert(2 == (u % 3)); + ret = H5Lcreate_external("external.h5", "/ext", gid, linkname, + H5P_DEFAULT, H5P_DEFAULT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: H5Lcreate_external() failed"; + } + HDassert(ret >= 0); + } /* end else */ + + u++; + + } /* end while() */ + + if ( pass ) { + + ret = H5Pclose(gcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: H5Pclose(gcpl) failed"; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Gclose(gid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_c: H5Gclose(gid) failed"; + } + HDassert(ret >= 0); + } + + return; + +} /* ns_grp_c() */ + + +/*------------------------------------------------------------------------- + * Function: vrfy_ns_grp_c + * + * Purpose: Verify a compact "new style" group, with 'nlinks' + * soft/hard/external links in it in the specified file. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + +void +vrfy_ns_grp_c(hid_t fid, const char *group_name, unsigned nlinks) +{ + hid_t gid = -1; + hid_t gcpl = -1; + H5G_info_t grp_info; + unsigned crt_order_flags = 0; + unsigned u; + herr_t ret; + + if ( pass ) { + + gid = H5Gopen2(fid, group_name, H5P_DEFAULT); + + if ( gid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Gopen2() failed"; + } + HDassert(gid > 0); + } + + if ( pass ) { + + gcpl = H5Gget_create_plist(gid); + + if ( gcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Gget_create_plist(gid) failed"; + } + assert(gcpl > 0); + } + + if ( pass ) { + + ret = H5Pget_link_creation_order(gcpl, &crt_order_flags); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Pget_link_creation_order() failed"; + } + else if ( H5P_CRT_ORDER_TRACKED != crt_order_flags ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_c: H5P_CRT_ORDER_TRACKED != crt_order_flags"; + } + HDassert(ret >= 0); + HDassert(H5P_CRT_ORDER_TRACKED == crt_order_flags); + } + + if ( pass ) { + + ret = H5Pclose(gcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Pclose() failed"; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + memset(&grp_info, 0, sizeof(grp_info)); + ret = H5Gget_info(gid, &grp_info); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Gget_info() failed"; + } + else if ( H5G_STORAGE_TYPE_COMPACT != grp_info.storage_type ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_c: H5G_STORAGE_TYPE_COMPACT != grp_info.storage_type"; + } + else if ( nlinks != grp_info.nlinks ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: nlinks != grp_info.nlinks"; + } + else if ( nlinks != grp_info.max_corder ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: nlinks != grp_info.max_corder"; + } + else if ( FALSE != grp_info.mounted ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: FALSE != grp_info.mounted"; + } + + HDassert(ret >= 0); + HDassert(H5G_STORAGE_TYPE_COMPACT == grp_info.storage_type); + HDassert(nlinks == grp_info.nlinks); + HDassert(nlinks == grp_info.max_corder); + HDassert(false == grp_info.mounted); + } + + u = 0; + while ( ( pass ) && ( u < nlinks ) ) { + + H5L_info_t lnk_info; + char linkname[16]; + htri_t link_exists; + + sprintf(linkname, "%u", u); + link_exists = H5Lexists(gid, linkname, H5P_DEFAULT); + + if ( link_exists < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Lexists() failed"; + } + HDassert(link_exists >= 0); + + memset(&lnk_info, 0, sizeof(grp_info)); + ret = H5Lget_info(gid, linkname, &lnk_info, H5P_DEFAULT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Lget_info() failed"; + } + else if ( TRUE != lnk_info.corder_valid ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: TRUE != lnk_info.corder_valid"; + } + else if ( u != lnk_info.corder ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: u != lnk_info.corder"; + } + else if ( H5T_CSET_ASCII != lnk_info.cset ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5T_CSET_ASCII != lnk_info.cset"; + } + HDassert(ret >= 0); + HDassert(true == lnk_info.corder_valid); + HDassert(u == lnk_info.corder); + HDassert(H5T_CSET_ASCII == lnk_info.cset); + + if ( 0 == (u % 3) ) { + + char *slinkval; + + if ( H5L_TYPE_SOFT != lnk_info.type ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5L_TYPE_SOFT != lnk_info.type"; + } + else if ( (strlen(group_name) + 1) != lnk_info.u.val_size ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_c: (strlen(group_name) + 1) != lnk_info.u.val_size"; + } + HDassert(H5L_TYPE_SOFT == lnk_info.type); + HDassert((strlen(group_name) + 1) == lnk_info.u.val_size); + + slinkval = (char *)malloc(lnk_info.u.val_size); + + if ( ! slinkval ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: malloc of slinkval failed"; + } + HDassert(slinkval); + + ret = H5Lget_val(gid, linkname, slinkval, lnk_info.u.val_size, + H5P_DEFAULT); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Lget_val() failed"; + } + else if ( 0 != strcmp(slinkval, group_name) ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_c: 0 != strcmp(slinkval, group_name)"; + } + HDassert(ret >= 0); + HDassert(0 == strcmp(slinkval, group_name)); + + free(slinkval); + } /* end if */ + else if(1 == (u % 3)) { + + H5O_info_t root_oinfo; + + if ( H5L_TYPE_HARD != lnk_info.type ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5L_TYPE_HARD != lnk_info.type"; + } + HDassert(H5L_TYPE_HARD == lnk_info.type); + + memset(&root_oinfo, 0, sizeof(root_oinfo)); + ret = H5Oget_info(fid, &root_oinfo); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Oget_info() failed."; + } + else if ( root_oinfo.addr != lnk_info.u.address ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_c: root_oinfo.addr != lnk_info.u.address"; + } + HDassert(ret >= 0); + HDassert(root_oinfo.addr == lnk_info.u.address); + } /* end else-if */ + else { + void *elinkval; + const char *file = NULL; + const char *path = NULL; + + HDassert(2 == (u % 3)); + + if ( H5L_TYPE_EXTERNAL != lnk_info.type ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_c: H5L_TYPE_EXTERNAL != lnk_info.type"; + } + HDassert(H5L_TYPE_EXTERNAL == lnk_info.type); + + elinkval = malloc(lnk_info.u.val_size); + + if ( ! elinkval ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: malloc of elinkval failed."; + } + HDassert(elinkval); + + ret = H5Lget_val(gid, linkname, elinkval, lnk_info.u.val_size, + H5P_DEFAULT); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Lget_val() failed."; + } + HDassert(ret >= 0); + + ret = H5Lunpack_elink_val(elinkval, lnk_info.u.val_size, + NULL, &file, &path); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Lunpack_elink_val() failed."; + } + else if ( 0 != strcmp(file, "external.h5") ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_c: 0 != strcmp(file, \"external.h5\")"; + } + else if ( 0 != strcmp(path, "/ext") ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: 0 != strcmp(path, \"/ext\")"; + } + HDassert(ret >= 0); + HDassert(0 == strcmp(file, "external.h5")); + HDassert(0 == strcmp(path, "/ext")); + + free(elinkval); + } /* end else */ + + u++; + + } /* end while */ + + if ( pass ) { + + ret = H5Gclose(gid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_c: H5Gclose() failed."; + } + assert(ret >= 0); + } + + return; + +} /* vrfy_ns_grp_c() */ + + +/*------------------------------------------------------------------------- + * Function: ns_grp_d + * + * Purpose: Create a dense "new style" group, with 'nlinks' + * (soft/hard/external) links in it in the specified file. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + +void +ns_grp_d(hid_t fid, const char *group_name, unsigned nlinks) +{ + hid_t gid = -1; + hid_t gcpl = -1; + unsigned max_compact; + unsigned u; + herr_t ret; + + if ( pass ) { + + gcpl = H5Pcreate(H5P_GROUP_CREATE); + + if ( gcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_d: H5Pcreate() failed."; + } + HDassert(gcpl > 0); + } + + if ( pass ) { + + ret = H5Pset_link_creation_order(gcpl, H5P_CRT_ORDER_TRACKED); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_d: H5Pset_link_creation_order() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + gid = H5Gcreate2(fid, group_name, H5P_DEFAULT, gcpl, H5P_DEFAULT); + + if ( gid <= 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_d: H5Gcreate2() failed."; + } + HDassert(gid > 0); + } + + if ( pass ) { + + max_compact = 0; + ret = H5Pget_link_phase_change(gcpl, &max_compact, NULL); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_d: H5Pget_link_phase_change() failed."; + } + else if ( nlinks <= max_compact ) { + + pass = FALSE; + failure_mssg = "ns_grp_d: nlinks <= max_compact"; + } + HDassert(ret >= 0); + HDassert(nlinks > max_compact); + } + + u = 0; + while ( ( pass ) && ( u < nlinks ) ) { + + char linkname[16]; + + sprintf(linkname, "%u", u); + + if(0 == (u % 3)) { + + ret = H5Lcreate_soft(group_name, gid, linkname, + H5P_DEFAULT, H5P_DEFAULT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_d: H5Lcreate_soft() failed."; + } + HDassert(ret >= 0); + } /* end if */ + else if(1 == (u % 3)) { + + ret = H5Lcreate_hard(fid, "/", gid, linkname, + H5P_DEFAULT, H5P_DEFAULT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_d: H5Lcreate_hard() failed."; + } + HDassert(ret >= 0); + } /* end else-if */ + else { + + HDassert(2 == (u % 3)); + + ret = H5Lcreate_external("external.h5", "/ext", gid, linkname, + H5P_DEFAULT, H5P_DEFAULT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_d: H5Lcreate_external() failed."; + } + HDassert(ret >= 0); + } /* end else */ + + u++; + + } /* end while */ + + if ( pass ) { + + ret = H5Pclose(gcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_d: H5Pclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Gclose(gid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ns_grp_d: H5Gclose() failed."; + } + HDassert(ret >= 0); + } + + return; + +} /* ns_grp_d() */ + + +/*------------------------------------------------------------------------- + * Function: vrfy_ns_grp_d + * + * Purpose: Verify a dense "new style" group, with 'nlinks' + * soft/hard/external links in it in the specified file. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + + +void +vrfy_ns_grp_d(hid_t fid, const char *group_name, unsigned nlinks) +{ + hid_t gid = -1; + hid_t gcpl = -1; + H5G_info_t grp_info; + unsigned crt_order_flags = 0; + unsigned u; + herr_t ret; + + if ( pass ) { + + gid = H5Gopen2(fid, group_name, H5P_DEFAULT); + + if ( gid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Gopen2() failed."; + } + HDassert(gid > 0); + } + + if ( pass ) { + + gcpl = H5Gget_create_plist(gid); + + if ( gcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Gget_create_plist() failed."; + } + assert(gcpl > 0); + } + + if ( pass ) { + + ret = H5Pget_link_creation_order(gcpl, &crt_order_flags); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_d: H5Pget_link_creation_order() failed."; + } + else if ( H5P_CRT_ORDER_TRACKED != crt_order_flags ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_d: H5P_CRT_ORDER_TRACKED != crt_order_flags"; + } + HDassert(ret >= 0); + HDassert(H5P_CRT_ORDER_TRACKED == crt_order_flags); + } + + if ( pass ) { + + ret = H5Pclose(gcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Pclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + memset(&grp_info, 0, sizeof(grp_info)); + ret = H5Gget_info(gid, &grp_info); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Gget_info() failed."; + } + else if ( H5G_STORAGE_TYPE_DENSE != grp_info.storage_type ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_d: H5G_STORAGE_TYPE_DENSE != grp_info.storage_type"; + } + else if ( nlinks != grp_info.nlinks ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: nlinks != grp_info.nlinks"; + } + else if ( nlinks != grp_info.max_corder ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: nlinks != grp_info.max_corder"; + } + else if ( FALSE != grp_info.mounted ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: FALSE != grp_info.mounted"; + } + HDassert(ret >= 0); + HDassert(H5G_STORAGE_TYPE_DENSE == grp_info.storage_type); + HDassert(nlinks == grp_info.nlinks); + HDassert(nlinks == grp_info.max_corder); + HDassert(false == grp_info.mounted); + } + + u = 0; + while ( ( pass ) && ( u < nlinks ) ) { + + H5L_info_t lnk_info; + char linkname[16]; + htri_t link_exists; + + sprintf(linkname, "%u", u); + link_exists = H5Lexists(gid, linkname, H5P_DEFAULT); + + if ( link_exists < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Lexists() failed."; + } + HDassert(link_exists >= 0); + + memset(&lnk_info, 0, sizeof(grp_info)); + ret = H5Lget_info(gid, linkname, &lnk_info, H5P_DEFAULT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Lget_info() failed."; + } + else if ( TRUE != lnk_info.corder_valid ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: TRUE != lnk_info.corder_valid"; + } + else if ( u != lnk_info.corder ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: u != lnk_info.corder"; + } + else if ( H5T_CSET_ASCII != lnk_info.cset ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5T_CSET_ASCII != lnk_info.cset"; + } + HDassert(ret >= 0); + HDassert(true == lnk_info.corder_valid); + HDassert(u == lnk_info.corder); + HDassert(H5T_CSET_ASCII == lnk_info.cset); + + if(0 == (u % 3)) { + char *slinkval; + + if ( H5L_TYPE_SOFT != lnk_info.type ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5L_TYPE_SOFT != lnk_info.type"; + } + else if ( (strlen(group_name) + 1) != lnk_info.u.val_size ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5L_TYPE_SOFT != lnk_info.type"; + } + HDassert(H5L_TYPE_SOFT == lnk_info.type); + HDassert((strlen(group_name) + 1) == lnk_info.u.val_size); + + slinkval = (char *)malloc(lnk_info.u.val_size); + + if ( ! slinkval ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: malloc of slinkval failed"; + } + HDassert(slinkval); + + ret = H5Lget_val(gid, linkname, slinkval, lnk_info.u.val_size, + H5P_DEFAULT); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Lget_val() failed"; + } + else if ( 0 != strcmp(slinkval, group_name) ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_d: 0 != strcmp(slinkval, group_name)"; + } + HDassert(ret >= 0); + HDassert(0 == strcmp(slinkval, group_name)); + + free(slinkval); + } /* end if */ + else if(1 == (u % 3)) { + H5O_info_t root_oinfo; + + if ( H5L_TYPE_HARD != lnk_info.type ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5L_TYPE_HARD != lnk_info.type"; + } + HDassert(H5L_TYPE_HARD == lnk_info.type); + + memset(&root_oinfo, 0, sizeof(root_oinfo)); + ret = H5Oget_info(fid, &root_oinfo); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Oget_info() failed."; + } + else if ( root_oinfo.addr != lnk_info.u.address ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_d: root_oinfo.addr != lnk_info.u.address"; + } + HDassert(ret >= 0); + HDassert(root_oinfo.addr == lnk_info.u.address); + } /* end else-if */ + else { + void *elinkval; + const char *file = NULL; + const char *path = NULL; + + HDassert(2 == (u % 3)); + + if ( H5L_TYPE_EXTERNAL != lnk_info.type ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_d: H5L_TYPE_EXTERNAL != lnk_info.type"; + } + HDassert(H5L_TYPE_EXTERNAL == lnk_info.type); + + elinkval = malloc(lnk_info.u.val_size); + + if ( ! elinkval ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: malloc of elinkval failed."; + } + HDassert(elinkval); + + ret = H5Lget_val(gid, linkname, elinkval, lnk_info.u.val_size, + H5P_DEFAULT); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Lget_val failed."; + } + HDassert(ret >= 0); + + ret = H5Lunpack_elink_val(elinkval, lnk_info.u.val_size, NULL, + &file, &path); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Lunpack_elink_val failed."; + } + else if ( 0 != strcmp(file, "external.h5") ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_d: 0 != strcmp(file, \"external.h5\")."; + } + else if ( 0 != strcmp(path, "/ext") ) { + + pass = FALSE; + failure_mssg = + "vrfy_ns_grp_d: 0 != strcmp(path, \"/ext\")"; + } + HDassert(ret >= 0); + HDassert(0 == strcmp(file, "external.h5")); + HDassert(0 == strcmp(path, "/ext")); + + free(elinkval); + + } /* end else */ + + u++; + + } /* end while() */ + + if ( pass ) { + + ret = H5Gclose(gid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ns_grp_d: H5Gclose() failed."; + } + HDassert(ret >= 0); + } + + return; + +} /* vrfy_ns_grp_d() */ + + +/*------------------------------------------------------------------------- + * Function: os_grp_0 + * + * Purpose: Create an empty "old style" group. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + +void +os_grp_0(hid_t fid, const char *group_name) +{ + hid_t gid = -1; + herr_t ret; + + if ( pass ) { /* turn file format latest off */ + + ret = H5Fset_latest_format(fid, FALSE); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "os_grp_0: H5Fset_latest_format() failed(1)."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + gid = H5Gcreate2(fid, group_name, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + if ( gid <= 0 ) { + + pass = FALSE; + failure_mssg = "os_grp_0: H5Gcreate2() failed."; + } + HDassert(gid > 0); + } + + if ( pass ) { + + ret = H5Gclose(gid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "os_grp_0: H5Gclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { /* turn file format latest on */ + + ret = H5Fset_latest_format(fid, TRUE); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "os_grp_0: H5Fset_latest_format() failed(2)."; + } + HDassert(ret >= 0); + } + + return; + +} /* os_grp_0() */ + + +/*------------------------------------------------------------------------- + * Function: vrfy_os_grp_0 + * + * Purpose: Validate an empty "old style" group. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + +void +vrfy_os_grp_0(hid_t fid, const char *group_name) +{ + hid_t gid = -1; + hid_t gcpl = -1; + H5G_info_t grp_info; + unsigned crt_order_flags = 0; + herr_t ret; + + if ( pass ) { + + gid = H5Gopen2(fid, group_name, H5P_DEFAULT); + + if ( gid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: H5Gopen2() failed."; + } + HDassert(gid > 0); + } + + if ( pass ) { + + gcpl = H5Gget_create_plist(gid); + + if ( gcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: H5Gget_create_plist() failed."; + } + HDassert(gcpl > 0); + } + + if ( pass ) { + + ret = H5Pget_link_creation_order(gcpl, &crt_order_flags); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: H5Pget_link_creation_order() failed"; + } + else if ( 0 != crt_order_flags ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: 0 != crt_order_flags"; + } + HDassert(ret >= 0); + HDassert(0 == crt_order_flags); + } + + if ( pass ) { + + ret = H5Pclose(gcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: H5Pclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + memset(&grp_info, 0, sizeof(grp_info)); + ret = H5Gget_info(gid, &grp_info); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: H5Gget_info() failed."; + } + else if ( H5G_STORAGE_TYPE_SYMBOL_TABLE != grp_info.storage_type ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: H5G_STORAGE_TYPE_SYMBOL_TABLE != grp_info.storage_type"; + } + else if ( 0 != grp_info.nlinks ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: 0 != grp_info.nlinks"; + } + else if ( 0 != grp_info.max_corder ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: 0 != grp_info.max_corder"; + } + else if ( FALSE != grp_info.mounted ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: FALSE != grp_info.mounted"; + } + HDassert(ret >= 0); + HDassert(H5G_STORAGE_TYPE_SYMBOL_TABLE == grp_info.storage_type); + HDassert(0 == grp_info.nlinks); + HDassert(0 == grp_info.max_corder); + HDassert(false == grp_info.mounted); + } + + if ( pass ) { + + ret = H5Gclose(gid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_0: H5Gclose() failed."; + } + HDassert(ret >= 0); + } + + return; + +} /* vrfy_os_grp_0() */ + + +/*------------------------------------------------------------------------- + * Function: os_grp_n + * + * Purpose: Create an "old style" group, with 'nlinks' soft/hard + * links in it. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + +void +os_grp_n(hid_t fid, const char *group_name, int proc_num, unsigned nlinks) +{ + hid_t gid = -1; + unsigned u; + herr_t ret; + + if ( pass ) { /* turn file format latest off */ + + ret = H5Fset_latest_format(fid, FALSE); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "os_grp_n: H5Fset_latest_format() failed(1)."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + gid = H5Gcreate2(fid, group_name, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + if ( gid <= 0 ) { + + pass = FALSE; + failure_mssg = "os_grp_n: H5Gcreate2() failed."; + } + HDassert(gid > 0); + } + + HDassert(nlinks > 0); + + u = 0; + while ( ( pass ) && ( u < nlinks ) ) { + + char linkname[32]; + + sprintf(linkname, "ln%d_%u", proc_num, u); + + if(0 == (u % 2)) { + + ret = H5Lcreate_soft(group_name, gid, linkname, H5P_DEFAULT, + H5P_DEFAULT); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "os_grp_n: H5Lcreate_soft() failed."; + } + HDassert(ret >= 0); + } /* end if */ + else { + + HDassert(1 == (u % 2)); + + ret = H5Lcreate_hard(fid, "/", gid, linkname, H5P_DEFAULT, + H5P_DEFAULT); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "os_grp_n: H5Lcreate_hard() failed."; + } + HDassert(ret >= 0); + } /* end else */ + + u++; + + } /* end while */ + + if ( pass ) { + + ret = H5Gclose(gid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "os_grp_n: H5Gclose() failed."; + } + assert(ret >= 0); + } + + if ( pass ) { /* turn file format latest on */ + + ret = H5Fset_latest_format(fid, TRUE); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "os_grp_n: H5Fset_latest_format() failed(2)."; + } + HDassert(ret >= 0); + } + + return; +} /* os_grp_n() */ + + +/*------------------------------------------------------------------------- + * Function: vrfy_os_grp_n + * + * Purpose: Validate an "old style" group with 'nlinks' soft/hard + * links in it. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ +void +vrfy_os_grp_n(hid_t fid, const char *group_name, int proc_num, unsigned nlinks) +{ + hid_t gid = -1; + hid_t gcpl = -1; + H5G_info_t grp_info; + unsigned crt_order_flags = 0; + unsigned u; + herr_t ret; + + if ( pass ) { + + gid = H5Gopen2(fid, group_name, H5P_DEFAULT); + + if ( gid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5Gopen2() failed"; + } + HDassert(gid > 0); + } + + if ( pass ) { + + gcpl = H5Gget_create_plist(gid); + + if ( gcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5Gget_create_plist() failed"; + } + HDassert(gcpl > 0); + } + + if ( pass ) { + + ret = H5Pget_link_creation_order(gcpl, &crt_order_flags); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5Pget_link_creation_order"; + } + else if ( 0 != crt_order_flags ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: 0 != crt_order_flags"; + } + HDassert(ret >= 0); + HDassert(0 == crt_order_flags); + } + + if ( pass ) { + + ret = H5Pclose(gcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5Pclose() failed"; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + memset(&grp_info, 0, sizeof(grp_info)); + + ret = H5Gget_info(gid, &grp_info); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5Gget_info() failed"; + } + else if ( H5G_STORAGE_TYPE_SYMBOL_TABLE != grp_info.storage_type ) { + + pass = FALSE; + failure_mssg = + "vrfy_os_grp_n: H5G_STORAGE_TYPE_SYMBOL_TABLE != grp_info.storage_type"; + } + else if ( nlinks != grp_info.nlinks ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: nlinks != grp_info.nlinks"; + } + else if ( 0 != grp_info.max_corder ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: 0 != grp_info.max_corder"; + } + else if ( FALSE != grp_info.mounted ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: FALSE != grp_info.mounted"; + } + HDassert(ret >= 0); + HDassert(H5G_STORAGE_TYPE_SYMBOL_TABLE == grp_info.storage_type); + HDassert(nlinks == grp_info.nlinks); + HDassert(0 == grp_info.max_corder); + HDassert(false == grp_info.mounted); + } + + u = 0; + while ( ( pass ) && ( u < nlinks ) ) { + + H5L_info_t lnk_info; + char linkname[32]; + htri_t link_exists; + + sprintf(linkname, "ln%d_%u", proc_num, u); + link_exists = H5Lexists(gid, linkname, H5P_DEFAULT); + + if ( link_exists < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5Lexists() failed"; + } + HDassert(link_exists >= 0); + + memset(&lnk_info, 0, sizeof(grp_info)); + ret = H5Lget_info(gid, linkname, &lnk_info, H5P_DEFAULT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5Lget_info() failed"; + } + else if ( FALSE != lnk_info.corder_valid ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: FALSE != lnk_info.corder_valid"; + } + else if ( H5T_CSET_ASCII != lnk_info.cset ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5T_CSET_ASCII != lnk_info.cset"; + } + HDassert(ret >= 0); + HDassert(false == lnk_info.corder_valid); + HDassert(H5T_CSET_ASCII == lnk_info.cset); + + if(0 == (u % 2)) { + char *slinkval; + + if ( H5L_TYPE_SOFT != lnk_info.type ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5L_TYPE_SOFT != lnk_info.type"; + } + else if ( (strlen(group_name) + 1) != lnk_info.u.val_size ) { + + pass = FALSE; + failure_mssg = + "vrfy_os_grp_n: (strlen(group_name) + 1) != lnk_info.u.val_size"; + } + HDassert(H5L_TYPE_SOFT == lnk_info.type); + HDassert((strlen(group_name) + 1) == lnk_info.u.val_size); + + slinkval = (char *)malloc(lnk_info.u.val_size); + + if ( ! slinkval ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: malloc of slinkval failed"; + } + HDassert(slinkval); + + ret = H5Lget_val(gid, linkname, slinkval, lnk_info.u.val_size, + H5P_DEFAULT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5Lget_val() failed"; + } + else if ( 0 != strcmp(slinkval, group_name) ) { + + pass = FALSE; + failure_mssg = + "vrfy_os_grp_n: 0 != strcmp(slinkval, group_name)"; + } + HDassert(ret >= 0); + HDassert(0 == strcmp(slinkval, group_name)); + + free(slinkval); + } /* end if */ + else { + H5O_info_t root_oinfo; + + HDassert(1 == (u % 2)); + + if ( H5L_TYPE_HARD != lnk_info.type ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5L_TYPE_HARD != lnk_info.type"; + } + HDassert(H5L_TYPE_HARD == lnk_info.type); + + memset(&root_oinfo, 0, sizeof(root_oinfo)); + ret = H5Oget_info(fid, &root_oinfo); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5Oget_info() failed."; + } + else if ( root_oinfo.addr != lnk_info.u.address ) { + + pass = FALSE; + failure_mssg = + "vrfy_os_grp_n: root_oinfo.addr != lnk_info.u.address"; + } + HDassert(ret >= 0); + HDassert(root_oinfo.addr == lnk_info.u.address); + } /* end else */ + + u++; + + } /* end while */ + + if ( pass ) { + + ret = H5Gclose(gid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_os_grp_n: H5Gclose() failed."; + } + HDassert(ret >= 0); + } + + return; + +} /* vrfy_os_grp_n() */ + + +/*------------------------------------------------------------------------- + * Function: ds_ctg_i + * + * Purpose: Create a contiguous dataset w/int datatype. Write data + * to the data set or not as indicated by the write_data + * parameter. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ +void +ds_ctg_i(hid_t fid, const char *dset_name, hbool_t write_data) +{ + int *wdata = NULL; + unsigned u; + hid_t dsid = -1; + hid_t sid = -1; + hsize_t dims[1] = {DSET_DIMS}; + herr_t ret; + + if ( pass ) { + + sid = H5Screate_simple(1, dims, NULL); + + if ( sid <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_i: H5Screate_simple() failed"; + } + HDassert(sid > 0); + } + + if ( pass ) { + + dsid = H5Dcreate2(fid, dset_name, H5T_NATIVE_INT, sid, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + + if ( dsid <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_i: H5Dcreate2() failed"; + } + HDassert(dsid > 0); + } + + if ( pass ) { + + ret = H5Sclose(sid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_i: H5Sclose() failed"; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + wdata = (int *)malloc(sizeof(int) * DSET_DIMS); + + if ( ! wdata ) { + + pass = FALSE; + failure_mssg = "ds_ctg_i: malloc of wdata failed."; + } + HDassert(wdata); + } + + if ( ( pass ) && ( write_data ) ) { + + for(u = 0; u < DSET_DIMS; u++) + + wdata[u] = (int)u; + + ret = H5Dwrite(dsid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, wdata); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_i: H5Dwrite() failed."; + } + HDassert(ret >= 0); + + free(wdata); + } + + if ( pass ) { + + ret = H5Dclose(dsid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_i: H5Dclose() failed"; + } + HDassert(ret >= 0); + } + + return; + +} /* ds_ctg_i */ + + +/*------------------------------------------------------------------------- + * Function: vrfy_ds_ctg_i + * + * Purpose: Validate a contiguous datasets w/int datatypes. Validate + * data if indicated via the write_data parameter. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ +void +vrfy_ds_ctg_i(hid_t fid, const char *dset_name, hbool_t write_data) +{ + int *rdata = NULL; + unsigned u; + hid_t dsid = -1; + hid_t sid = -1; + hid_t tid = -1; + hid_t dcpl = -1; + H5D_space_status_t allocation; + H5D_layout_t layout; + int ndims; + hsize_t dims[1], max_dims[1]; + htri_t type_equal; + herr_t ret; + + if ( pass ) { + + dsid = H5Dopen2(fid, dset_name, H5P_DEFAULT); + + if ( dsid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Dopen2() failed."; + } + HDassert(dsid > 0); + } + + if ( pass ) { + + sid = H5Dget_space(dsid); + + if ( sid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Dget_space() failed."; + } + HDassert(sid > 0); + } + + if ( pass ) { + + ndims = H5Sget_simple_extent_ndims(sid); + + if ( 1 != ndims ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: 1 != ndims"; + } + HDassert(1 == ndims); + } + + if ( pass ) { + + ret = H5Sget_simple_extent_dims(sid, dims, max_dims); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Sget_simple_extent_dims() failed"; + } + else if ( DSET_DIMS != dims[0] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: DSET_DIMS != dims[0]"; + } + else if ( DSET_DIMS != max_dims[0] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: DSET_DIMS != max_dims[0]"; + } + HDassert(ret >= 0); + HDassert(DSET_DIMS == dims[0]); + HDassert(DSET_DIMS == max_dims[0]); + } + + if ( pass ) { + + ret = H5Sclose(sid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Sclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + tid = H5Dget_type(dsid); + + if ( tid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Dget_type() failed."; + } + HDassert(tid > 0); + } + + if ( pass ) { + + type_equal = H5Tequal(tid, H5T_NATIVE_INT); + + if ( 1 != type_equal ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: type not H5T_NATIVE_INT"; + } + HDassert(1 == type_equal); + } + + if ( pass ) { + + ret = H5Tclose(tid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Tclose() failed."; + } + assert(ret >= 0); + } + + if ( pass ) { + + ret = H5Dget_space_status(dsid, &allocation); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Dget_space_status() failed."; + } + else if ( write_data && ( allocation != H5D_SPACE_STATUS_ALLOCATED ) ) { + + pass = FALSE; + failure_mssg = + "vrfy_ds_ctg_i: write_data && allocation != H5D_SPACE_STATUS_ALLOCATED"; + } + else if ( !write_data && + ( allocation != H5D_SPACE_STATUS_NOT_ALLOCATED ) ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: !write_data && allocation != H5D_SPACE_STATUS_NOT_ALLOCATED"; + } + HDassert(ret >= 0); + HDassert((write_data && allocation == H5D_SPACE_STATUS_ALLOCATED) || + (!write_data && allocation == H5D_SPACE_STATUS_NOT_ALLOCATED)); + } + + if ( pass ) { + + dcpl = H5Dget_create_plist(dsid); + + if ( dcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Dget_create_plist() failed."; + } + HDassert(dcpl > 0); + } + + if ( pass ) { + + layout = H5Pget_layout(dcpl); + + if ( H5D_CONTIGUOUS != layout ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5D_CONTIGUOUS != layout"; + } + HDassert(H5D_CONTIGUOUS == layout); + } + + if ( pass ) { + + ret = H5Pclose(dcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Pclose() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + rdata = (int *)malloc(sizeof(int) * DSET_DIMS); + + if ( ! rdata ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: malloc of rdata failed."; + } + HDassert(rdata); + } + + if ( ( pass ) && ( write_data ) ) { + + ret = H5Dread(dsid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, rdata); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Dread() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + for(u = 0; u < DSET_DIMS; u++) { + + if ( (int)u != rdata[u] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: u != rdata[u]."; + break; + } + HDassert((int)u == rdata[u]); + } + + free(rdata); + } /* end if */ + + if ( pass ) { + + ret = H5Dclose(dsid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_i: H5Dclose() failed"; + } + HDassert(ret >= 0); + } + + return; + +} /* vrfy_ds_ctg_i() */ + + +/*------------------------------------------------------------------------- + * Function: ds_chk_i + * + * Purpose: Create a chunked dataset w/int datatype. Write data + * to the data set or not as indicated by the write_data + * parameter. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ +void +ds_chk_i(hid_t fid, const char *dset_name, hbool_t write_data) +{ + int *wdata = NULL; + unsigned u; + hid_t dsid = -1; + hid_t dcpl = -1; + hid_t sid = -1; + hsize_t dims[1] = {DSET_DIMS}; + hsize_t chunk_dims[1] = {DSET_CHUNK_DIMS}; + herr_t ret; + + if ( pass ) { + + sid = H5Screate_simple(1, dims, NULL); + + if ( sid <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_chk_i: H5Screate_simple() failed."; + } + HDassert(sid > 0); + } + + if ( pass ) { + + dcpl = H5Pcreate(H5P_DATASET_CREATE); + + if ( dcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_chk_i: H5Pcreate() failed."; + } + HDassert(dcpl > 0); + } + + if ( pass ) { + + ret = H5Pset_chunk(dcpl, 1, chunk_dims); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_chk_i: H5Pset_chunk() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + dsid = H5Dcreate2(fid, dset_name, H5T_NATIVE_INT, sid, + H5P_DEFAULT, dcpl, H5P_DEFAULT); + + if ( dsid <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_chk_i: H5Dcreate2() failed"; + } + HDassert(dsid > 0); + } + + if ( pass ) { + + ret = H5Pclose(dcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_chk_i: H5Pclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Sclose(sid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_chk_i: H5Sclose() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + wdata = (int *)malloc(sizeof(int) * DSET_DIMS); + + if ( ! wdata ) { + + pass = FALSE; + failure_mssg = "ds_chk_i: malloc of wdata failed."; + } + HDassert(wdata); + } + + if ( ( pass ) && ( write_data ) ) { + + for(u = 0; u < DSET_DIMS; u++) + wdata[u] = (int)u; + + ret = H5Dwrite(dsid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, wdata); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_chk_i: H5Dwrite() failed."; + } + HDassert(ret >= 0); + + free(wdata); + } /* end if */ + + if ( pass ) { + + ret = H5Dclose(dsid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_chk_i: H5Dclose() failed."; + } + HDassert(ret >= 0); + } + + return; + +} /* ds_chk_i */ + + +/*------------------------------------------------------------------------- + * Function: vrfy_ds_chk_i + * + * Purpose: Validate a chunked datasets w/int datatypes. Validate + * data if indicated via the write_data parameter. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ +void +vrfy_ds_chk_i(hid_t fid, const char *dset_name, hbool_t write_data) +{ + int *rdata = NULL; + unsigned u; + hid_t dsid = -1; + hid_t sid = -1; + hid_t tid = -1; + hid_t dcpl = -1; + H5D_space_status_t allocation; + H5D_layout_t layout; + int ndims; + hsize_t dims[1], max_dims[1], chunk_dims[1]; + htri_t type_equal; + herr_t ret; + + if ( pass ) { + + dsid = H5Dopen2(fid, dset_name, H5P_DEFAULT); + + if ( dsid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Dopen2() failed."; + } + HDassert(dsid > 0); + } + + if ( pass ) { + + sid = H5Dget_space(dsid); + + if ( sid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Dget_space() failed."; + } + HDassert(sid > 0); + } + + if ( pass ) { + + ndims = H5Sget_simple_extent_ndims(sid); + + if ( 1 != ndims ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: 1 != ndims"; + } + HDassert(1 == ndims); + } + + if ( pass ) { + + ret = H5Sget_simple_extent_dims(sid, dims, max_dims); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Sget_simple_extent_dims() failed"; + } + else if ( DSET_DIMS != dims[0] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: DSET_DIMS != dims[0]"; + } + else if ( DSET_DIMS != max_dims[0] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: DSET_DIMS != max_dims[0]"; + } + HDassert(ret >= 0); + HDassert(DSET_DIMS == dims[0]); + HDassert(DSET_DIMS == max_dims[0]); + } + + if ( pass ) { + + ret = H5Sclose(sid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Sclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + tid = H5Dget_type(dsid); + + if ( tid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Dget_type() failed."; + } + HDassert(tid > 0); + } + + if ( pass ) { + + type_equal = H5Tequal(tid, H5T_NATIVE_INT); + + if ( 1 != type_equal ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: tid != H5T_NATIVE_INT"; + } + HDassert(1 == type_equal); + } + + if ( pass ) { + + ret = H5Tclose(tid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Tclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Dget_space_status(dsid, &allocation); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Dget_space_status() failed."; + } + else if ( write_data && ( allocation != H5D_SPACE_STATUS_ALLOCATED ) ) { + + pass = FALSE; + failure_mssg = + "vrfy_ds_chk_i: write_data && allocation != H5D_SPACE_STATUS_ALLOCATED"; + } + else if ( !write_data && + ( allocation != H5D_SPACE_STATUS_NOT_ALLOCATED ) ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: !write_data && allocation != H5D_SPACE_STATUS_NOT_ALLOCATED"; + } + HDassert(ret >= 0); + HDassert((write_data && allocation == H5D_SPACE_STATUS_ALLOCATED) || + (!write_data && allocation == H5D_SPACE_STATUS_NOT_ALLOCATED)); + } + + if ( pass ) { + + dcpl = H5Dget_create_plist(dsid); + + if ( dcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Dget_create_plist() failed."; + } + HDassert(dcpl > 0); + } + + if ( pass ) { + + layout = H5Pget_layout(dcpl); + + if ( H5D_CHUNKED != layout ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5D_CHUNKED != layout"; + } + HDassert(H5D_CHUNKED == layout); + } + + if ( pass ) { + + ret = H5Pget_chunk(dcpl, 1, chunk_dims); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Pget_chunk"; + } + else if ( DSET_CHUNK_DIMS != chunk_dims[0] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: "; + } + HDassert(ret >= 0); + HDassert(DSET_CHUNK_DIMS == chunk_dims[0]); + } + + if ( pass ) { + + ret = H5Pclose(dcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Pclose() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + rdata = (int *)malloc(sizeof(int) * DSET_DIMS); + + if ( ! rdata ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: malloc of rdata failed."; + } + HDassert(rdata); + } + + if ( ( pass ) && ( write_data ) ) { + + ret = H5Dread(dsid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, + rdata); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Dread() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + for(u = 0; u < DSET_DIMS; u++) { + + if ( (int)u != rdata[u] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: u != rdata[u]"; + break; + } + HDassert((int)u == rdata[u]); + } + + free(rdata); + } /* end if */ + + + if ( pass ) { + + ret = H5Dclose(dsid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_chk_i: H5Dclose() failed."; + } + HDassert(ret >= 0); + } + + return; + +} /* vrfy_ds_chk_i() */ + + +/*------------------------------------------------------------------------- + * Function: ds_cpt_i + * + * Purpose: Create a compact dataset w/int datatype. Write data + * to the data set or not as indicated by the write_data + * parameter. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ +void +ds_cpt_i(hid_t fid, const char *dset_name, hbool_t write_data) +{ + int *wdata = NULL; + unsigned u; + hid_t dsid = -1; + hid_t dcpl = -1; + hid_t sid = -1; + hsize_t dims[1] = {DSET_COMPACT_DIMS}; + herr_t ret; + + if ( pass ) { + + sid = H5Screate_simple(1, dims, NULL); + + if ( sid <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_cpt_i: H5Screate_simple() failed."; + } + HDassert(sid > 0); + } + + if ( pass ) { + + dcpl = H5Pcreate(H5P_DATASET_CREATE); + + if ( dcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_cpt_i: H5Pcreate() failed."; + } + HDassert(dcpl > 0); + } + + if ( pass ) { + + ret = H5Pset_layout(dcpl, H5D_COMPACT); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_cpt_i: H5Pset_layout() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + dsid = H5Dcreate2(fid, dset_name, H5T_NATIVE_INT, sid, + H5P_DEFAULT, dcpl, H5P_DEFAULT); + + if ( dsid <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_cpt_i: H5Dcreate2() failed."; + } + HDassert(dsid > 0); + } + + if ( pass ) { + + ret = H5Pclose(dcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_cpt_i: H5Pclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Sclose(sid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_cpt_i: H5Sclose() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + wdata = (int *)malloc(sizeof(int) * DSET_COMPACT_DIMS); + + if ( ! wdata ) { + + pass = FALSE; + failure_mssg = "ds_cpt_i: malloc of wdata failed."; + } + HDassert(wdata); + } + + if ( ( pass ) && ( write_data ) ) { + + for(u = 0; u < DSET_COMPACT_DIMS; u++) + wdata[u] = (int)u; + + ret = H5Dwrite(dsid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, wdata); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_cpt_i: H5Dwrite() failed."; + } + HDassert(ret >= 0); + + free(wdata); + } /* end if */ + + if ( pass ) { + + ret = H5Dclose(dsid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_cpt_i: H5Dclose() failed."; + } + HDassert(ret >= 0); + } + + return; + +} /* ds_cpt_i() */ + + +/*------------------------------------------------------------------------- + * Function: vrfy_ds_cpt_i + * + * Purpose: Validate a compact datasets w/int datatypes. Validate + * data if indicated via the write_data parameter. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ +void +vrfy_ds_cpt_i(hid_t fid, const char *dset_name, hbool_t write_data) +{ + int *rdata = NULL; + unsigned u; + hid_t dsid = -1; + hid_t sid = -1; + hid_t tid = -1; + hid_t dcpl = -1; + H5D_space_status_t allocation; + H5D_layout_t layout; + int ndims; + hsize_t dims[1], max_dims[1]; + htri_t type_equal; + herr_t ret; + + if ( pass ) { + + dsid = H5Dopen2(fid, dset_name, H5P_DEFAULT); + + if ( dsid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Dopen2() failed."; + } + HDassert(dsid > 0); + } + + if ( pass ) { + + sid = H5Dget_space(dsid); + + if ( sid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Dget_space() failed."; + } + HDassert(sid > 0); + } + + if ( pass ) { + + ndims = H5Sget_simple_extent_ndims(sid); + + if ( 1 != ndims ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: 1 != ndims"; + } + HDassert(1 == ndims); + } + + if ( pass ) { + + ret = H5Sget_simple_extent_dims(sid, dims, max_dims); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Sget_simple_extent_dims() failed"; + } + else if ( DSET_COMPACT_DIMS != dims[0] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: DSET_COMPACT_DIMS != dims[0]"; + } + else if ( DSET_COMPACT_DIMS != max_dims[0] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: DSET_COMPACT_DIMS != max_dims[0]"; + } + HDassert(ret >= 0); + HDassert(DSET_COMPACT_DIMS == dims[0]); + HDassert(DSET_COMPACT_DIMS == max_dims[0]); + } + + if ( pass ) { + + ret = H5Sclose(sid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Sclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + tid = H5Dget_type(dsid); + + if ( tid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Dget_type() failed."; + } + HDassert(tid > 0); + } + + if ( pass ) { + + type_equal = H5Tequal(tid, H5T_NATIVE_INT); + + if ( 1 != type_equal ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: type != H5T_NATIVE_INT"; + } + HDassert(1 == type_equal); + } + + if ( pass ) { + + ret = H5Tclose(tid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Tclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Dget_space_status(dsid, &allocation); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Dget_space_status() failed."; + } + else if ( H5D_SPACE_STATUS_ALLOCATED != allocation ) { + + pass = FALSE; + failure_mssg = + "vrfy_ds_cpt_i: H5D_SPACE_STATUS_ALLOCATED != allocation"; + } + HDassert(ret >= 0); + HDassert(H5D_SPACE_STATUS_ALLOCATED == allocation); + } + + if ( pass ) { + + dcpl = H5Dget_create_plist(dsid); + + if ( dcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Dget_create_plist() failed."; + } + HDassert(dcpl > 0); + } + + if ( pass ) { + + layout = H5Pget_layout(dcpl); + + if ( H5D_COMPACT != layout ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5D_COMPACT != layout"; + } + HDassert(H5D_COMPACT == layout); + } + + if ( pass ) { + + ret = H5Pclose(dcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Pclose() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + rdata = (int *)malloc(sizeof(int) * DSET_COMPACT_DIMS); + + if ( ! rdata ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: malloc of rdata failed."; + } + HDassert(rdata); + } + + if ( ( pass ) && ( write_data ) ) { + + ret = H5Dread(dsid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, rdata); + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Dread() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + for(u = 0; u < DSET_COMPACT_DIMS; u++) { + + if ( (int)u != rdata[u] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: (int)u != rdata[u]"; + break; + } + HDassert((int)u == rdata[u]); + } + + free(rdata); + } /* end if */ + + if ( pass ) { + + ret = H5Dclose(dsid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_cpt_i: H5Dclose() failed."; + } + HDassert(ret >= 0); + } + + return; + +} /* vrfy_ds_cpt_i() */ + + +/*------------------------------------------------------------------------- + * Function: ds_ctg_v + * + * Purpose: Create a contiguous dataset w/variable-length datatype. + * Write data to the data set or not as indicated by the + * write_data parameter. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ +void +ds_ctg_v(hid_t fid, const char *dset_name, hbool_t write_data) +{ + hid_t dsid = -1; + hid_t sid = -1; + hid_t tid = -1; + hsize_t dims[1] = {DSET_SMALL_DIMS}; + herr_t ret; + hvl_t *wdata = NULL; + unsigned u; + + if ( pass ) { + + sid = H5Screate_simple(1, dims, NULL); + + if ( sid <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_v: H5Screate_simple"; + } + HDassert(sid > 0); + } + + if ( pass ) { + + tid = H5Tvlen_create(H5T_NATIVE_INT); + + if ( tid <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_v: H5Tvlen_create() failed."; + } + HDassert(tid > 0); + } + + if ( pass ) { + + dsid = H5Dcreate2(fid, dset_name, tid, sid, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + + if ( dsid <= 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_v: H5Dcreate2() failed."; + } + HDassert(dsid > 0); + } + + if ( ( pass ) && ( write_data ) ) { + + wdata = (hvl_t *)malloc(sizeof(hvl_t) * DSET_SMALL_DIMS); + + if ( ! wdata ) { + + pass = FALSE; + failure_mssg = "ds_ctg_v: malloc of wdata failed."; + } + HDassert(wdata); + } + + if ( ( pass ) && ( write_data ) ) { + + for(u = 0; u < DSET_SMALL_DIMS; u++) { + + int *tdata; + unsigned len; + unsigned v; + + len = (u % 10) + 1; + tdata = (int *)malloc(sizeof(int) * len); + + if ( !tdata ) { + + pass = FALSE; + failure_mssg = "ds_ctg_v: malloc of tdata failed."; + break; + } + HDassert(tdata); + + for(v = 0; v < len; v++) + tdata[v] = (int)(u + v); + + wdata[u].len = len; + wdata[u].p = tdata; + } /* end for */ + } + + if ( ( pass ) && ( write_data ) ) { + + ret = H5Dwrite(dsid, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_v: H5Dwrite() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + ret = H5Dvlen_reclaim(tid, sid, H5P_DEFAULT, wdata); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_v: H5Dvlen_reclaim() failed."; + } + HDassert(ret >= 0); + + free(wdata); + + } /* end if */ + + if ( pass ) { + + ret = H5Sclose(sid); + + if ( sid < 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_v: H5Sclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Tclose(tid); + + if ( tid < 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_v: H5Tclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Dclose(dsid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "ds_ctg_v: H5Dclose() failed."; + } + HDassert(ret >= 0); + } + + return; + +} /* ds_ctg_v() */ + + +/*------------------------------------------------------------------------- + * Function: vrfy_ds_ctg_v + * + * Purpose: Validate a contiguous datasets w/variable-length datatypes. + * Validate data if indicated via the write_data parameter. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ +void +vrfy_ds_ctg_v(hid_t fid, const char *dset_name, hbool_t write_data) +{ + hid_t dsid = -1; + hid_t sid = -1; + hid_t tid = -1; + hid_t tmp_tid = -1; + hid_t dcpl = -1; + H5D_space_status_t allocation; + H5D_layout_t layout; + int ndims; + hsize_t dims[1], max_dims[1]; + htri_t type_equal; + hvl_t *rdata = NULL; + unsigned u; + herr_t ret; + + if ( pass ) { + + dsid = H5Dopen2(fid, dset_name, H5P_DEFAULT); + + if ( dsid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Dopen2() failed."; + } + HDassert(dsid > 0); + } + + if ( pass ) { + + sid = H5Dget_space(dsid); + + if ( sid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Dget_space() failed"; + } + HDassert(sid > 0); + } + + if ( pass ) { + + ndims = H5Sget_simple_extent_ndims(sid); + + if ( 1 != ndims ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: 1 != ndims"; + } + HDassert(1 == ndims); + } + + if ( pass ) { + + ret = H5Sget_simple_extent_dims(sid, dims, max_dims); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Sget_simple_extent_dims() failed."; + } + else if ( DSET_SMALL_DIMS != dims[0] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: DSET_SMALL_DIMS != dims[0]"; + } + else if ( DSET_SMALL_DIMS != max_dims[0] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: DSET_SMALL_DIMS != max_dims[0]"; + } + HDassert(ret >= 0); + HDassert(DSET_SMALL_DIMS == dims[0]); + HDassert(DSET_SMALL_DIMS == max_dims[0]); + } + + if ( pass ) { + + tid = H5Dget_type(dsid); + + if ( tid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Dget_type() failed."; + } + HDassert(tid > 0); + } + + if ( pass ) { + + tmp_tid = H5Tvlen_create(H5T_NATIVE_INT); + + if ( tmp_tid <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Tvlen_create() failed."; + } + HDassert(tmp_tid > 0); + } + + if ( pass ) { + + type_equal = H5Tequal(tid, tmp_tid); + + if ( 1 != type_equal ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: type != vlen H5T_NATIVE_INT"; + } + HDassert(1 == type_equal); + } + + if ( pass ) { + + ret = H5Tclose(tmp_tid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Tclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Dget_space_status(dsid, &allocation); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Dget_space_status() failed"; + } + else if ( write_data && (allocation != H5D_SPACE_STATUS_ALLOCATED) ) { + + pass = FALSE; + failure_mssg = + "vrfy_ds_ctg_v: write_data && allocation != H5D_SPACE_STATUS_ALLOCATED"; + } + else if ( !write_data && + ( allocation != H5D_SPACE_STATUS_NOT_ALLOCATED ) ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: !write_data && allocation != H5D_SPACE_STATUS_NOT_ALLOCATED"; + } + HDassert(ret >= 0); + HDassert((write_data && allocation == H5D_SPACE_STATUS_ALLOCATED) || + (!write_data && allocation == H5D_SPACE_STATUS_NOT_ALLOCATED)); + } + + if ( pass ) { + + dcpl = H5Dget_create_plist(dsid); + + if ( dcpl <= 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Dget_create_plist() failed."; + } + HDassert(dcpl > 0); + } + + if ( pass ) { + + layout = H5Pget_layout(dcpl); + + if ( H5D_CONTIGUOUS != layout ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5D_CONTIGUOUS != layout"; + } + HDassert(H5D_CONTIGUOUS == layout); + } + + if ( pass ) { + + ret = H5Pclose(dcpl); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Pclose() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + rdata = (hvl_t *)malloc(sizeof(hvl_t) * DSET_SMALL_DIMS); + + if ( !rdata ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: malloc of rdata failed."; + } + HDassert(rdata); + } + + if ( ( pass ) && ( write_data ) ) { + + ret = H5Dread(dsid, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Dread() failed."; + } + HDassert(ret >= 0); + } + + if ( ( pass ) && ( write_data ) ) { + + for(u = 0; u < DSET_SMALL_DIMS; u++) { + unsigned len; + unsigned v; + + len = (unsigned)rdata[u].len; + for(v = 0; v < len; v++) { + int *tdata = (int *)rdata[u].p; + + if ( !tdata ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: !tdata"; + break; + } + else if ( (int)(u + v) != tdata[v] ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: (int)(u + v) != tdata[v]"; + break; + } + HDassert(tdata); + HDassert((int)(u + v) == tdata[v]); + } /* end for */ + } /* end for */ + } + + if ( ( pass ) && ( write_data ) ) { + + ret = H5Dvlen_reclaim(tid, sid, H5P_DEFAULT, rdata); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Dvlen_reclaim() failed."; + } + HDassert(ret >= 0); + + free(rdata); + } /* end if */ + + if ( pass ) { + + ret = H5Sclose(sid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Sclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Tclose(tid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Tclose() failed."; + } + HDassert(ret >= 0); + } + + if ( pass ) { + + ret = H5Dclose(dsid); + + if ( ret < 0 ) { + + pass = FALSE; + failure_mssg = "vrfy_ds_ctg_v: H5Dclose() failed."; + } + HDassert(ret >= 0); + } + + return; + +} /* vrfy_ds_ctg_v() */ + + +/*------------------------------------------------------------------------- + * Function: create_zoo + * + * Purpose: Given the path to a group, construct a variety of HDF5 + * data sets, groups, and other objects selected so as to + * include instances of all on disk data structures used + * in the HDF5 library. + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * This function was initially created to assist in testing + * the cache image feature of the metadata cache. Thus, it + * only concerns itself with the version 2 superblock, and + * on disk structures that can occur with this version of + * the superblock. + * + * Note the associated validate_zoo() function. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + +void +create_zoo(hid_t fid, const char *base_path, int proc_num) +{ + char full_path[1024]; + + HDassert(base_path); + + /* Add & verify an empty "new style" group */ + if ( pass ) { + sprintf(full_path, "%s/A", base_path); + HDassert(strlen(full_path) < 1024); + ns_grp_0(fid, full_path); + } + + if ( pass ) { + sprintf(full_path, "%s/A", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ns_grp_0(fid, full_path); + } + + /* Add & verify a compact "new style" group (3 link messages) */ + if ( pass ) { + sprintf(full_path, "%s/B", base_path); + HDassert(strlen(full_path) < 1024); + ns_grp_c(fid, full_path, 3); + } + + if ( pass ) { + sprintf(full_path, "%s/B", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ns_grp_c(fid, full_path, 3); + } + + /* Add & verify a dense "new style" group (w/300 links, in v2 B-tree & + * fractal heap) + */ + if ( pass ) { + sprintf(full_path, "%s/C", base_path); + HDassert(strlen(full_path) < 1024); + ns_grp_d(fid, full_path, 300); + } + + if ( pass ) { + sprintf(full_path, "%s/C", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ns_grp_d(fid, full_path, 300); + } + + /* Add & verify an empty "old style" group to file */ + if ( pass ) { + sprintf(full_path, "%s/D", base_path); + HDassert(strlen(full_path) < 1024); + os_grp_0(fid, full_path); + } + + if ( pass ) { + sprintf(full_path, "%s/D", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_os_grp_0(fid, full_path); + } + + /* Add & verify an "old style" group (w/300 links, in v1 B-tree & + * local heap) to file + */ + if ( pass ) { + sprintf(full_path, "%s/E", base_path); + HDassert(strlen(full_path) < 1024); + os_grp_n(fid, full_path, proc_num, 300); + } + + if ( pass ) { + sprintf(full_path, "%s/E", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_os_grp_n(fid, full_path, proc_num, 300); + } + + /* Add & verify a contiguous dataset w/integer datatype (but no data) + * to file + */ + if ( pass ) { + sprintf(full_path, "%s/F", base_path); + HDassert(strlen(full_path) < 1024); + ds_ctg_i(fid, full_path, FALSE); + } + + if ( pass ) { + sprintf(full_path, "%s/F", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_ctg_i(fid, full_path, FALSE); + } + + /* Add & verify a contiguous dataset w/integer datatype (with data) + * to file + */ + if ( pass ) { + sprintf(full_path, "%s/G", base_path); + HDassert(strlen(full_path) < 1024); + ds_ctg_i(fid, full_path, TRUE); + } + + if ( pass ) { + sprintf(full_path, "%s/G", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_ctg_i(fid, full_path, TRUE); + } + + /* Add & verify a chunked dataset w/integer datatype (but no data) + * to file + */ + if ( pass ) { + sprintf(full_path, "%s/H", base_path); + HDassert(strlen(full_path) < 1024); + ds_chk_i(fid, full_path, FALSE); + } + + if ( pass ) { + sprintf(full_path, "%s/H", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_chk_i(fid, full_path, FALSE); + } + + /* Add & verify a chunked dataset w/integer datatype (and data) + * to file + */ + if ( pass ) { + sprintf(full_path, "%s/I", base_path); + HDassert(strlen(full_path) < 1024); + ds_chk_i(fid, full_path, TRUE); + } + + if ( pass ) { + sprintf(full_path, "%s/I", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_chk_i(fid, full_path, TRUE); + } + + /* Add & verify a compact dataset w/integer datatype (but no data) + * to file + */ + if ( pass ) { + sprintf(full_path, "%s/J", base_path); + HDassert(strlen(full_path) < 1024); + ds_cpt_i(fid, full_path, FALSE); + } + + if ( pass ) { + sprintf(full_path, "%s/J", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_cpt_i(fid, full_path, FALSE); + } + + /* Add & verify a compact dataset w/integer datatype (and data) + * to file + */ + if ( pass ) { + sprintf(full_path, "%s/K", base_path); + HDassert(strlen(full_path) < 1024); + ds_cpt_i(fid, full_path, TRUE); + } + + if ( pass ) { + sprintf(full_path, "%s/K", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_cpt_i(fid, full_path, TRUE); + } + + /* Add & verify a contiguous dataset w/variable-length datatype + * (but no data) to file + */ + if ( pass ) { + sprintf(full_path, "%s/L", base_path); + HDassert(strlen(full_path) < 1024); + ds_ctg_v(fid, full_path, FALSE); + } + + if ( pass ) { + sprintf(full_path, "%s/L", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_ctg_v(fid, full_path, FALSE); + } + + /* Add & verify a contiguous dataset w/variable-length datatype + * (and data) to file + */ + if ( pass ) { + sprintf(full_path, "%s/M", base_path); + HDassert(strlen(full_path) < 1024); + ds_ctg_v(fid, full_path, TRUE); + } + + if ( pass ) { + sprintf(full_path, "%s/M", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_ctg_v(fid, full_path, TRUE); + } + + return; + +} /* create_zoo() */ + + +/*------------------------------------------------------------------------- + * Function: validate_zoo + * + * Purpose: Given the path to a group in which a "zoo" has been + * constructed, validate the objects in the "zoo". + * + * If pass is false on entry, do nothing. + * + * If an error is detected, set pass to FALSE, and set + * failure_mssg to point to an appropriate error message. + * + * This function was initially created to assist in testing + * the cache image feature of the metadata cache. Thus, it + * only concerns itself with the version 2 superblock, and + * on disk structures that can occur with this version of + * the superblock. + * + * Note the associated validate_zoo() function. + * + * Return: void + * + * Programmer: John Mainzer + * 9/14/15 + * + *------------------------------------------------------------------------- + */ + +void +validate_zoo(hid_t fid, const char *base_path, int proc_num) +{ + char full_path[1024]; + + HDassert(base_path); + + /* validate an empty "new style" group */ + if ( pass ) { + sprintf(full_path, "%s/A", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ns_grp_0(fid, full_path); + } + + /* validate a compact "new style" group (3 link messages) */ + if ( pass ) { + sprintf(full_path, "%s/B", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ns_grp_c(fid, full_path, 3); + } + + /* validate a dense "new style" group (w/300 links, in v2 B-tree & + * fractal heap) + */ + if ( pass ) { + sprintf(full_path, "%s/C", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ns_grp_d(fid, full_path, 300); + } + + /* validate an empty "old style" group in file */ + if ( pass ) { + sprintf(full_path, "%s/D", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_os_grp_0(fid, full_path); + } + + /* validate an "old style" group (w/300 links, in v1 B-tree & + * local heap) + */ + if ( pass ) { + sprintf(full_path, "%s/E", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_os_grp_n(fid, full_path, proc_num, 300); + } + + /* validate a contiguous dataset w/integer datatype (but no data) + * in file. + */ + if ( pass ) { + sprintf(full_path, "%s/F", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_ctg_i(fid, full_path, FALSE); + } + + /* validate a contiguous dataset w/integer datatype (with data) + * in file. + */ + if ( pass ) { + sprintf(full_path, "%s/G", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_ctg_i(fid, full_path, TRUE); + } + + /* validate a chunked dataset w/integer datatype (but no data) + * in file + */ + if ( pass ) { + sprintf(full_path, "%s/H", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_chk_i(fid, full_path, FALSE); + } + + /* validate a chunked dataset w/integer datatype (and data) + * in file + */ + if ( pass ) { + sprintf(full_path, "%s/I", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_chk_i(fid, full_path, TRUE); + } + + /* Validate a compact dataset w/integer datatype (but no data) + * in file + */ + if ( pass ) { + sprintf(full_path, "%s/J", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_cpt_i(fid, full_path, FALSE); + } + + /* validate a compact dataset w/integer datatype (and data) + * in file + */ + if ( pass ) { + sprintf(full_path, "%s/K", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_cpt_i(fid, full_path, TRUE); + } + + /* validate a contiguous dataset w/variable-length datatype + * (but no data) to file + */ + if ( pass ) { + sprintf(full_path, "%s/L", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_ctg_v(fid, full_path, FALSE); + } + + /* validate a contiguous dataset w/variable-length datatype + * (and data) to file + */ + if ( pass ) { + sprintf(full_path, "%s/M", base_path); + HDassert(strlen(full_path) < 1024); + vrfy_ds_ctg_v(fid, full_path, TRUE); + } + + return; + +} /* validate_zoo() */ + diff --git a/test/genall5.h b/test/genall5.h new file mode 100644 index 0000000..70b5a6f --- /dev/null +++ b/test/genall5.h @@ -0,0 +1,53 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Programmer: John Mainzer + * 9/4/15 + * + * This file contains declarations of all functions defined + * in genall5.c + */ + +void create_zoo(hid_t fid, const char *base_path, int proc_num); +void validate_zoo(hid_t fid, const char *base_path, int proc_num); + +void ns_grp_0(hid_t fid, const char *group_name); +void vrfy_ns_grp_0(hid_t fid, const char *group_name); + +void ns_grp_c(hid_t fid, const char *group_name, unsigned nlinks); +void vrfy_ns_grp_c(hid_t fid, const char *group_name, unsigned nlinks); + +void ns_grp_d(hid_t fid, const char *group_name, unsigned nlinks); +void vrfy_ns_grp_d(hid_t fid, const char *group_name, unsigned nlinks); + +void os_grp_0(hid_t fid, const char *group_name); +void vrfy_os_grp_0(hid_t fid, const char *group_name); + +void os_grp_n(hid_t fid, const char *group_name, int proc_num, unsigned nlinks); +void vrfy_os_grp_n(hid_t fid, const char *group_name, int proc_num, + unsigned nlinks); + +void ds_ctg_i(hid_t fid, const char *dset_name, hbool_t write_data); +void vrfy_ds_ctg_i(hid_t fid, const char *dset_name, hbool_t write_data); + +void ds_chk_i(hid_t fid, const char *dset_name, hbool_t write_data); +void vrfy_ds_chk_i(hid_t fid, const char *dset_name, hbool_t write_data); + +void ds_cpt_i(hid_t fid, const char *dset_name, hbool_t write_data); +void vrfy_ds_cpt_i(hid_t fid, const char *dset_name, hbool_t write_data); + +void ds_ctg_v(hid_t fid, const char *dset_name, hbool_t write_data); +void vrfy_ds_ctg_v(hid_t fid, const char *dset_name, hbool_t write_data); + -- cgit v0.12