/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*------------------------------------------------------------------------- * * Created: H5AC.c * * Purpose: Functions in this file implement a cache for * things which exist on disk. All "things" associated * with a particular HDF file share the same cache; each * HDF file has it's own cache. * *------------------------------------------------------------------------- */ /****************/ /* Module Setup */ /****************/ #include "H5ACmodule.h" /* This source code file is part of the H5AC module */ #define H5C_FRIEND /* Suppress error about including H5Cpkg */ #define H5F_FRIEND /* Suppress error about including H5Fpkg */ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5ACpkg.h" /* Metadata cache */ #include "H5Clog.h" /* Cache logging */ #include "H5Cpkg.h" /* Cache */ #include "H5CXprivate.h" /* API Contexts */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fpkg.h" /* Files */ #include "H5Iprivate.h" /* IDs */ #include "H5Pprivate.h" /* Property lists */ #include "H5SLprivate.h" /* Skip Lists */ /****************/ /* Local Macros */ /****************/ /******************/ /* Local Typedefs */ /******************/ /********************/ /* Local Prototypes */ /********************/ static herr_t H5AC__check_if_write_permitted(const H5F_t *f, bool *write_permitted_ptr); static herr_t H5AC__ext_config_2_int_config(const H5AC_cache_config_t *ext_conf_ptr, H5C_auto_size_ctl_t *int_conf_ptr); #if H5AC_DO_TAGGING_SANITY_CHECKS static herr_t H5AC__verify_tag(const H5AC_class_t *type); #endif /* H5AC_DO_TAGGING_SANITY_CHECKS */ /*********************/ /* Package Variables */ /*********************/ /*****************************/ /* Library Private Variables */ /*****************************/ #ifdef H5_HAVE_PARALLEL /* Environment variable for collective API sanity checks */ bool H5_coll_api_sanity_check_g = false; #endif /* H5_HAVE_PARALLEL */ /*******************/ /* Local Variables */ /*******************/ /* Metadata entry class list */ /* Remember to add new type ID to the H5AC_type_t enum in H5ACprivate.h when * adding a new class. */ static const H5AC_class_t *const H5AC_class_s[] = { H5AC_BT, /* ( 0) B-tree nodes */ H5AC_SNODE, /* ( 1) symbol table nodes */ H5AC_LHEAP_PRFX, /* ( 2) local heap prefix */ H5AC_LHEAP_DBLK, /* ( 3) local heap data block */ H5AC_GHEAP, /* ( 4) global heap */ H5AC_OHDR, /* ( 5) object header */ H5AC_OHDR_CHK, /* ( 6) object header chunk */ H5AC_BT2_HDR, /* ( 7) v2 B-tree header */ H5AC_BT2_INT, /* ( 8) v2 B-tree internal node */ H5AC_BT2_LEAF, /* ( 9) v2 B-tree leaf node */ H5AC_FHEAP_HDR, /* (10) fractal heap header */ H5AC_FHEAP_DBLOCK, /* (11) fractal heap direct block */ H5AC_FHEAP_IBLOCK, /* (12) fractal heap indirect block */ H5AC_FSPACE_HDR, /* (13) free space header */ H5AC_FSPACE_SINFO, /* (14) free space sections */ H5AC_SOHM_TABLE, /* (15) shared object header message master table */ H5AC_SOHM_LIST, /* (16) shared message index stored as a list */ H5AC_EARRAY_HDR, /* (17) extensible array header */ H5AC_EARRAY_IBLOCK, /* (18) extensible array index block */ H5AC_EARRAY_SBLOCK, /* (19) extensible array super block */ H5AC_EARRAY_DBLOCK, /* (20) extensible array data block */ H5AC_EARRAY_DBLK_PAGE, /* (21) extensible array data block page */ H5AC_FARRAY_HDR, /* (22) fixed array header */ H5AC_FARRAY_DBLOCK, /* (23) fixed array data block */ H5AC_FARRAY_DBLK_PAGE, /* (24) fixed array data block page */ H5AC_SUPERBLOCK, /* (25) file superblock */ H5AC_DRVRINFO, /* (26) driver info block (supplements superblock) */ H5AC_EPOCH_MARKER, /* (27) epoch marker - always internal to cache */ H5AC_PROXY_ENTRY, /* (28) cache entry proxy */ H5AC_PREFETCHED_ENTRY /* (29) prefetched entry - always internal to cache */ }; /*------------------------------------------------------------------------- * Function: H5AC_init * * Purpose: Initialize the interface from some other layer. * * Return: Success: non-negative * Failure: negative * *------------------------------------------------------------------------- */ herr_t H5AC_init(void) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOERR #ifdef H5_HAVE_PARALLEL /* check whether to enable strict collective function calling * sanity checks using MPI barriers */ { const char *s; /* String for environment variables */ s = getenv("H5_COLL_API_SANITY_CHECK"); if (s && isdigit(*s)) { long env_val = strtol(s, NULL, 0); H5_coll_api_sanity_check_g = (0 == env_val) ? false : true; } } #endif /* H5_HAVE_PARALLEL */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5AC_init() */ /*------------------------------------------------------------------------- * Function: H5AC_term_package * * Purpose: Terminate this interface. * * Return: Success: Positive if anything was done that might * affect other interfaces; zero otherwise. * Failure: Negative. * *------------------------------------------------------------------------- */ int H5AC_term_package(void) { FUNC_ENTER_NOAPI_NOINIT_NOERR FUNC_LEAVE_NOAPI(0) } /* end H5AC_term_package() */ /*------------------------------------------------------------------------- * * Function: H5AC_cache_image_pending() * * Purpose: Debugging function that tests to see if the load of a * metadata cache image load is pending (i.e. will be executed * on the next protect or insert) * * Returns true if a cache image load is pending, and false * if not. Throws an assertion failure on error. * * Return: true if a cache image load is pending, and false otherwise. * *------------------------------------------------------------------------- */ bool H5AC_cache_image_pending(const H5F_t *f) { H5C_t *cache_ptr; bool ret_value = false; /* Return value */ FUNC_ENTER_NOAPI_NOINIT_NOERR /* Sanity checks */ assert(f); assert(f->shared); cache_ptr = f->shared->cache; ret_value = H5C_cache_image_pending(cache_ptr); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_cache_image_pending() */ /*------------------------------------------------------------------------- * Function: H5AC_create * * Purpose: Initialize the cache just after a file is opened. The * SIZE_HINT is the number of cache slots desired. If you * pass an invalid value then H5AC_NSLOTS is used. You can * turn off caching by using 1 for the SIZE_HINT value. * * Return: Success: Number of slots actually used. * * Failure: Negative * *------------------------------------------------------------------------- */ herr_t H5AC_create(const H5F_t *f, H5AC_cache_config_t *config_ptr, H5AC_cache_image_config_t *image_config_ptr) { #ifdef H5_HAVE_PARALLEL char prefix[H5C__PREFIX_LEN] = ""; H5AC_aux_t *aux_ptr = NULL; #endif /* H5_HAVE_PARALLEL */ struct H5C_cache_image_ctl_t int_ci_config = H5C__DEFAULT_CACHE_IMAGE_CTL; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Check arguments */ assert(f); assert(NULL == f->shared->cache); assert(config_ptr != NULL); assert(image_config_ptr != NULL); assert(image_config_ptr->version == H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION); HDcompile_assert(NELMTS(H5AC_class_s) == H5AC_NTYPES); HDcompile_assert(H5C__MAX_NUM_TYPE_IDS == H5AC_NTYPES); /* Validate configurations */ if (H5AC_validate_config(config_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad cache configuration"); if (H5AC_validate_cache_image_config(image_config_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad cache image configuration"); #ifdef H5_HAVE_PARALLEL if (H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) { MPI_Comm mpi_comm; int mpi_rank; int mpi_size; if (MPI_COMM_NULL == (mpi_comm = H5F_mpi_get_comm(f))) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get MPI communicator"); if ((mpi_rank = H5F_mpi_get_rank(f)) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get mpi rank"); if ((mpi_size = H5F_mpi_get_size(f)) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get mpi size"); if (NULL == (aux_ptr = H5FL_CALLOC(H5AC_aux_t))) HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "Can't allocate H5AC auxiliary structure"); aux_ptr->mpi_comm = mpi_comm; aux_ptr->mpi_rank = mpi_rank; aux_ptr->mpi_size = mpi_size; aux_ptr->write_permitted = false; aux_ptr->dirty_bytes_threshold = H5AC__DEFAULT_DIRTY_BYTES_THRESHOLD; aux_ptr->dirty_bytes = 0; aux_ptr->metadata_write_strategy = H5AC__DEFAULT_METADATA_WRITE_STRATEGY; #ifdef H5AC_DEBUG_DIRTY_BYTES_CREATION aux_ptr->dirty_bytes_propagations = 0; aux_ptr->unprotect_dirty_bytes = 0; aux_ptr->unprotect_dirty_bytes_updates = 0; aux_ptr->insert_dirty_bytes = 0; aux_ptr->insert_dirty_bytes_updates = 0; aux_ptr->move_dirty_bytes = 0; aux_ptr->move_dirty_bytes_updates = 0; #endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */ aux_ptr->d_slist_ptr = NULL; aux_ptr->c_slist_ptr = NULL; aux_ptr->candidate_slist_ptr = NULL; aux_ptr->write_done = NULL; aux_ptr->sync_point_done = NULL; aux_ptr->p0_image_len = 0; snprintf(prefix, sizeof(prefix), "%d:", mpi_rank); if (mpi_rank == 0) { if (NULL == (aux_ptr->d_slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL))) HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create dirtied entry list"); if (NULL == (aux_ptr->c_slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL))) HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create cleaned entry list"); } /* end if */ /* construct the candidate skip list for all processes. * when the distributed strategy is selected as all processes * will use it in the case of a flush. */ if (NULL == (aux_ptr->candidate_slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL))) HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create candidate entry list"); if (aux_ptr->mpi_rank == 0) f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE, H5AC__DEFAULT_MIN_CLEAN_SIZE, (H5AC_NTYPES - 1), H5AC_class_s, H5AC__check_if_write_permitted, true, H5AC__log_flushed_entry, (void *)aux_ptr); else f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE, H5AC__DEFAULT_MIN_CLEAN_SIZE, (H5AC_NTYPES - 1), H5AC_class_s, H5AC__check_if_write_permitted, true, NULL, (void *)aux_ptr); } /* end if */ else { #endif /* H5_HAVE_PARALLEL */ /* The default max cache size and min clean size will frequently be * overwritten shortly by the subsequent set resize config call. * -- JRM */ f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE, H5AC__DEFAULT_MIN_CLEAN_SIZE, (H5AC_NTYPES - 1), H5AC_class_s, H5AC__check_if_write_permitted, true, NULL, NULL); #ifdef H5_HAVE_PARALLEL } /* end else */ #endif /* H5_HAVE_PARALLEL */ if (NULL == f->shared->cache) HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed"); #ifdef H5_HAVE_PARALLEL if (aux_ptr != NULL) if (H5C_set_prefix(f->shared->cache, prefix) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "H5C_set_prefix() failed"); #endif /* H5_HAVE_PARALLEL */ /* Turn on metadata cache logging, if being used * This will be JSON until we create a special API call. Trace output * is generated when logging is controlled by the struct. */ if (H5F_USE_MDC_LOGGING(f)) if (H5C_log_set_up(f->shared->cache, H5F_MDC_LOG_LOCATION(f), H5C_LOG_STYLE_JSON, H5F_START_MDC_LOG_ON_ACCESS(f)) < 0) HGOTO_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "mdc logging setup failed"); /* Set the cache parameters */ if (H5AC_set_cache_auto_resize_config(f->shared->cache, config_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "auto resize configuration failed"); /* Don't need to get the current H5C image config here since the * cache has just been created, and thus f->shared->cache->image_ctl * must still set to its initial value (H5C__DEFAULT_CACHE_IMAGE_CTL). * Note that this not true as soon as control returns to the application * program, as some test code modifies f->shared->cache->image_ctl. */ int_ci_config.version = image_config_ptr->version; int_ci_config.generate_image = image_config_ptr->generate_image; int_ci_config.save_resize_status = image_config_ptr->save_resize_status; int_ci_config.entry_ageout = image_config_ptr->entry_ageout; if (H5C_set_cache_image_config(f, f->shared->cache, &int_ci_config) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "auto resize configuration failed"); done: /* If currently logging, generate a message */ if (f->shared->cache->log_info->logging) if (H5C_log_write_create_cache_msg(f->shared->cache, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); #ifdef H5_HAVE_PARALLEL /* if there is a failure, try to tidy up the auxiliary structure */ if (ret_value < 0) { if (aux_ptr != NULL) { if (aux_ptr->d_slist_ptr != NULL) H5SL_close(aux_ptr->d_slist_ptr); if (aux_ptr->c_slist_ptr != NULL) H5SL_close(aux_ptr->c_slist_ptr); if (aux_ptr->candidate_slist_ptr != NULL) H5SL_close(aux_ptr->candidate_slist_ptr); aux_ptr = H5FL_FREE(H5AC_aux_t, aux_ptr); } /* end if */ } /* end if */ #endif /* H5_HAVE_PARALLEL */ FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_create() */ /*------------------------------------------------------------------------- * Function: H5AC_dest * * Purpose: Flushes all data to disk and destroys the cache. * This function fails if any object are protected since the * resulting file might not be consistent. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_dest(H5F_t *f) { bool log_enabled; /* true if logging was set up */ bool curr_logging; /* true if currently logging */ #ifdef H5_HAVE_PARALLEL H5AC_aux_t *aux_ptr = NULL; #endif /* H5_HAVE_PARALLEL */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(f); assert(f->shared); assert(f->shared->cache); #if H5AC_DUMP_STATS_ON_CLOSE /* Dump debugging info */ H5AC_stats(f); #endif /* H5AC_DUMP_STATS_ON_CLOSE */ /* Check if log messages are being emitted */ if (H5C_get_logging_status(f->shared->cache, &log_enabled, &curr_logging) < 0) HGOTO_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to get logging status"); /* Tear down logging */ if (log_enabled) { if (curr_logging) if (H5C_log_write_destroy_cache_msg(f->shared->cache) < 0) HGOTO_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); if (H5C_log_tear_down(f->shared->cache) < 0) HGOTO_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "metadata cache logging tear-down failed"); } /* end if */ #ifdef H5_HAVE_PARALLEL /* destroying the cache, so clear all collective entries */ if (H5C_clear_coll_entries(f->shared->cache, false) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "can't clear collective entries"); aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(f->shared->cache); if (aux_ptr) { /* If the file was opened R/W, attempt to flush all entries * from rank 0 & Bcast clean list to other ranks. * * Must not flush in the R/O case, as this will trigger the * free space manager settle routines. * * Must also enable the skip list before the call to * H5AC__flush_entries() and disable it afterwards, as the * skip list will be disabled after the previous flush. * * Note that H5C_dest() does skip list setup and take down as well. * Unfortunately, we can't do the setup and take down just once, * as H5C_dest() is called directly in the test code. * * Fortunately, the cache should be clean or close to it at this * point, so the overhead should be minimal. */ if (H5F_ACC_RDWR & H5F_INTENT(f)) { /* enable and load the skip list */ if (H5C_set_slist_enabled(f->shared->cache, true, false) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't enable skip list"); if (H5AC__flush_entries(f) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush"); /* disable the skip list -- should be empty */ if (H5C_set_slist_enabled(f->shared->cache, false, false) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't disable skip list"); } /* end if */ } /* end if */ #endif /* H5_HAVE_PARALLEL */ /* Destroy the cache */ if (H5C_dest(f) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "can't destroy cache"); f->shared->cache = NULL; #ifdef H5_HAVE_PARALLEL if (aux_ptr != NULL) { if (aux_ptr->d_slist_ptr != NULL) { assert(H5SL_count(aux_ptr->d_slist_ptr) == 0); H5SL_close(aux_ptr->d_slist_ptr); } /* end if */ if (aux_ptr->c_slist_ptr != NULL) { assert(H5SL_count(aux_ptr->c_slist_ptr) == 0); H5SL_close(aux_ptr->c_slist_ptr); } /* end if */ if (aux_ptr->candidate_slist_ptr != NULL) { assert(H5SL_count(aux_ptr->candidate_slist_ptr) == 0); H5SL_close(aux_ptr->candidate_slist_ptr); } /* end if */ aux_ptr = H5FL_FREE(H5AC_aux_t, aux_ptr); } /* end if */ #endif /* H5_HAVE_PARALLEL */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_dest() */ /*------------------------------------------------------------------------- * Function: H5AC_evict * * Purpose: Evict all entries except the pinned entries * in the cache. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_evict(H5F_t *f) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(f); assert(f->shared); assert(f->shared->cache); /* Evict all entries in the cache except the pinned superblock entry */ if (H5C_evict(f) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "can't evict cache"); done: /* If currently logging, generate a message */ if (f->shared->cache->log_info->logging) if (H5C_log_write_evict_cache_msg(f->shared->cache, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_evict() */ /*------------------------------------------------------------------------- * Function: H5AC_expunge_entry * * Purpose: Expunge the target entry from the cache without writing it * to disk even if it is dirty. The entry must not be either * pinned or protected. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_expunge_entry(H5F_t *f, const H5AC_class_t *type, haddr_t addr, unsigned flags) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared); assert(f->shared->cache); assert(type); assert(type->serialize); assert(H5_addr_defined(addr)); if (H5C_expunge_entry(f, type, addr, flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "H5C_expunge_entry() failed"); done: /* If currently logging, generate a message */ if (f->shared->cache->log_info->logging) if (H5C_log_write_expunge_entry_msg(f->shared->cache, addr, type->id, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_expunge_entry() */ /*------------------------------------------------------------------------- * Function: H5AC_flush * * Purpose: Flush (and possibly destroy) the metadata cache associated * with the specified file. * * If the cache contains protected entries, the function will * fail, as protected entries cannot be flushed. However * all unprotected entries should be flushed before the * function returns failure. * * Return: Non-negative on success/Negative on failure if there was a * request to flush all items and something was protected. * *------------------------------------------------------------------------- */ herr_t H5AC_flush(H5F_t *f) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared); assert(f->shared->cache); #ifdef H5_HAVE_PARALLEL /* flushing the cache, so clear all collective entries */ if (H5C_clear_coll_entries(f->shared->cache, false) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5C_clear_coll_entries() failed"); /* Attempt to flush all entries from rank 0 & Bcast clean list to other ranks */ if (H5AC__flush_entries(f) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush"); #endif /* H5_HAVE_PARALLEL */ /* Flush the cache */ /* (Again, in parallel - writes out the superblock) */ if (H5C_flush_cache(f, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush cache"); done: /* If currently logging, generate a message */ if (f->shared->cache->log_info->logging) if (H5C_log_write_flush_cache_msg(f->shared->cache, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_flush() */ /*------------------------------------------------------------------------- * Function: H5AC_get_entry_status * * Purpose: Given a file address, determine whether the metadata * cache contains an entry at that location. If it does, * also determine whether the entry is dirty, protected, * pinned, etc. and return that information to the caller * in *status. * * If the specified entry doesn't exist, set *status_ptr * to zero. * * On error, the value of *status is undefined. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_get_entry_status(const H5F_t *f, haddr_t addr, unsigned *status) { bool in_cache; /* Entry @ addr is in the cache */ bool is_dirty; /* Entry @ addr is in the cache and dirty */ bool is_protected; /* Entry @ addr is in the cache and protected */ bool is_pinned; /* Entry @ addr is in the cache and pinned */ bool is_corked; bool is_flush_dep_child; /* Entry @ addr is in the cache and is a flush dependency child */ bool is_flush_dep_parent; /* Entry @ addr is in the cache and is a flush dependency parent */ bool image_is_up_to_date; /* Entry @ addr is in the cache and has an up to date image */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if ((f == NULL) || (!H5_addr_defined(addr)) || (status == NULL)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad param(s) on entry"); if (H5C_get_entry_status(f, addr, NULL, &in_cache, &is_dirty, &is_protected, &is_pinned, &is_corked, &is_flush_dep_parent, &is_flush_dep_child, &image_is_up_to_date) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_entry_status() failed"); if (in_cache) { *status |= H5AC_ES__IN_CACHE; if (is_dirty) *status |= H5AC_ES__IS_DIRTY; if (is_protected) *status |= H5AC_ES__IS_PROTECTED; if (is_pinned) *status |= H5AC_ES__IS_PINNED; if (is_corked) *status |= H5AC_ES__IS_CORKED; if (is_flush_dep_parent) *status |= H5AC_ES__IS_FLUSH_DEP_PARENT; if (is_flush_dep_child) *status |= H5AC_ES__IS_FLUSH_DEP_CHILD; if (image_is_up_to_date) *status |= H5AC_ES__IMAGE_IS_UP_TO_DATE; } /* end if */ else *status = 0; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_get_entry_status() */ /*------------------------------------------------------------------------- * Function: H5AC_insert_entry * * Purpose: Adds the specified thing to the cache. The thing need not * exist on disk yet, but it must have an address and disk * space reserved. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_insert_entry(H5F_t *f, const H5AC_class_t *type, haddr_t addr, void *thing, unsigned int flags) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared); assert(f->shared->cache); assert(type); assert(type->serialize); assert(H5_addr_defined(addr)); assert(thing); /* Check for invalid access request */ if (0 == (H5F_INTENT(f) & H5F_ACC_RDWR)) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "no write intent on file"); #if H5AC_DO_TAGGING_SANITY_CHECKS if (!H5C_get_ignore_tags(f->shared->cache) && H5AC__verify_tag(type) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "Bad tag value"); #endif /* H5AC_DO_TAGGING_SANITY_CHECKS */ /* Insert entry into metadata cache */ if (H5C_insert_entry(f, type, addr, thing, flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5C_insert_entry() failed"); #ifdef H5_HAVE_PARALLEL { H5AC_aux_t *aux_ptr; if (NULL != (aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(f->shared->cache))) { /* Log the new entry */ if (H5AC__log_inserted_entry((H5AC_info_t *)thing) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5AC__log_inserted_entry() failed"); /* Check if we should try to flush */ if (aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold) if (H5AC__run_sync_point(f, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point"); } /* end if */ } #endif /* H5_HAVE_PARALLEL */ done: /* If currently logging, generate a message */ if (f->shared->cache->log_info->logging) if (H5C_log_write_insert_entry_msg(f->shared->cache, addr, type->id, flags, ((H5C_cache_entry_t *)thing)->size, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_insert_entry() */ /*------------------------------------------------------------------------- * Function: H5AC_load_cache_image_on_next_protect * * Purpose: 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 * *------------------------------------------------------------------------- */ herr_t H5AC_load_cache_image_on_next_protect(H5F_t *f, haddr_t addr, hsize_t len, bool rw) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared); assert(f->shared->cache); if (H5C_load_cache_image_on_next_protect(f, addr, len, rw) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, FAIL, "call to H5C_load_cache_image_on_next_protect failed"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_load_cache_image_on_next_protect() */ /*------------------------------------------------------------------------- * Function: H5AC_mark_entry_dirty * * Purpose: Mark a pinned or protected entry as dirty. The target * entry MUST be either pinned, protected, or both. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_mark_entry_dirty(void *thing) { H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(thing); /* Set up entry & cache pointers */ entry_ptr = (H5AC_info_t *)thing; cache_ptr = entry_ptr->cache_ptr; #ifdef H5_HAVE_PARALLEL { H5AC_aux_t *aux_ptr; aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr); if ((!entry_ptr->is_dirty) && (!entry_ptr->is_protected) && (entry_ptr->is_pinned) && (NULL != aux_ptr)) if (H5AC__log_dirtied_entry(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't log dirtied entry"); } #endif /* H5_HAVE_PARALLEL */ if (H5C_mark_entry_dirty(thing) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't mark pinned or protected entry dirty"); done: /* If currently logging, generate a message */ if (cache_ptr != NULL && cache_ptr->log_info != NULL) if (cache_ptr->log_info->logging) if (H5C_log_write_mark_entry_dirty_msg(cache_ptr, entry_ptr, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_mark_entry_dirty() */ /*------------------------------------------------------------------------- * Function: H5AC_mark_entry_clean * * Purpose: Mark a pinned entry as clean. The target * entry MUST be pinned. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_mark_entry_clean(void *thing) { H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(thing); entry_ptr = (H5AC_info_t *)thing; cache_ptr = entry_ptr->cache_ptr; #ifdef H5_HAVE_PARALLEL { H5AC_aux_t *aux_ptr; aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr); if ((!entry_ptr->is_dirty) && (!entry_ptr->is_protected) && (entry_ptr->is_pinned) && (NULL != aux_ptr)) if (H5AC__log_cleaned_entry(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "can't log cleaned entry"); } #endif /* H5_HAVE_PARALLEL */ if (H5C_mark_entry_clean(thing) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "can't mark pinned or protected entry clean"); done: /* If currently logging, generate a message */ if (cache_ptr != NULL && cache_ptr->log_info != NULL) if (cache_ptr->log_info->logging) if (H5C_log_write_mark_entry_clean_msg(cache_ptr, entry_ptr, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_mark_entry_clean() */ /*------------------------------------------------------------------------- * Function: H5AC_mark_entry_unserialized * * Purpose: Mark a pinned or protected entry as unserialized. The target * entry MUST be either pinned, protected, or both. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_mark_entry_unserialized(void *thing) { H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(thing); /* Set up entry & cache pointers */ entry_ptr = (H5AC_info_t *)thing; cache_ptr = entry_ptr->cache_ptr; if (H5C_mark_entry_unserialized(thing) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKUNSERIALIZED, FAIL, "can't mark entry unserialized"); done: /* If currently logging, generate a message */ if (cache_ptr != NULL && cache_ptr->log_info != NULL) if (cache_ptr->log_info->logging) if (H5C_log_write_mark_unserialized_entry_msg(cache_ptr, entry_ptr, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_mark_entry_unserialized() */ /*------------------------------------------------------------------------- * Function: H5AC_mark_entry_serialized * * Purpose: Mark a pinned entry as serialized. The target * entry MUST be pinned. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_mark_entry_serialized(void *thing) { H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(thing); entry_ptr = (H5AC_info_t *)thing; cache_ptr = entry_ptr->cache_ptr; if (H5C_mark_entry_serialized(thing) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKSERIALIZED, FAIL, "can't mark entry serialized"); done: /* If currently logging, generate a message */ if (cache_ptr != NULL && cache_ptr->log_info != NULL) if (cache_ptr->log_info->logging) if (H5C_log_write_mark_serialized_entry_msg(cache_ptr, entry_ptr, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_mark_entry_serialized() */ /*------------------------------------------------------------------------- * Function: H5AC_move_entry * * Purpose: Use this function to notify the cache that an object's * file address changed. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_move_entry(H5F_t *f, const H5AC_class_t *type, haddr_t old_addr, haddr_t new_addr) { #ifdef H5_HAVE_PARALLEL H5AC_aux_t *aux_ptr; #endif /* H5_HAVE_PARALLEL */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared->cache); assert(type); assert(H5_addr_defined(old_addr)); assert(H5_addr_defined(new_addr)); assert(H5_addr_ne(old_addr, new_addr)); #ifdef H5_HAVE_PARALLEL /* Log moving the entry */ if (NULL != (aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(f->shared->cache))) if (H5AC__log_moved_entry(f, old_addr, new_addr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "can't log moved entry"); #endif /* H5_HAVE_PARALLEL */ if (H5C_move_entry(f->shared->cache, type, old_addr, new_addr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMOVE, FAIL, "H5C_move_entry() failed"); #ifdef H5_HAVE_PARALLEL /* Check if we should try to flush */ if (NULL != aux_ptr && aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold) if (H5AC__run_sync_point(f, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point"); #endif /* H5_HAVE_PARALLEL */ done: /* If currently logging, generate a message */ if (f->shared->cache->log_info->logging) if (H5C_log_write_move_entry_msg(f->shared->cache, old_addr, new_addr, type->id, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_move_entry() */ /*------------------------------------------------------------------------- * Function: H5AC_pin_protected_entry() * * Purpose: Pin a protected cache entry. The entry must be protected * at the time of call, and must be unpinned. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_pin_protected_entry(void *thing) { H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(thing); entry_ptr = (H5AC_info_t *)thing; cache_ptr = entry_ptr->cache_ptr; assert(cache_ptr); /* Pin entry */ if (H5C_pin_protected_entry(thing) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "can't pin entry"); done: /* If currently logging, generate a message */ if (cache_ptr != NULL && cache_ptr->log_info != NULL) if (cache_ptr->log_info->logging) if (H5C_log_write_pin_entry_msg(cache_ptr, entry_ptr, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_pin_protected_entry() */ /*------------------------------------------------------------------------- * * Function: H5AC_prep_for_file_close * * Purpose: This function should be called just prior to the cache * flushes at file close. * * The objective of the call is to allow the metadata cache * to do any preparatory work prior to generation of a * cache image. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_prep_for_file_close(H5F_t *f) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared); assert(f->shared->cache); if (H5C_prep_for_file_close(f) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "cache prep for file close failed"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_prep_for_file_close() */ /*------------------------------------------------------------------------- * * Function: H5AC_prep_for_file_flush * * Purpose: Handle any setup required prior to metadata cache flush. * * This function should be called just prior to the first * call to H5AC_flush() during a file flush. * * Initially, this means setting up the skip list prior to the * flush. We do this in a separate call because * H5F__flush_phase2() make repeated calls to H5AC_flush(). * Handling this detail in separate calls allows us to avoid * the overhead of setting up and taking down the skip list * repeatedly. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_prep_for_file_flush(H5F_t *f) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared); assert(f->shared->cache); if (H5C_set_slist_enabled(f->shared->cache, true, false) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't enable skip list"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_prep_for_file_flush() */ /*------------------------------------------------------------------------- * * Function: H5AC_secure_from_file_flush * * Purpose: This function should be called just after the last * call to H5AC_flush() during a file flush. * * The objective of the call is to allow the metadata cache * to do any necessary necessary cleanup work after a cache * flush. * * Initially, this means taking down the skip list after the * flush. We do this in a separate call because * H5F__flush_phase2() make repeated calls to H5AC_flush(). * Handling this detail in separate calls allows us to avoid * the overhead of setting up and taking down the skip list * repeatedly. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_secure_from_file_flush(H5F_t *f) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared); assert(f->shared->cache); if (H5C_set_slist_enabled(f->shared->cache, false, false) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't disable skip list"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_secure_from_file_flush() */ /*------------------------------------------------------------------------- * * Function: H5AC_create_flush_dependency() * * Purpose: Create a flush dependency between two entries in the metadata * cache. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_create_flush_dependency(void *parent_thing, void *child_thing) { H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(parent_thing); assert(child_thing); entry_ptr = (H5AC_info_t *)parent_thing; cache_ptr = entry_ptr->cache_ptr; assert(cache_ptr); /* Create the flush dependency */ if (H5C_create_flush_dependency(parent_thing, child_thing) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "H5C_create_flush_dependency() failed"); done: /* If currently logging, generate a message */ if (cache_ptr != NULL && cache_ptr->log_info != NULL) if (cache_ptr->log_info->logging) if (H5C_log_write_create_fd_msg(cache_ptr, (H5AC_info_t *)parent_thing, (H5AC_info_t *)child_thing, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_create_flush_dependency() */ /*------------------------------------------------------------------------- * Function: H5AC_protect * * Purpose: If the target entry is not in the cache, load it. If * necessary, attempt to evict one or more entries to keep * the cache within its maximum size. * * Mark the target entry as protected, and return its address * to the caller. The caller must call H5AC_unprotect() when * finished with the entry. * * While it is protected, the entry may not be either evicted * or flushed -- nor may it be accessed by another call to * H5AC_protect. Any attempt to do so will result in a failure. * * Return: Success: Ptr to the object. * Failure: NULL * *------------------------------------------------------------------------- */ void * H5AC_protect(H5F_t *f, const H5AC_class_t *type, haddr_t addr, void *udata, unsigned flags) { void *thing = NULL; /* Pointer to native data structure for entry */ void *ret_value = NULL; /* Return value */ FUNC_ENTER_NOAPI(NULL) /* Sanity check */ assert(f); assert(f->shared); assert(f->shared->cache); assert(type); assert(type->serialize); assert(H5_addr_defined(addr)); /* Check for unexpected flags -- H5C__FLUSH_COLLECTIVELY_FLAG * only permitted in the parallel case. */ #ifdef H5_HAVE_PARALLEL assert(0 == (flags & (unsigned)(~(H5C__READ_ONLY_FLAG | H5C__FLUSH_LAST_FLAG | H5C__FLUSH_COLLECTIVELY_FLAG)))); #else /* H5_HAVE_PARALLEL */ assert(0 == (flags & (unsigned)(~(H5C__READ_ONLY_FLAG | H5C__FLUSH_LAST_FLAG)))); #endif /* H5_HAVE_PARALLEL */ /* Check for invalid access request */ if ((0 == (H5F_INTENT(f) & H5F_ACC_RDWR)) && (0 == (flags & H5C__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "no write intent on file"); #if H5AC_DO_TAGGING_SANITY_CHECKS if (!H5C_get_ignore_tags(f->shared->cache) && H5AC__verify_tag(type) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, NULL, "Bad tag value"); #endif /* H5AC_DO_TAGGING_SANITY_CHECKS */ if (NULL == (thing = H5C_protect(f, type, addr, udata, flags))) HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C_protect() failed"); /* Set return value */ ret_value = thing; done: /* If currently logging, generate a message */ { herr_t fake_ret_value = (NULL == ret_value) ? FAIL : SUCCEED; if (f->shared->cache->log_info->logging) if (H5C_log_write_protect_entry_msg(f->shared->cache, (H5AC_info_t *)thing, type->id, flags, fake_ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, NULL, "unable to emit log message"); } FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_protect() */ /*------------------------------------------------------------------------- * Function: H5AC_resize_entry * * Purpose: Resize a pinned or protected entry. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_resize_entry(void *thing, size_t new_size) { H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(thing); entry_ptr = (H5AC_info_t *)thing; cache_ptr = entry_ptr->cache_ptr; assert(cache_ptr); #ifdef H5_HAVE_PARALLEL /* Log the generation of dirty bytes of metadata iff: * * 1) The entry is clean on entry, and this resize will dirty it * (i.e. the current and new sizes are different), and * * 2) This is a parallel computation -- which it is if the aux_ptr * is non-null. * * A few points to note about this section of the code: * * 1) This call must occur before the call to H5C_resize_entry() since * H5AC__log_dirtied_entry() expects the target entry to be clean * on entry. * * 2) This code has some basic issues in terms of the number of bytes * added to the dirty bytes count. * * First, it adds the initial entry size to aux_ptr->dirty_bytes, * not the final size. Note that this code used to use the final * size, but code to support this has been removed from * H5AC__log_dirtied_entry() for reasons unknown since I wrote this * code. * * As long as all ranks do the same thing here, this probably doesn't * matter much, although it will delay initiation of sync points. * * A more interesting point is that this code will not increment * aux_ptr->dirty_bytes if a dirty entry is resized. At first glance * this seems major, as particularly with the older file formats, * resizes can be quite large. However, this is probably not an * issue either, since such resizes will be accompanied by large * amounts of dirty metadata creation in other areas -- which will * cause aux_ptr->dirty_bytes to be incremented. * */ if ((!entry_ptr->is_dirty) && (entry_ptr->size != new_size)) { /* the entry is clean, and will be marked dirty in the resize * operation. */ H5AC_aux_t *aux_ptr; aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr); if (NULL != aux_ptr) { if (H5AC__log_dirtied_entry(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't log dirtied entry"); } } #endif /* H5_HAVE_PARALLEL */ /* Resize the entry */ if (H5C_resize_entry(thing, new_size) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTRESIZE, FAIL, "can't resize entry"); done: /* If currently logging, generate a message */ if (cache_ptr != NULL && cache_ptr->log_info != NULL) if (cache_ptr->log_info->logging) if (H5C_log_write_resize_entry_msg(cache_ptr, entry_ptr, new_size, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_resize_entry() */ /*------------------------------------------------------------------------- * Function: H5AC_unpin_entry() * * Purpose: Unpin a cache entry. The entry must be unprotected at * the time of call, and must be pinned. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_unpin_entry(void *thing) { H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(thing); entry_ptr = (H5AC_info_t *)thing; cache_ptr = entry_ptr->cache_ptr; assert(cache_ptr); /* Unpin the entry */ if (H5C_unpin_entry(thing) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "can't unpin entry"); done: /* If currently logging, generate a message */ if (cache_ptr != NULL && cache_ptr->log_info != NULL) if (cache_ptr->log_info->logging) if (H5C_log_write_unpin_entry_msg(cache_ptr, entry_ptr, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_unpin_entry() */ /*------------------------------------------------------------------------- * Function: H5AC_destroy_flush_dependency() * * Purpose: Destroy a flush dependency between two entries. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_destroy_flush_dependency(void *parent_thing, void *child_thing) { H5AC_info_t *entry_ptr = NULL; /* Pointer to the cache entry */ H5C_t *cache_ptr = NULL; /* Pointer to the entry's associated metadata cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(parent_thing); assert(child_thing); entry_ptr = (H5AC_info_t *)parent_thing; cache_ptr = entry_ptr->cache_ptr; assert(cache_ptr); /* Destroy the flush dependency */ if (H5C_destroy_flush_dependency(parent_thing, child_thing) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "H5C_destroy_flush_dependency() failed"); done: /* If currently logging, generate a message */ if (cache_ptr != NULL && cache_ptr->log_info != NULL) if (cache_ptr->log_info->logging) if (H5C_log_write_destroy_fd_msg(cache_ptr, (H5AC_info_t *)parent_thing, (H5AC_info_t *)child_thing, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_destroy_flush_dependency() */ /*------------------------------------------------------------------------- * Function: H5AC_unprotect * * Purpose: Undo an H5AC_protect() call -- specifically, mark the * entry as unprotected, remove it from the protected list, * and give it back to the replacement policy. * * The TYPE and ADDR arguments must be the same as those in * the corresponding call to H5AC_protect() and the THING * argument must be the value returned by that call to * H5AC_protect(). * * If the deleted flag is true, simply remove the target entry * from the cache, clear it, and free it without writing it to * disk. * * This version of the function is a complete re-write to * use the new metadata cache. While there isn't all that * much difference between the old and new Purpose sections, * the original version is given below. * * Original purpose section: * * This function should be called to undo the effect of * H5AC_protect(). The TYPE and ADDR arguments should be the * same as the corresponding call to H5AC_protect() and the * THING argument should be the value returned by H5AC_protect(). * If the DELETED flag is set, then this object has been deleted * from the file and should not be returned to the cache. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_unprotect(H5F_t *f, const H5AC_class_t *type, haddr_t addr, void *thing, unsigned flags) { bool dirtied; bool deleted; #ifdef H5_HAVE_PARALLEL H5AC_aux_t *aux_ptr = NULL; #endif /* H5_HAVE_PARALLEL */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared); assert(f->shared->cache); assert(type); assert(type->deserialize); assert(type->image_len); assert(H5_addr_defined(addr)); assert(thing); assert(((H5AC_info_t *)thing)->addr == addr); assert(((H5AC_info_t *)thing)->type == type); dirtied = (bool)(((flags & H5AC__DIRTIED_FLAG) == H5AC__DIRTIED_FLAG) || (((H5AC_info_t *)thing)->dirtied)); deleted = (bool)((flags & H5C__DELETED_FLAG) == H5C__DELETED_FLAG); /* Check if the size changed out from underneath us, if we're not deleting * the entry. */ if (dirtied && !deleted) { size_t curr_size = 0; if ((type->image_len)(thing, &curr_size) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTGETSIZE, FAIL, "Can't get size of thing"); if (((H5AC_info_t *)thing)->size != curr_size) HGOTO_ERROR(H5E_CACHE, H5E_BADSIZE, FAIL, "size of entry changed"); } /* end if */ #ifdef H5_HAVE_PARALLEL if (NULL != (aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(f->shared->cache))) { if (dirtied && ((H5AC_info_t *)thing)->is_dirty == false) if (H5AC__log_dirtied_entry((H5AC_info_t *)thing) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "can't log dirtied entry"); if (deleted && aux_ptr->mpi_rank == 0) { if (H5AC__log_deleted_entry((H5AC_info_t *)thing) < 0) { /* If we fail to log the deleted entry, push an error but still * participate in a possible sync point ahead */ HDONE_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "H5AC__log_deleted_entry() failed"); } } } /* end if */ #endif /* H5_HAVE_PARALLEL */ if (H5C_unprotect(f, addr, thing, flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "H5C_unprotect() failed"); #ifdef H5_HAVE_PARALLEL /* Check if we should try to flush */ if ((aux_ptr != NULL) && (aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold)) if (H5AC__run_sync_point(f, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point"); #endif /* H5_HAVE_PARALLEL */ done: /* If currently logging, generate a message */ if (f->shared->cache->log_info->logging) if (H5C_log_write_unprotect_entry_msg(f->shared->cache, addr, type->id, flags, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_unprotect() */ /*------------------------------------------------------------------------- * Function: H5AC_get_cache_auto_resize_config * * Purpose: Wrapper function for H5C_get_cache_auto_resize_config(). * * Return: SUCCEED on success, and FAIL on failure. * *------------------------------------------------------------------------- */ herr_t H5AC_get_cache_auto_resize_config(const H5AC_t *cache_ptr, H5AC_cache_config_t *config_ptr) { H5C_auto_size_ctl_t internal_config; bool evictions_enabled; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Check args */ if ((cache_ptr == NULL) || (config_ptr == NULL) || (config_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr or config_ptr on entry"); /* Retrieve the configuration */ if (H5C_get_cache_auto_resize_config((const H5C_t *)cache_ptr, &internal_config) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_cache_auto_resize_config() failed"); if (H5C_get_evictions_enabled((const H5C_t *)cache_ptr, &evictions_enabled) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_resize_enabled() failed"); /* Set the information to return */ if (internal_config.rpt_fcn == NULL) config_ptr->rpt_fcn_enabled = false; else config_ptr->rpt_fcn_enabled = true; config_ptr->open_trace_file = false; config_ptr->close_trace_file = false; config_ptr->trace_file_name[0] = '\0'; config_ptr->evictions_enabled = evictions_enabled; config_ptr->set_initial_size = internal_config.set_initial_size; config_ptr->initial_size = internal_config.initial_size; config_ptr->min_clean_fraction = internal_config.min_clean_fraction; config_ptr->max_size = internal_config.max_size; config_ptr->min_size = internal_config.min_size; config_ptr->epoch_length = (long)(internal_config.epoch_length); config_ptr->incr_mode = internal_config.incr_mode; config_ptr->lower_hr_threshold = internal_config.lower_hr_threshold; config_ptr->increment = internal_config.increment; config_ptr->apply_max_increment = internal_config.apply_max_increment; config_ptr->max_increment = internal_config.max_increment; config_ptr->decr_mode = internal_config.decr_mode; config_ptr->upper_hr_threshold = internal_config.upper_hr_threshold; config_ptr->flash_incr_mode = internal_config.flash_incr_mode; config_ptr->flash_multiple = internal_config.flash_multiple; config_ptr->flash_threshold = internal_config.flash_threshold; config_ptr->decrement = internal_config.decrement; config_ptr->apply_max_decrement = internal_config.apply_max_decrement; config_ptr->max_decrement = internal_config.max_decrement; config_ptr->epochs_before_eviction = (int)(internal_config.epochs_before_eviction); config_ptr->apply_empty_reserve = internal_config.apply_empty_reserve; config_ptr->empty_reserve = internal_config.empty_reserve; #ifdef H5_HAVE_PARALLEL { H5AC_aux_t *aux_ptr; if (NULL != (aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr))) { config_ptr->dirty_bytes_threshold = aux_ptr->dirty_bytes_threshold; config_ptr->metadata_write_strategy = aux_ptr->metadata_write_strategy; } /* end if */ else { #endif /* H5_HAVE_PARALLEL */ config_ptr->dirty_bytes_threshold = H5AC__DEFAULT_DIRTY_BYTES_THRESHOLD; config_ptr->metadata_write_strategy = H5AC__DEFAULT_METADATA_WRITE_STRATEGY; #ifdef H5_HAVE_PARALLEL } /* end else */ } #endif /* H5_HAVE_PARALLEL */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_get_cache_auto_resize_config() */ /*------------------------------------------------------------------------- * Function: H5AC_get_cache_size * * Purpose: Wrapper function for H5C_get_cache_size(). * * Return: SUCCEED on success, and FAIL on failure. * *------------------------------------------------------------------------- */ herr_t H5AC_get_cache_size(const H5AC_t *cache_ptr, size_t *max_size_ptr, size_t *min_clean_size_ptr, size_t *cur_size_ptr, uint32_t *cur_num_entries_ptr) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if (H5C_get_cache_size((const H5C_t *)cache_ptr, max_size_ptr, min_clean_size_ptr, cur_size_ptr, cur_num_entries_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_cache_size() failed"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_get_cache_size() */ /*------------------------------------------------------------------------- * Function: H5AC_get_cache_flush_in_progess * * Purpose: Wrapper function for H5C_get_cache_flush_in_progress(). * * Return: SUCCEED on success, and FAIL on failure. * *------------------------------------------------------------------------- */ herr_t H5AC_get_cache_flush_in_progress(H5AC_t *cache_ptr, bool *flush_in_progress_ptr) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if (H5C_get_cache_flush_in_progress((H5C_t *)cache_ptr, flush_in_progress_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_cache_flush_in_progress() failed"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_get_cache_flush_in_progress() */ /*------------------------------------------------------------------------- * Function: H5AC_get_cache_hit_rate * * Purpose: Wrapper function for H5C_get_cache_hit_rate(). * * Return: SUCCEED on success, and FAIL on failure. * *------------------------------------------------------------------------- */ herr_t H5AC_get_cache_hit_rate(const H5AC_t *cache_ptr, double *hit_rate_ptr) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if (H5C_get_cache_hit_rate((const H5C_t *)cache_ptr, hit_rate_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_cache_hit_rate() failed"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_get_cache_hit_rate() */ /*------------------------------------------------------------------------- * * Function: H5AC_reset_cache_hit_rate_stats() * * Purpose: Wrapper function for H5C_reset_cache_hit_rate_stats(). * * Return: SUCCEED on success, and FAIL on failure. * *------------------------------------------------------------------------- */ herr_t H5AC_reset_cache_hit_rate_stats(H5AC_t *cache_ptr) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if (H5C_reset_cache_hit_rate_stats((H5C_t *)cache_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_reset_cache_hit_rate_stats() failed"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_reset_cache_hit_rate_stats() */ /*------------------------------------------------------------------------- * Function: H5AC_set_cache_auto_resize_config * * Purpose: Wrapper function for H5C_set_cache_auto_resize_config(). * * Return: SUCCEED on success, and FAIL on failure. * *------------------------------------------------------------------------- */ herr_t H5AC_set_cache_auto_resize_config(H5AC_t *cache_ptr, const H5AC_cache_config_t *config_ptr) { H5C_auto_size_ctl_t internal_config; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(cache_ptr); if (cache_ptr == NULL) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "bad cache_ptr on entry"); /* Validate external configuration */ if (H5AC_validate_config(config_ptr) != SUCCEED) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Bad cache configuration"); /* If the cache config struct is being used to control logging, perform * the open/close operations. Note that this is the only place where the * struct-based control opens and closes the log files so we also have * to write start/stop messages. */ /* close */ if (config_ptr->close_trace_file) if (H5C_log_tear_down((H5C_t *)cache_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "mdc logging tear-down failed"); /* open */ if (config_ptr->open_trace_file) { /* Turn on metadata cache logging. * This will be trace output until we create a special API call. JSON * output is generated when logging is controlled by the H5P calls. */ if (H5C_log_set_up((H5C_t *)cache_ptr, config_ptr->trace_file_name, H5C_LOG_STYLE_TRACE, true) < 0) HGOTO_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "mdc logging setup failed"); } /* Convert external configuration to internal representation */ if (H5AC__ext_config_2_int_config(config_ptr, &internal_config) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC__ext_config_2_int_config() failed"); /* Set configuration */ if (H5C_set_cache_auto_resize_config(cache_ptr, &internal_config) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_set_cache_auto_resize_config() failed"); if (H5C_set_evictions_enabled(cache_ptr, config_ptr->evictions_enabled) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_set_evictions_enabled() failed"); #ifdef H5_HAVE_PARALLEL { H5AC_aux_t *aux_ptr; /* Set parallel configuration values */ /* (Which are only held in the H5AC layer -QAK) */ if (NULL != (aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(cache_ptr))) { aux_ptr->dirty_bytes_threshold = config_ptr->dirty_bytes_threshold; aux_ptr->metadata_write_strategy = config_ptr->metadata_write_strategy; } /* end if */ } #endif /* H5_HAVE_PARALLEL */ done: /* If currently logging, generate a message */ if (cache_ptr->log_info->logging) if (H5C_log_write_set_cache_config_msg(cache_ptr, config_ptr, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_set_cache_auto_resize_config() */ /*------------------------------------------------------------------------- * Function: H5AC_validate_config() * * Purpose: Run a sanity check on the contents of the supplied * instance of H5AC_cache_config_t. * * Do nothing and return SUCCEED if no errors are detected, * and flag an error and return FAIL otherwise. * * At present, this function operates by packing the data * from the instance of H5AC_cache_config_t into an instance * of H5C_auto_size_ctl_t, and then calling * H5C_validate_resize_config(). As H5AC_cache_config_t and * H5C_auto_size_ctl_t diverge, we may have to change this. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_validate_config(const H5AC_cache_config_t *config_ptr) { H5C_auto_size_ctl_t internal_config; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Check args */ if (config_ptr == NULL) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "NULL config_ptr on entry"); if (config_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Unknown config version"); /* don't bother to test trace_file_name unless open_trace_file is true */ if (config_ptr->open_trace_file) { size_t name_len; /* Can't really test the trace_file_name field without trying to * open the file, so we will content ourselves with a couple of * sanity checks on the length of the file name. */ name_len = strlen(config_ptr->trace_file_name); if (name_len == 0) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "config_ptr->trace_file_name is empty"); else if (name_len > H5AC__MAX_TRACE_FILE_NAME_LEN) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "config_ptr->trace_file_name too long"); } /* end if */ if ((config_ptr->evictions_enabled == false) && ((config_ptr->incr_mode != H5C_incr__off) || (config_ptr->flash_incr_mode != H5C_flash_incr__off) || (config_ptr->decr_mode != H5C_decr__off))) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Can't disable evictions while auto-resize is enabled"); if (config_ptr->dirty_bytes_threshold < H5AC__MIN_DIRTY_BYTES_THRESHOLD) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "dirty_bytes_threshold too small"); else if (config_ptr->dirty_bytes_threshold > H5AC__MAX_DIRTY_BYTES_THRESHOLD) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "dirty_bytes_threshold too big"); if ((config_ptr->metadata_write_strategy != H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY) && (config_ptr->metadata_write_strategy != H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED)) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "config_ptr->metadata_write_strategy out of range"); if (H5AC__ext_config_2_int_config(config_ptr, &internal_config) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC__ext_config_2_int_config() failed"); if (H5C_validate_resize_config(&internal_config, H5C_RESIZE_CFG__VALIDATE_ALL) < 0) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "error(s) in new config"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_validate_config() */ /*------------------------------------------------------------------------- * Function: H5AC_validate_cache_image_config() * * Purpose: Run a sanity check on the contents of the supplied * instance of H5AC_cache_image_config_t. * * Do nothing and return SUCCEED if no errors are detected, * and flag an error and return FAIL otherwise. * * At present, this function operates by packing the data * from the instance of H5AC_cache_image_config_t into an * instance of H5C_cache_image_ctl_t, and then calling * H5C_validate_cache_image_config(). If and when * H5AC_cache_image_config_t and H5C_cache_image_ctl_t * diverge, we may have to change this. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_validate_cache_image_config(H5AC_cache_image_config_t *config_ptr) { H5C_cache_image_ctl_t internal_config = H5C__DEFAULT_CACHE_IMAGE_CTL; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Check args */ if (config_ptr == NULL) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "NULL config_ptr on entry"); if (config_ptr->version != H5AC__CURR_CACHE_IMAGE_CONFIG_VERSION) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Unknown image config version"); /* don't need to get the current H5C image config here since the * default values of fields not in the H5AC config will always be * valid. */ internal_config.version = config_ptr->version; internal_config.generate_image = config_ptr->generate_image; internal_config.save_resize_status = config_ptr->save_resize_status; internal_config.entry_ageout = config_ptr->entry_ageout; if (H5C_validate_cache_image_config(&internal_config) < 0) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "error(s) in new cache image config"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_validate_cache_image_config() */ /*------------------------------------------------------------------------- * * Function: H5AC__check_if_write_permitted * * Purpose: Determine if a write is permitted under the current * circumstances, and set *write_permitted_ptr accordingly. * As a general rule it is, but when we are running in parallel * mode with collective I/O, we must ensure that a read cannot * cause a write. * * In the event of failure, the value of *write_permitted_ptr * is undefined. * * Return: Non-negative on success/Negative on failure. * *------------------------------------------------------------------------- */ static herr_t H5AC__check_if_write_permitted(const H5F_t #ifndef H5_HAVE_PARALLEL H5_ATTR_UNUSED #endif /* H5_HAVE_PARALLEL */ *f, bool *write_permitted_ptr) { #ifdef H5_HAVE_PARALLEL H5AC_aux_t *aux_ptr = NULL; #endif /* H5_HAVE_PARALLEL */ bool write_permitted = true; FUNC_ENTER_PACKAGE_NOERR #ifdef H5_HAVE_PARALLEL /* Sanity checks */ assert(f != NULL); assert(f->shared != NULL); assert(f->shared->cache != NULL); aux_ptr = (H5AC_aux_t *)H5C_get_aux_ptr(f->shared->cache); if (aux_ptr != NULL) { if ((aux_ptr->mpi_rank == 0) || (aux_ptr->metadata_write_strategy == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED)) write_permitted = aux_ptr->write_permitted; else write_permitted = false; } /* end if */ #endif /* H5_HAVE_PARALLEL */ *write_permitted_ptr = write_permitted; FUNC_LEAVE_NOAPI(SUCCEED) } /* H5AC__check_if_write_permitted() */ /*------------------------------------------------------------------------- * Function: H5AC__ext_config_2_int_config() * * Purpose: Utility function to translate an instance of * H5AC_cache_config_t to an instance of H5C_auto_size_ctl_t. * * Places translation in *int_conf_ptr and returns SUCCEED * if successful. Returns FAIL on failure. * * Does only minimal sanity checking. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5AC__ext_config_2_int_config(const H5AC_cache_config_t *ext_conf_ptr, H5C_auto_size_ctl_t *int_conf_ptr) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE if ((ext_conf_ptr == NULL) || (ext_conf_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION) || (int_conf_ptr == NULL)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad ext_conf_ptr or inf_conf_ptr on entry"); int_conf_ptr->version = H5C__CURR_AUTO_SIZE_CTL_VER; if (ext_conf_ptr->rpt_fcn_enabled) int_conf_ptr->rpt_fcn = H5C_def_auto_resize_rpt_fcn; else int_conf_ptr->rpt_fcn = NULL; int_conf_ptr->set_initial_size = ext_conf_ptr->set_initial_size; int_conf_ptr->initial_size = ext_conf_ptr->initial_size; int_conf_ptr->min_clean_fraction = ext_conf_ptr->min_clean_fraction; int_conf_ptr->max_size = ext_conf_ptr->max_size; int_conf_ptr->min_size = ext_conf_ptr->min_size; int_conf_ptr->epoch_length = (int64_t)(ext_conf_ptr->epoch_length); int_conf_ptr->incr_mode = ext_conf_ptr->incr_mode; int_conf_ptr->lower_hr_threshold = ext_conf_ptr->lower_hr_threshold; int_conf_ptr->increment = ext_conf_ptr->increment; int_conf_ptr->apply_max_increment = ext_conf_ptr->apply_max_increment; int_conf_ptr->max_increment = ext_conf_ptr->max_increment; int_conf_ptr->flash_incr_mode = ext_conf_ptr->flash_incr_mode; int_conf_ptr->flash_multiple = ext_conf_ptr->flash_multiple; int_conf_ptr->flash_threshold = ext_conf_ptr->flash_threshold; int_conf_ptr->decr_mode = ext_conf_ptr->decr_mode; int_conf_ptr->upper_hr_threshold = ext_conf_ptr->upper_hr_threshold; int_conf_ptr->decrement = ext_conf_ptr->decrement; int_conf_ptr->apply_max_decrement = ext_conf_ptr->apply_max_decrement; int_conf_ptr->max_decrement = ext_conf_ptr->max_decrement; int_conf_ptr->epochs_before_eviction = (int32_t)(ext_conf_ptr->epochs_before_eviction); int_conf_ptr->apply_empty_reserve = ext_conf_ptr->apply_empty_reserve; int_conf_ptr->empty_reserve = ext_conf_ptr->empty_reserve; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC__ext_config_2_int_config() */ /*------------------------------------------------------------------------------ * Function: H5AC_ignore_tags() * * Purpose: Override all assertion frameworks and force application of * global tag everywhere. This should really only be used in the * tests that need to access functions without going through * API paths. * * Return: SUCCEED on success, FAIL otherwise. * *------------------------------------------------------------------------------ */ herr_t H5AC_ignore_tags(const H5F_t *f) { herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared); assert(f->shared->cache); /* Set up a new metadata tag */ if (H5C_ignore_tags(f->shared->cache) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "H5C_ignore_tags() failed"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_ignore_tags() */ /*------------------------------------------------------------------------------ * Function: H5AC_tag() * * Purpose: Sets the metadata tag property in the provided property list. * * Return: void * *------------------------------------------------------------------------------ */ void H5AC_tag(haddr_t metadata_tag, haddr_t *prev_tag) { FUNC_ENTER_NOAPI_NOINIT_NOERR /* Get the current tag value and return that (if prev_tag is NOT null) */ if (prev_tag) *prev_tag = H5CX_get_tag(); /* Set the provided tag */ H5CX_set_tag(metadata_tag); FUNC_LEAVE_NOAPI_VOID } /* H5AC_tag */ /*------------------------------------------------------------------------------ * Function: H5AC_retag_copied_metadata() * * Purpose: Searches through cache index for all entries with the * H5AC__COPIED_TAG, indicating that it was created as a * result of an object copy, and applies the provided tag. * * Return: SUCCEED on success, FAIL otherwise. * *------------------------------------------------------------------------------ */ herr_t H5AC_retag_copied_metadata(const H5F_t *f, haddr_t metadata_tag) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(f); assert(f->shared); /* Call cache-level function to re-tag entries with the COPIED tag */ if (H5C_retag_entries(f->shared->cache, H5AC__COPIED_TAG, metadata_tag) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "Can't retag metadata"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_retag_copied_metadata() */ /*------------------------------------------------------------------------------ * Function: H5AC_flush_tagged_metadata() * * Purpose: Wrapper for cache level function which flushes all metadata * that contains the specific tag. * * Return: SUCCEED on success, FAIL otherwise. * *------------------------------------------------------------------------------ */ herr_t H5AC_flush_tagged_metadata(H5F_t *f, haddr_t metadata_tag) { /* Variable Declarations */ herr_t ret_value = SUCCEED; /* Function Enter Macro */ FUNC_ENTER_NOAPI(FAIL) /* Assertions */ assert(f); assert(f->shared); /* Call cache level function to flush metadata entries with specified tag */ if (H5C_flush_tagged_entries(f, metadata_tag) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot flush metadata"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_flush_tagged_metadata */ /*------------------------------------------------------------------------------ * Function: H5AC_evict_tagged_metadata() * * Purpose: Wrapper for cache level function which evicts all metadata * that contains the specific tag. * * The match_global parameter determines if the global file * data (e.g., global heaps, shared object header messages) * should be checked. This is false when closing objects * and true when flushing. * * Return: SUCCEED on success, FAIL otherwise. *------------------------------------------------------------------------------ */ herr_t H5AC_evict_tagged_metadata(H5F_t *f, haddr_t metadata_tag, bool match_global) { /* Variable Declarations */ herr_t ret_value = SUCCEED; /* Function Enter Macro */ FUNC_ENTER_NOAPI(FAIL) /* Assertions */ assert(f); assert(f->shared); /* Call cache level function to evict metadata entries with specified tag */ if (H5C_evict_tagged_entries(f, metadata_tag, match_global) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict metadata"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_evict_tagged_metadata() */ /*------------------------------------------------------------------------------ * Function: H5AC_expunge_tag_type_metadata() * * Purpose: Wrapper for cache level function which expunges entries with * a specific tag and type id. * * Return: SUCCEED on success, FAIL otherwise. * *------------------------------------------------------------------------------ */ herr_t H5AC_expunge_tag_type_metadata(H5F_t *f, haddr_t tag, int type_id, unsigned flags) { /* Variable Declarations */ herr_t ret_value = SUCCEED; /* Function Enter Macro */ FUNC_ENTER_NOAPI(FAIL) /* Assertions */ assert(f); assert(f->shared); /* Call cache level function to expunge entries with specified tag and type id */ if (H5C_expunge_tag_type_metadata(f, tag, type_id, flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot expunge tagged type entries"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_expunge_tag_type_metadata*/ /*------------------------------------------------------------------------------ * Function: H5AC_get_tag() * * Purpose: Get the tag for a metadata cache entry. * * Return: SUCCEED/FAIL * *------------------------------------------------------------------------------ */ herr_t H5AC_get_tag(const void *thing, haddr_t *tag) { /* Variable Declarations */ herr_t ret_value = SUCCEED; /* Function Enter Macro */ FUNC_ENTER_NOAPI(FAIL) /* Assertions */ assert(thing); assert(tag); /* Call cache level function to get the tag */ if (H5C_get_tag(thing, tag) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "Cannot get tag for metadata cache entry"); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5AC_get_tag() */ /*------------------------------------------------------------------------- * Function: H5AC_cork * * Purpose: To cork/uncork/get cork status for an object * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_cork(H5F_t *f, haddr_t obj_addr, unsigned action, bool *corked) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(f); assert(f->shared); assert(f->shared->cache); assert(H5_addr_defined(obj_addr)); assert(action == H5AC__SET_CORK || action == H5AC__UNCORK || action == H5AC__GET_CORKED); /* Skip the search on "tag_list" when there are no "corked" objects. * This is done to mitigate the slow down when closing objects. * Re-visit this optimization when we optimize tag info management * in the future. */ if (action == H5AC__GET_CORKED) { assert(corked); if (H5C_get_num_objs_corked(f->shared->cache) == 0) { *corked = false; HGOTO_DONE(SUCCEED); } } if (H5C_cork(f->shared->cache, obj_addr, action, corked) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Cannot perform the cork action"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_cork() */ #if H5AC_DO_TAGGING_SANITY_CHECKS /*------------------------------------------------------------------------- * * Function: H5AC__verify_tag * * Purpose: Performs sanity checking on an entry type and tag value * stored in a supplied dxpl_id. * * Return: SUCCEED or FAIL. * *------------------------------------------------------------------------- */ static herr_t H5AC__verify_tag(const H5AC_class_t *type) { haddr_t tag; /* Entry tag to validate */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Get the current tag */ tag = H5CX_get_tag(); /* Verify legal tag value */ if (H5C_verify_tag(type->id, tag) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "tag verification failed"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC__verify_tag */ #endif /* H5AC_DO_TAGGING_SANITY_CHECKS */ /*------------------------------------------------------------------------- * Function: H5AC_get_entry_ring * * Purpose: Given a file address, retrieve the ring for an entry at that * address. * * On error, the value of *ring is not modified. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_get_entry_ring(const H5F_t *f, haddr_t addr, H5AC_ring_t *ring) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(f); assert(H5_addr_defined(addr)); assert(ring); /* Retrieve the ring value for the entry at address */ if (H5C_get_entry_ring(f, addr, ring) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "Can't retrieve ring for entry"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_get_entry_ring() */ /*------------------------------------------------------------------------- * Function: H5AC_set_ring * * Purpose: Routine to set the ring on a DXPL (for passing through * to the metadata cache). * * Return: void * *------------------------------------------------------------------------- */ void H5AC_set_ring(H5AC_ring_t ring, H5AC_ring_t *orig_ring) { FUNC_ENTER_NOAPI_NOINIT_NOERR /* Note: orig_ring can be NULL so don't check it with assert() */ /* Get the current ring value and return that (if orig_ring is NOT null) */ if (orig_ring) *orig_ring = H5CX_get_ring(); /* Set the provided ring */ H5CX_set_ring(ring); FUNC_LEAVE_NOAPI_VOID } /* end H5AC_set_ring() */ /*------------------------------------------------------------------------- * Function: H5AC_unsettle_entry_ring() * * Purpose: Advise the metadata cache that the specified entry's metadata * cache manager ring is no longer settled (if it was on entry). * * If the target metadata cache manager ring is already * unsettled, do nothing, and return SUCCEED. * * If the target metadata cache manager ring is settled, and * we are not in the process of a file shutdown, mark * the ring as unsettled, and return SUCCEED. * * If the target metadata cache manager is settled, and we * are in the process of a file shutdown, post an error * message, and return FAIL. * * Note that this function simply passes the call on to * the metadata cache proper, and returns the result. * * Return: Success: Non-negative * Failure: Negative * *------------------------------------------------------------------------- */ herr_t H5AC_unsettle_entry_ring(void *_entry) { H5AC_info_t *entry = (H5AC_info_t *)_entry; /* Entry to remove */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(entry); /* Unsettle the entry's ring */ if (H5C_unsettle_entry_ring(entry) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_unsettle_entry_ring() */ /*------------------------------------------------------------------------- * Function: H5AC_unsettle_ring() * * Purpose: Advise the metadata cache that the specified free space * manager ring is no longer settled (if it was on entry). * * If the target free space manager ring is already * unsettled, do nothing, and return SUCCEED. * * If the target free space manager ring is settled, and * we are not in the process of a file shutdown, mark * the ring as unsettled, and return SUCCEED. * * If the target free space manager is settled, and we * are in the process of a file shutdown, post an error * message, and return FAIL. * * Note that this function simply passes the call on to * the metadata cache proper, and returns the result. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_unsettle_ring(H5F_t *f, H5C_ring_t ring) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if (FAIL == (ret_value = H5C_unsettle_ring(f, ring))) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_unsettle_ring() failed"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_unsettle_ring() */ /*------------------------------------------------------------------------- * Function: H5AC_remove_entry() * * Purpose: Remove an entry from the cache. Must be not protected, pinned, * dirty, involved in flush dependencies, etc. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5AC_remove_entry(void *_entry) { H5AC_info_t *entry = (H5AC_info_t *)_entry; /* Entry to remove */ H5C_t *cache = NULL; /* Pointer to the entry's associated metadata cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ assert(entry); cache = entry->cache_ptr; assert(cache); /* Remove the entry from the cache*/ if (H5C_remove_entry(entry) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry"); done: /* If currently logging, generate a message */ if (cache != NULL && cache->log_info != NULL) if (cache->log_info->logging) if (H5C_log_write_remove_entry_msg(cache, entry, ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_LOGGING, FAIL, "unable to emit log message"); FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_remove_entry() */ /*------------------------------------------------------------------------- * Function: H5AC_get_mdc_image_info * * Purpose: Wrapper function for H5C_get_mdc_image_info(). * * Return: SUCCEED on success, and FAIL on failure. * *------------------------------------------------------------------------- */ herr_t H5AC_get_mdc_image_info(const H5AC_t *cache_ptr, haddr_t *image_addr, hsize_t *image_len) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if (H5C_get_mdc_image_info((const H5C_t *)cache_ptr, image_addr, image_len) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "can't retrieve cache image info"); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5AC_get_mdc_image_info() */