diff options
author | Larry Knox <lrknox@hdfgroup.org> | 2020-10-16 22:47:27 (GMT) |
---|---|---|
committer | Larry Knox <lrknox@hdfgroup.org> | 2020-10-16 22:47:27 (GMT) |
commit | db30c2da68ece4a155e9e50c28ec16d6057509b2 (patch) | |
tree | 1d36f673c36dfee71c266bba39511da21ecc782e /src/H5C.c | |
parent | 5b9cf732caab9daa6ed1e00f2df4f5a792340196 (diff) | |
parent | 2e2b87d1cbdee3b919e6e5cba6c5ecd1b9434434 (diff) | |
download | hdf5-db30c2da68ece4a155e9e50c28ec16d6057509b2.zip hdf5-db30c2da68ece4a155e9e50c28ec16d6057509b2.tar.gz hdf5-db30c2da68ece4a155e9e50c28ec16d6057509b2.tar.bz2 |
Merge HDF5 1.10.7 release files into 1.10/masterhdf5-1_10_7
Diffstat (limited to 'src/H5C.c')
-rw-r--r-- | src/H5C.c | 2295 |
1 files changed, 1665 insertions, 630 deletions
@@ -168,7 +168,7 @@ static herr_t H5C__verify_len_eoa(H5F_t *f, const H5C_class_t * type, haddr_t addr, size_t *len, hbool_t actual); #if H5C_DO_SLIST_SANITY_CHECKS -static hbool_t H5C_entry_in_skip_list(H5C_t * cache_ptr, +static hbool_t H5C_entry_in_skip_list(H5C_t * cache_ptr, H5C_cache_entry_t *target_ptr); #endif /* H5C_DO_SLIST_SANITY_CHECKS */ @@ -234,6 +234,82 @@ H5FL_BLK_DEFINE_STATIC(parent); * Programmer: John Mainzer * 6/2/04 * + * Modifications: + * + * JRM -- 7/20/04 + * Updated for the addition of the hash table. + * + * JRM -- 10/5/04 + * Added call to H5C_reset_cache_hit_rate_stats(). Also + * added initialization for cache_is_full flag and for + * resize_ctl. + * + * JRM -- 11/12/04 + * Added initialization for the new size_decreased field. + * + * JRM -- 11/17/04 + * Added/updated initialization for the automatic cache + * size control data structures. + * + * JRM -- 6/24/05 + * Added support for the new write_permitted field of + * the H5C_t structure. + * + * JRM -- 7/5/05 + * Added the new log_flush parameter and supporting code. + * + * JRM -- 9/21/05 + * Added the new aux_ptr parameter and supporting code. + * + * JRM -- 1/20/06 + * Added initialization of the new prefix field in H5C_t. + * + * JRM -- 3/16/06 + * Added initialization for the pinned entry related fields. + * + * JRM -- 5/31/06 + * Added initialization for the trace_file_ptr field. + * + * JRM -- 8/19/06 + * Added initialization for the flush_in_progress field. + * + * JRM -- 8/25/06 + * Added initialization for the slist_len_increase and + * slist_size_increase fields. These fields are used + * for sanity checking in the flush process, and are not + * compiled in unless H5C_DO_SANITY_CHECKS is TRUE. + * + * JRM -- 3/28/07 + * Added initialization for the new is_read_only and + * ro_ref_count fields. + * + * JRM -- 7/27/07 + * Added initialization for the new evictions_enabled + * field of H5C_t. + * + * JRM -- 12/31/07 + * Added initialization for the new flash cache size increase + * related fields of H5C_t. + * + * JRM -- 11/5/08 + * Added initialization for the new clean_index_size and + * dirty_index_size fields of H5C_t. + * + * + * Missing entries? + * + * + * JRM -- 4/20/20 + * Added initialization for the slist_enabled field. Recall + * that the slist is used to flush metadata cache entries + * in (roughly) increasing address order. While this is + * needed at flush and close, it is not used elsewhere. + * The slist_enabled field exists to allow us to construct + * the slist when needed, and leave it empty otherwise -- thus + * avoiding the overhead of maintaining it. + * + * JRM -- 4/29/20 + * *------------------------------------------------------------------------- */ H5C_t * @@ -308,30 +384,36 @@ H5C_create(size_t max_cache_size, cache_ptr->dirty_index_size = (size_t)0; for(i = 0; i < H5C_RING_NTYPES; i++) { - cache_ptr->index_ring_len[i] = 0; - cache_ptr->index_ring_size[i] = (size_t)0; - cache_ptr->clean_index_ring_size[i] = (size_t)0; - cache_ptr->dirty_index_ring_size[i] = (size_t)0; + cache_ptr->index_ring_len[i] = 0; + cache_ptr->index_ring_size[i] = (size_t)0; + cache_ptr->clean_index_ring_size[i] = (size_t)0; + cache_ptr->dirty_index_ring_size[i] = (size_t)0; - cache_ptr->slist_ring_len[i] = 0; - cache_ptr->slist_ring_size[i] = (size_t)0; + cache_ptr->slist_ring_len[i] = 0; + cache_ptr->slist_ring_size[i] = (size_t)0; } /* end for */ for(i = 0; i < H5C__HASH_TABLE_LEN; i++) (cache_ptr->index)[i] = NULL; - cache_ptr->il_len = 0; - cache_ptr->il_size = (size_t)0; - cache_ptr->il_head = NULL; - cache_ptr->il_tail = NULL; + cache_ptr->il_len = 0; + cache_ptr->il_size = (size_t)0; + cache_ptr->il_head = NULL; + cache_ptr->il_tail = NULL; /* Tagging Field Initializations */ cache_ptr->ignore_tags = FALSE; cache_ptr->num_objs_corked = 0; - cache_ptr->slist_changed = FALSE; - cache_ptr->slist_len = 0; - cache_ptr->slist_size = (size_t)0; + /* slist field initializations */ + cache_ptr->slist_enabled = ! H5C__SLIST_OPT_ENABLED; + cache_ptr->slist_changed = FALSE; + cache_ptr->slist_len = 0; + cache_ptr->slist_size = (size_t)0; + + /* slist_ring_len, slist_ring_size, and + * slist_ptr initializaed above. + */ #if H5C_DO_SANITY_CHECKS cache_ptr->slist_len_increase = 0; @@ -719,10 +801,10 @@ H5C_free_tag_list_cb(void *_item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED * * Function: H5C_prep_for_file_close * - * Purpose: This function should be called just prior to the cache - * flushes at file close. There should be no protected + * Purpose: This function should be called just prior to the cache + * flushes at file close. There should be no protected * entries in the cache at this point. - * + * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer @@ -747,8 +829,8 @@ H5C_prep_for_file_close(H5F_t *f) HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); - /* For now at least, it is possible to receive the - * close warning more than once -- the following + /* For now at least, it is possible to receive the + * close warning more than once -- the following * if statement handles this. */ if(cache_ptr->close_warning_received) @@ -764,8 +846,8 @@ H5C_prep_for_file_close(H5F_t *f) #ifdef H5_HAVE_PARALLEL if ( ( H5F_INTENT(f) & H5F_ACC_RDWR ) && - ( ! image_generated ) && - ( cache_ptr->aux_ptr != NULL ) && + ( ! image_generated ) && + ( cache_ptr->aux_ptr != NULL ) && ( f->shared->fs_persist ) ) { /* If persistent free space managers are enabled, flushing the * metadata cache may result in the deletion, insertion, and/or @@ -825,6 +907,20 @@ done: * Programmer: John Mainzer * 6/2/04 * + * Modifications: + * + * JRM -- 5/15/20 + * + * Updated the function to enable the slist prior to the + * call to H5C__flush_invalidate_cache(). + * + * Arguably, it shouldn't be necessary to re-enable the + * slist after the call to H5C__flush_invalidate_cache(), as + * the metadata cache should be discarded. However, in the + * test code, we make multiple calls to H5C_dest(). Thus + * we re-enable the slist on failure if it and the cache + * still exist. + * *------------------------------------------------------------------------- */ herr_t @@ -845,33 +941,60 @@ H5C_dest(H5F_t * f) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't display cache image stats") #endif /* H5AC_DUMP_IMAGE_STATS_ON_CLOSE */ + /* Enable the slist, as it is needed in the flush */ + if ( H5C_set_slist_enabled(f->shared->cache, TRUE, FALSE) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "set slist enabled failed") + /* Flush and invalidate all cache entries */ - if(H5C__flush_invalidate_cache(f, H5C__NO_FLAGS_SET) < 0 ) + if ( H5C__flush_invalidate_cache(f, H5C__NO_FLAGS_SET) < 0 ) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache") /* Generate & write cache image if requested */ - if(cache_ptr->image_ctl.generate_image) - if(H5C__generate_cache_image(f, cache_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "Can't generate metadata cache image") + if ( cache_ptr->image_ctl.generate_image ) { + + if ( H5C__generate_cache_image(f, cache_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, \ + "Can't generate metadata cache image") + } + + /* Question: Is it possible for cache_ptr->slist be non-null at this + * point? If no, shouldn't this if statement be an assert? + */ + if ( cache_ptr->slist_ptr != NULL ) { + + HDassert(cache_ptr->slist_len == 0); + HDassert(cache_ptr->slist_size == 0); - if(cache_ptr->slist_ptr != NULL) { H5SL_close(cache_ptr->slist_ptr); + cache_ptr->slist_ptr = NULL; + } /* end if */ if(cache_ptr->tag_list != NULL) { + H5SL_destroy(cache_ptr->tag_list, H5C_free_tag_list_cb, NULL); cache_ptr->tag_list = NULL; + } /* end if */ - if(cache_ptr->log_info != NULL) + if(cache_ptr->log_info != NULL) { + H5MM_xfree(cache_ptr->log_info); + } #ifndef NDEBUG #if H5C_DO_SANITY_CHECKS - if(cache_ptr->get_entry_ptr_from_addr_counter > 0) - HDfprintf(stdout, "*** %ld calls to H5C_get_entry_ptr_from_add(). ***\n", - cache_ptr->get_entry_ptr_from_addr_counter); + + if ( cache_ptr->get_entry_ptr_from_addr_counter > 0 ) { + + HDfprintf(stdout, + "*** %ld calls to H5C_get_entry_ptr_from_add(). ***\n", + cache_ptr->get_entry_ptr_from_addr_counter); + } #endif /* H5C_DO_SANITY_CHECKS */ cache_ptr->magic = 0; @@ -880,7 +1003,19 @@ H5C_dest(H5F_t * f) cache_ptr = H5FL_FREE(H5C_t, cache_ptr); done: + + if ( ( ret_value < 0 ) && ( cache_ptr ) && ( cache_ptr->slist_ptr ) ) { + + /* need this for test code -- see change note for details */ + + if ( H5C_set_slist_enabled(f->shared->cache, FALSE, FALSE) < 0 ) + + HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "disable slist on flush dest failure failed") + } + FUNC_LEAVE_NOAPI(ret_value) + } /* H5C_dest() */ @@ -894,6 +1029,14 @@ done: * Programmer: Vailin Choi * Dec 2013 * + * Modifications: + * + * JRM -- 5/5/20 + * + * Added code to enable the skip list prior to the call + * to H5C__flush_invalidate_cache(), and disable it + * afterwards. + * *------------------------------------------------------------------------- */ herr_t @@ -906,9 +1049,22 @@ H5C_evict(H5F_t * f) /* Sanity check */ HDassert(f); + /* Enable the slist, as it is needed in the flush */ + if ( H5C_set_slist_enabled(f->shared->cache, TRUE, FALSE) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "set slist enabled failed") + /* Flush and invalidate all cache entries except the pinned entries */ - if(H5C__flush_invalidate_cache(f, H5C__EVICT_ALLOW_LAST_PINS_FLAG) < 0 ) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to evict entries in the cache") + if ( H5C__flush_invalidate_cache(f, H5C__EVICT_ALLOW_LAST_PINS_FLAG) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, + "unable to evict entries in the cache") + + /* Disable the slist, + */ + if ( H5C_set_slist_enabled(f->shared->cache, FALSE, TRUE) < 0) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "set slist disabled failed") done: FUNC_LEAVE_NOAPI(ret_value) @@ -1008,31 +1164,31 @@ done: * Programmer: John Mainzer * 6/2/04 * - * Changes: Modified function to test for slist chamges in + * Changes: Modified function to test for slist chamges in * pre_serialize and serialize callbacks, and re-start * scans through the slist when such changes occur. * * This has been a potential problem for some time, - * and there has been code in this function to deal - * with elements of this issue. However the shift + * and there has been code in this function to deal + * with elements of this issue. However the shift * to the V3 cache in combination with the activities - * of some of the cache clients (in particular the + * of some of the cache clients (in particular the * free space manager and the fractal heap) have * made this re-work necessary. * * JRM -- 12/13/14 * - * Modified function to support rings. Basic idea is that + * Modified function to support rings. Basic idea is that * every entry in the cache is assigned to a ring. Entries - * in the outermost ring are flushed first, followed by - * those in the next outermost ring, and so on until the - * innermost ring is flushed. See header comment on - * H5C_ring_t in H5Cprivate.h for a more detailed + * in the outermost ring are flushed first, followed by + * those in the next outermost ring, and so on until the + * innermost ring is flushed. See header comment on + * H5C_ring_t in H5Cprivate.h for a more detailed * discussion. * * JRM -- 8/30/15 * - * Modified function to call the free space manager + * Modified function to call the free space manager * settling functions. * JRM -- 6/9/16 * @@ -1110,7 +1266,7 @@ H5C_flush_cache(H5F_t *f, unsigned flags) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush invalidate failed") } /* end if */ else { - /* flush each ring, starting from the outermost ring and + /* flush each ring, starting from the outermost ring and * working inward. */ ring = H5C_RING_USER; @@ -1286,7 +1442,7 @@ H5C_insert_entry(H5F_t * f, insert_pinned = ( (flags & H5C__PIN_ENTRY_FLAG) != 0 ); flush_last = ( (flags & H5C__FLUSH_LAST_FLAG) != 0 ); - /* Get the ring type from the DXPL */ + /* Get the ring type from the API context */ ring = H5CX_get_ring(); entry_ptr = (H5C_cache_entry_t *)thing; @@ -2244,7 +2400,7 @@ H5C_protect(H5F_t * f, if(entry_ptr->prefetched) { /* This call removes the prefetched entry from the cache, - * and replaces it with an entry deserialized from the + * and replaces it with an entry deserialized from the * image of the prefetched entry. */ if(H5C__deserialize_prefetched_entry(f, cache_ptr, &entry_ptr, type, addr, udata) < 0) @@ -2285,7 +2441,7 @@ H5C_protect(H5F_t * f, if(NULL == (entry_ptr->image_ptr = H5MM_malloc(entry_ptr->size + H5C_IMAGE_EXTRA_SPACE))) HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed for on disk image buffer") #if H5C_DO_MEMORY_SANITY_CHECKS - HDmemcpy(((uint8_t *)entry_ptr->image_ptr) + entry_ptr->size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); + H5MM_memcpy(((uint8_t *)entry_ptr->image_ptr) + entry_ptr->size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ if(0 == mpi_rank) if(H5C__generate_image(f, cache_ptr, entry_ptr) < 0) @@ -2313,15 +2469,15 @@ H5C_protect(H5F_t * f, if(cache_ptr->ignore_tags != TRUE) { haddr_t tag; /* Tag value */ - /* The entry is already in the cache, but make sure that the tag value - is still legal. This will ensure that had - the entry NOT been in the cache, tagging was still set up correctly - and it would have received a legal tag value after getting loaded - from disk. */ + /* The entry is already in the cache, but make sure that the tag value + * is still legal. This will ensure that had the entry NOT been in the + * cache, tagging was still set up correctly and it would have received + * a legal tag value after getting loaded from disk. + */ /* Get the tag */ tag = H5CX_get_tag(); - + if(H5C_verify_tag(entry_ptr->type->id, tag) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "tag verification failed") } /* end if */ @@ -2337,9 +2493,9 @@ H5C_protect(H5F_t * f, hit = FALSE; - if(NULL == (thing = H5C_load_entry(f, + if(NULL == (thing = H5C_load_entry(f, #ifdef H5_HAVE_PARALLEL - coll_access, + coll_access, #endif /* H5_HAVE_PARALLEL */ type, addr, udata))) HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "can't load entry") @@ -2372,10 +2528,10 @@ H5C_protect(H5F_t * f, else empty_space = cache_ptr->max_cache_size - cache_ptr->index_size; - /* try to free up if necceary and if evictions are permitted. Note - * that if evictions are enabled, we will call H5C__make_space_in_cache() - * regardless if the min_free_space requirement is not met. - */ + /* try to free up if necceary and if evictions are permitted. Note + * that if evictions are enabled, we will call H5C__make_space_in_cache() + * regardless if the min_free_space requirement is not met. + */ if ( ( cache_ptr->evictions_enabled ) && ( ( (cache_ptr->index_size + entry_ptr->size) > cache_ptr->max_cache_size) @@ -2421,10 +2577,10 @@ H5C_protect(H5F_t * f, * * Second, when writes are not permitted it is also possible * for the cache to grow without bound. - * - * Third, the user may choose to disable evictions -- causing - * the cache to grow without bound until evictions are - * re-enabled. + * + * Third, the user may choose to disable evictions -- causing + * the cache to grow without bound until evictions are + * re-enabled. * * Finally, we usually don't check to see if the cache is * oversized at the end of an unprotect. As a result, it is @@ -2448,12 +2604,12 @@ H5C_protect(H5F_t * f, * ******************************************* * * Set the flush_last field - * of the newly loaded entry before inserting it into the - * index. Must do this, as the index tracked the number of - * entries with the flush_last field set, but assumes that + * of the newly loaded entry before inserting it into the + * index. Must do this, as the index tracked the number of + * entries with the flush_last field set, but assumes that * the field will not change after insertion into the index. * - * Note that this means that the H5C__FLUSH_LAST_FLAG flag + * Note that this means that the H5C__FLUSH_LAST_FLAG flag * is ignored if the entry is already in cache. */ entry_ptr->flush_me_last = flush_last; @@ -2485,7 +2641,7 @@ H5C_protect(H5F_t * f, HDassert(entry_ptr->ro_ref_count > 0); (entry_ptr->ro_ref_count)++; } /* end if */ - else + else HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "Target already protected & not read only?!?") } /* end if */ else { @@ -2878,6 +3034,179 @@ done: /*------------------------------------------------------------------------- + * + * Function: H5C_set_slist_enabled() + * + * Purpose: Enable or disable the slist as directed. + * + * The slist (skip list) is an address ordered list of + * dirty entries in the metadata cache. However, this + * list is only needed during flush and close, where we + * use it to write entries in more or less increasing + * address order. + * + * This function sets up and enables further operations + * on the slist, or disable the slist. This in turn + * allows us to avoid the overhead of maintaining the + * slist when it is not needed. + * + * + * If the slist_enabled parameter is TRUE, the function + * + * 1) Verifies that the slist is empty. + * + * 2) Scans the index list, and inserts all dirty entries + * into the slist. + * + * 3) Sets cache_ptr->slist_enabled = TRUE. + * + * Note that the clear_slist parameter is ignored if + * the slist_enabed parameter is TRUE. + * + * + * If the slist_enabled_parameter is FALSE, the function + * shuts down the slist. + * + * Normally the slist will be empty at this point, however + * that need not be the case if H5C_flush_cache() has been + * called with the H5C__FLUSH_MARKED_ENTRIES_FLAG. + * + * Thus shutdown proceeds as follows: + * + * 1) Test to see if the slist is empty. If it is, proceed + * to step 3. + * + * 2) Test to see if the clear_slist parameter is TRUE. + * + * If it is, remove all entries from the slist. + * + * If it isn't, throw an error. + * + * 3) set cache_ptr->slist_enabled = FALSE. + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 5/1/20 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ +herr_t +H5C_set_slist_enabled(H5C_t *cache_ptr, hbool_t slist_enabled, + hbool_t clear_slist) +{ + H5C_cache_entry_t * entry_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_SYSTEM, FAIL, "Bad cache_ptr on entry") + +#if H5C__SLIST_OPT_ENABLED + + if ( slist_enabled ) { + + if ( cache_ptr->slist_enabled ) { + + HDassert(FALSE); + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist already enabled?") + } + + if ( ( cache_ptr->slist_len != 0 ) || + ( cache_ptr->slist_size != 0 ) ) { + + HDassert(FALSE); + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist not empty (1)?") + } + + + /* set cache_ptr->slist_enabled to TRUE so that the slist + * mainenance macros will be enabled. + */ + cache_ptr->slist_enabled = TRUE; + + + /* scan the index list and insert all dirty entries in the slist */ + entry_ptr = cache_ptr->il_head; + + while ( entry_ptr != NULL ) { + + HDassert( entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC ); + + if ( entry_ptr->is_dirty ) { + + H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) + } + + entry_ptr = entry_ptr->il_next; + } + + /* we don't maintain a dirty index len, so we can't do a cross + * check against it. Note that there is no point in cross checking + * against the dirty LRU size, as the dirty LRU may not be maintained, + * and in any case, there is no requirement that all dirty entries + * will reside on the dirty LRU. + */ + HDassert( cache_ptr->dirty_index_size == cache_ptr->slist_size ); + + } else { /* take down the skip list */ + + if ( ! cache_ptr->slist_enabled ) { + + HDassert(FALSE); + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist already disabled?") + } + + if ( ( cache_ptr->slist_len != 0 ) || + ( cache_ptr->slist_size != 0 ) ) { + + if ( clear_slist ) { + + H5SL_node_t *node_ptr; + + node_ptr = H5SL_first(cache_ptr->slist_ptr); + + while ( node_ptr != NULL ) { + + entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); + + H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, FALSE); + + node_ptr = H5SL_first(cache_ptr->slist_ptr); + } + } else { + + HDassert(FALSE); + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist not empty (2)?") + } + } + + cache_ptr->slist_enabled = FALSE; + + HDassert( 0 == cache_ptr->slist_len ); + HDassert( 0 == cache_ptr->slist_size ); + } + +#else /* H5C__SLIST_OPT_ENABLED is FALSE */ + + HDassert(cache_ptr->slist_enabled); + +#endif /* H5C__SLIST_OPT_ENABLED is FALSE */ + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C_set_slist_enabled() */ + + +/*------------------------------------------------------------------------- * Function: H5C_unpin_entry() * * Purpose: Unpin a cache entry. The entry can be either protected or @@ -2888,8 +3217,8 @@ done: * Programmer: John Mainzer * 3/22/06 * - * Changes: Added extreme sanity checks on entry and exit. - JRM -- 4/26/14 + * Changes: Added extreme sanity checks on entry and exit. + * JRM -- 4/26/14 * *------------------------------------------------------------------------- */ @@ -2955,6 +3284,81 @@ done: * Programmer: John Mainzer * 6/2/04 * + * Modifications: + * + * JRM -- 7/21/04 + * Updated for the addition of the hash table. + * + * JRM -- 10/28/04 + * Added code to set cache_full to TRUE whenever we try to + * make space in the cache. + * + * JRM -- 11/12/04 + * Added code to call to H5C_make_space_in_cache() after the + * call to H5C__auto_adjust_cache_size() if that function + * sets the size_decreased flag is TRUE. + * + * JRM -- 4/25/05 + * The size_decreased flag can also be set to TRUE in + * H5C_set_cache_auto_resize_config() if a new configuration + * forces an immediate reduction in cache size. Modified + * the code to deal with this eventuallity. + * + * JRM -- 6/24/05 + * Added support for the new write_permitted field of H5C_t. + * + * JRM -- 10/22/05 + * Hand optimizations. + * + * JRM -- 5/3/06 + * Added code to set the new dirtied field in + * H5C_cache_entry_t to FALSE prior to return. + * + * JRM -- 6/23/06 + * Modified code to allow dirty entries to be loaded from + * disk. This is necessary as a bug fix in the object + * header code requires us to modify a header as it is read. + * + * JRM -- 3/28/07 + * Added the flags parameter and supporting code. At least + * for now, this parameter is used to allow the entry to + * be protected read only, thus allowing multiple protects. + * + * Also added code to allow multiple read only protects + * of cache entries. + * + * JRM -- 7/27/07 + * Added code supporting the new evictions_enabled field + * in H5C_t. + * + * JRM -- 1/3/08 + * Added to do a flash cache size increase if appropriate + * when a large entry is loaded. + * + * JRM -- 11/13/08 + * Modified function to call H5C_make_space_in_cache() when + * the min_clean_size is violated, not just when there isn't + * enough space for and entry that has just been loaded. + * + * The purpose of this modification is to avoid "metadata + * blizzards" in the write only case. In such instances, + * the cache was allowed to fill with dirty metadata. When + * we finally needed to evict an entry to make space, we had + * to flush out a whole cache full of metadata -- which has + * interesting performance effects. We hope to avoid (or + * perhaps more accurately hide) this effect by maintaining + * the min_clean_size, which should force us to start flushing + * entries long before we actually have to evict something + * to make space. + * + * + * Missing entries? + * + * + * JRM -- 5/8/20 + * Updated for the possibility that the slist will be + * disabled. + * *------------------------------------------------------------------------- */ herr_t @@ -2996,9 +3400,15 @@ H5C_unprotect(H5F_t *f, haddr_t addr, void *thing, unsigned flags) HDassert( H5F_addr_defined(addr) ); HDassert( thing ); HDassert( ! ( pin_entry && unpin_entry ) ); - HDassert( ( ! free_file_space ) || ( deleted ) ); /* deleted flag must accompany free_file_space */ - HDassert( ( ! take_ownership ) || ( deleted ) ); /* deleted flag must accompany take_ownership */ - HDassert( ! ( free_file_space && take_ownership ) ); /* can't have both free_file_space & take_ownership */ + + /* deleted flag must accompany free_file_space */ + HDassert( ( ! free_file_space ) || ( deleted ) ); + + /* deleted flag must accompany take_ownership */ + HDassert( ( ! take_ownership ) || ( deleted ) ); + + /* can't have both free_file_space & take_ownership */ + HDassert( ! ( free_file_space && take_ownership ) ); entry_ptr = (H5C_cache_entry_t *)thing; @@ -3011,48 +3421,66 @@ H5C_unprotect(H5F_t *f, haddr_t addr, void *thing, unsigned flags) was_clean = ! ( entry_ptr->is_dirty ); #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") + 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") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ /* if the entry has multiple read only protects, just decrement * the ro_ref_counter. Don't actually unprotect until the ref count * drops to zero. */ - if(entry_ptr->ro_ref_count > 1) { + if ( entry_ptr->ro_ref_count > 1 ) { + /* Sanity check */ - HDassert(entry_ptr->is_protected); + HDassert(entry_ptr->is_protected); HDassert(entry_ptr->is_read_only); - if(dirtied) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Read only entry modified??") + if ( dirtied ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "Read only entry modified??") /* Reduce the RO ref count */ - (entry_ptr->ro_ref_count)--; + (entry_ptr->ro_ref_count)--; /* Pin or unpin the entry as requested. */ - if(pin_entry) { + if ( pin_entry ) { + /* Pin the entry from a client */ - if(H5C__pin_entry_from_client(cache_ptr, entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Can't pin entry by client") - } else if(unpin_entry) { + if ( H5C__pin_entry_from_client(cache_ptr, entry_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, \ + "Can't pin entry by client") + + } else if ( unpin_entry ) { + /* Unpin the entry from a client */ - if(H5C__unpin_entry_from_client(cache_ptr, entry_ptr, FALSE) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Can't unpin entry by client") + if ( H5C__unpin_entry_from_client(cache_ptr, entry_ptr, FALSE) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, \ + "Can't unpin entry by client") + } /* end if */ } else { - if(entry_ptr->is_read_only) { + + if ( entry_ptr->is_read_only ) { + /* Sanity check */ - HDassert(entry_ptr->ro_ref_count == 1); + HDassert(entry_ptr->ro_ref_count == 1); - if(dirtied) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Read only entry modified??") + if ( dirtied ) - entry_ptr->is_read_only = FALSE; - entry_ptr->ro_ref_count = 0; - } /* end if */ + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "Read only entry modified??") + + entry_ptr->is_read_only = FALSE; + entry_ptr->ro_ref_count = 0; + + } /* end if */ #ifdef H5_HAVE_PARALLEL /* When the H5C code is used to implement the metadata cache in the @@ -3080,63 +3508,102 @@ H5C_unprotect(H5F_t *f, haddr_t addr, void *thing, unsigned flags) } /* end if */ #endif /* H5_HAVE_PARALLEL */ - if(!entry_ptr->is_protected) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Entry already unprotected??") + if ( ! entry_ptr->is_protected ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "Entry already unprotected??") /* Mark the entry as dirty if appropriate */ entry_ptr->is_dirty = (entry_ptr->is_dirty || dirtied); - if(dirtied) - if(entry_ptr->image_up_to_date) { - entry_ptr->image_up_to_date = FALSE; - if(entry_ptr->flush_dep_nparents > 0) - if(H5C__mark_flush_dep_unserialized(entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents") + if ( dirtied ) { + + if ( entry_ptr->image_up_to_date ) { + + entry_ptr->image_up_to_date = FALSE; + + if ( entry_ptr->flush_dep_nparents > 0 ) { + + if ( H5C__mark_flush_dep_unserialized(entry_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, \ + "Can't propagate serialization status to fd parents") + + } /* end if */ } /* end if */ + } /* end if */ /* Check for newly dirtied entry */ - if(was_clean && entry_ptr->is_dirty) { + if ( was_clean && entry_ptr->is_dirty ) { + /* Update index for newly dirtied entry */ H5C__UPDATE_INDEX_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr) - /* If the entry's type has a 'notify' callback send a 'entry dirtied' - * notice now that the entry is fully integrated into the cache. + /* If the entry's type has a 'notify' callback send a + * 'entry dirtied' notice now that the entry is fully + * integrated into the cache. */ - if(entry_ptr->type->notify && - (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_DIRTIED, entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag set") + if ( ( entry_ptr->type->notify ) && + ( (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_DIRTIED, + entry_ptr) < 0 ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, \ + "can't notify client about entry dirty flag set") /* Propagate the flush dep dirty flag up the flush dependency chain - * if appropriate */ - if(entry_ptr->flush_dep_nparents > 0) - if(H5C__mark_flush_dep_dirty(entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag") - } /* end if */ + * if appropriate + */ + if ( entry_ptr->flush_dep_nparents > 0 ) { + + if ( H5C__mark_flush_dep_dirty(entry_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ + "Can't propagate flush dep dirty flag") + } + } /* end if */ /* Check for newly clean entry */ - else if(!was_clean && !entry_ptr->is_dirty) { - /* If the entry's type has a 'notify' callback send a 'entry cleaned' - * notice now that the entry is fully integrated into the cache. + else if ( ! was_clean && ! entry_ptr->is_dirty ) { + + /* If the entry's type has a 'notify' callback send a + * 'entry cleaned' notice now that the entry is fully + * integrated into the cache. */ - if(entry_ptr->type->notify && - (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag cleared") + if ( ( entry_ptr->type->notify ) && + ( (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, + entry_ptr) < 0 ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, \ + "can't notify client about entry dirty flag cleared") /* Propagate the flush dep clean flag up the flush dependency chain - * if appropriate */ - if(entry_ptr->flush_dep_nparents > 0) - if(H5C__mark_flush_dep_clean(entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag") + * if appropriate + */ + if ( entry_ptr->flush_dep_nparents > 0 ) { + + if ( H5C__mark_flush_dep_clean(entry_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ + "Can't propagate flush dep dirty flag") + + } } /* end else-if */ /* Pin or unpin the entry as requested. */ - if(pin_entry) { + if ( pin_entry ) { + /* Pin the entry from a client */ - if(H5C__pin_entry_from_client(cache_ptr, entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Can't pin entry by client") - } else if(unpin_entry) { + if ( H5C__pin_entry_from_client(cache_ptr, entry_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, \ + "Can't pin entry by client") + + } else if ( unpin_entry ) { + /* Unpin the entry from a client */ - if(H5C__unpin_entry_from_client(cache_ptr, entry_ptr, FALSE) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Can't unpin entry by client") + if ( H5C__unpin_entry_from_client(cache_ptr, entry_ptr, FALSE) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, \ + "Can't unpin entry by client") } /* end if */ /* H5C__UPDATE_RP_FOR_UNPROTECT will place the unprotected entry on @@ -3149,10 +3616,15 @@ H5C_unprotect(H5F_t *f, haddr_t addr, void *thing, unsigned flags) /* if the entry is dirty, 'or' its flush_marker with the set flush flag, * and then add it to the skip list if it isn't there already. */ - if(entry_ptr->is_dirty) { + if ( entry_ptr->is_dirty ) { + entry_ptr->flush_marker |= set_flush_marker; - if(!entry_ptr->in_slist) + + if ( !entry_ptr->in_slist ) { + + /* this is a no-op if cache_ptr->slist_enabled is FALSE */ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) + } } /* end if */ /* this implementation of the "deleted" option is a bit inefficient, as @@ -3164,44 +3636,71 @@ H5C_unprotect(H5F_t *f, haddr_t addr, void *thing, unsigned flags) * makes good use of existing code. * JRM - 5/19/04 */ - if(deleted) { - unsigned flush_flags = (H5C__FLUSH_CLEAR_ONLY_FLAG | - H5C__FLUSH_INVALIDATE_FLAG); + if ( deleted ) { + + unsigned flush_flags = (H5C__FLUSH_CLEAR_ONLY_FLAG | + H5C__FLUSH_INVALIDATE_FLAG); /* verify that the target entry is in the cache. */ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL) - if(test_entry_ptr == NULL) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "entry not in hash table?!?") - else if(test_entry_ptr != entry_ptr) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "hash table contains multiple entries for addr?!?") + + if ( test_entry_ptr == NULL ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "entry not in hash table?!?") + + else if ( test_entry_ptr != entry_ptr ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "hash table contains multiple entries for addr?!?") /* Set the 'free file space' flag for the flush, if needed */ - if(free_file_space) + if ( free_file_space ) { + flush_flags |= H5C__FREE_FILE_SPACE_FLAG; + } /* Set the "take ownership" flag for the flush, if needed */ - if(take_ownership) + if ( take_ownership ) { + flush_flags |= H5C__TAKE_OWNERSHIP_FLAG; + } /* Delete the entry from the skip list on destroy */ flush_flags |= H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG; - HDassert(((!was_clean) || dirtied) == entry_ptr->in_slist); - if(H5C__flush_single_entry(f, entry_ptr, flush_flags) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Can't flush entry") + HDassert( ( ! cache_ptr->slist_enabled ) || \ + ( ( ( ! was_clean ) || dirtied ) == \ + ( entry_ptr->in_slist ) ) ); + + if ( H5C__flush_single_entry(f, entry_ptr, flush_flags) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "Can't flush entry") + } /* end if */ #ifdef H5_HAVE_PARALLEL - else if(clear_entry) { + else if ( clear_entry ) { /* verify that the target entry is in the cache. */ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL) - if(test_entry_ptr == NULL) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "entry not in hash table?!?") - else if(test_entry_ptr != entry_ptr) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "hash table contains multiple entries for addr?!?") - if(H5C__flush_single_entry(f, entry_ptr, H5C__FLUSH_CLEAR_ONLY_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Can't clear entry") + if ( test_entry_ptr == NULL ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "entry not in hash table?!?") + + else if ( test_entry_ptr != entry_ptr ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "hash table contains multiple entries for addr?!?") + + if ( H5C__flush_single_entry(f, entry_ptr, + H5C__FLUSH_CLEAR_ONLY_FLAG | + H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) < 0 ) + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "Can't clear entry") + } /* end else if */ #endif /* H5_HAVE_PARALLEL */ } @@ -3209,14 +3708,18 @@ H5C_unprotect(H5F_t *f, haddr_t addr, void *thing, unsigned flags) H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr) done: + #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)) { - HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit") + if ( ( H5C_validate_protected_entry_list(cache_ptr) < 0 ) || + ( H5C_validate_pinned_entry_list(cache_ptr) < 0 ) || + ( H5C_validate_lru_list(cache_ptr) < 0 ) ) { + + HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "an extreme sanity check failed on exit") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ FUNC_LEAVE_NOAPI(ret_value) + } /* H5C_unprotect() */ @@ -3962,8 +4465,8 @@ H5C__auto_adjust_cache_size(H5F_t *f, hbool_t write_permitted) HDassert( (cache_ptr->resize_ctl).min_clean_fraction <= (double)100.0f ); /* check to see if cache_ptr->resize_in_progress is TRUE. If it, this - * is a re-entrant call via a client callback called in the resize - * process. To avoid an infinite recursion, set reentrant_call to + * is a re-entrant call via a client callback called in the resize + * process. To avoid an infinite recursion, set reentrant_call to * TRUE, and goto done. */ if(cache_ptr->resize_in_progress) { @@ -4260,11 +4763,8 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5C__autoadjust__ageout(H5F_t * f, - double hit_rate, - enum H5C_resize_status * status_ptr, - size_t * new_max_cache_size_ptr, - hbool_t write_permitted) +H5C__autoadjust__ageout(H5F_t * f, double hit_rate, enum H5C_resize_status * status_ptr, + size_t * new_max_cache_size_ptr, hbool_t write_permitted) { H5C_t * cache_ptr = f->shared->cache; size_t test_size; @@ -5031,6 +5531,7 @@ done: /*------------------------------------------------------------------------- + * * Function: H5C__flush_invalidate_cache * * Purpose: Flush and destroy the entries contained in the target @@ -5060,6 +5561,51 @@ done: * Programmer: John Mainzer * 3/24/065 * + * Modifications: + * + * To support the fractal heap, the cache must now deal with + * entries being dirtied, resized, and/or renamed inside + * flush callbacks. Updated function to support this. + * + * -- JRM 8/27/06 + * + * Added code to detect and manage the case in which a + * flush callback changes the s-list out from under + * the function. The only way I can think of in which this + * can happen is if a flush function loads an entry + * into the cache that isn't there already. Quincey tells + * me that this will never happen, but I'm not sure I + * believe him. + * + * Note that this is a pretty bad scenario if it ever + * happens. The code I have added should allow us to + * handle the situation under all but the worst conditions, + * but one can argue that we should just scream and die if + * we ever detect the condition. + * + * -- JRM 10/13/07 + * + * Missing entries? + * + * + * Added support for the H5C__EVICT_ALLOW_LAST_PINS_FLAG. + * This flag is used to flush and evict all entries in + * the metadata cache that are not pinned -- typically, + * everything other than the superblock. + * + * ??? -- ??/??/?? + * + * Added sanity checks to verify that the skip list is + * enabled on entry. On the face of it, it would make + * sense to enable the slist on entry, and disable it + * on exit, as this function is not called repeatedly. + * However, since this function can be called from + * H5C_flush_cache(), this would create cases in the test + * code where we would have to check the flags to determine + * whether we must setup and take down the slist. + * + * JRM -- 5/5/20 + * *------------------------------------------------------------------------- */ static herr_t @@ -5077,6 +5623,7 @@ H5C__flush_invalidate_cache(H5F_t *f, unsigned flags) HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(cache_ptr->slist_ptr); + HDassert(cache_ptr->slist_enabled); #if H5C_DO_SANITY_CHECKS { @@ -5095,7 +5642,8 @@ H5C__flush_invalidate_cache(H5F_t *f, unsigned flags) 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++) { + 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]; @@ -5103,6 +5651,7 @@ H5C__flush_invalidate_cache(H5F_t *f, unsigned flags) 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); @@ -5115,49 +5664,68 @@ H5C__flush_invalidate_cache(H5F_t *f, unsigned flags) #endif /* H5C_DO_SANITY_CHECKS */ /* remove ageout markers if present */ - if(cache_ptr->epoch_markers_active > 0) - if(H5C__autoadjust__ageout__remove_all_markers(cache_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "error removing all epoch markers") + if ( cache_ptr->epoch_markers_active > 0 ) { + + if ( H5C__autoadjust__ageout__remove_all_markers(cache_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "error removing all epoch markers") + } /* flush invalidate each ring, starting from the outermost ring and * working inward. */ ring = H5C_RING_USER; - while(ring < H5C_RING_NTYPES) { + + while ( ring < H5C_RING_NTYPES) { + if(H5C_flush_invalidate_ring(f, ring, flags) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush invalidate ring failed") + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, + "flush invalidate ring failed") ring++; + } /* end while */ /* Invariants, after destroying all entries in the hash table */ - if(!(flags & H5C__EVICT_ALLOW_LAST_PINS_FLAG)) { + if( ! ( flags & H5C__EVICT_ALLOW_LAST_PINS_FLAG ) ) { + HDassert(cache_ptr->index_size == 0); HDassert(cache_ptr->clean_index_size == 0); HDassert(cache_ptr->pel_len == 0); HDassert(cache_ptr->pel_size == 0); + } /* end if */ else { + H5C_cache_entry_t *entry_ptr; /* Cache entry */ unsigned u; /* Local index variable */ /* All rings except ring 4 should be empty now */ /* (Ring 4 has the superblock) */ - for(u = H5C_RING_USER; u < H5C_RING_SB; u++) { + for ( u = H5C_RING_USER; u < H5C_RING_SB; u++ ) { + HDassert(cache_ptr->index_ring_len[u] == 0); HDassert(cache_ptr->index_ring_size[u] == 0); HDassert(cache_ptr->clean_index_ring_size[u] == 0); + } /* end for */ /* Check that any remaining pinned entries are in the superblock ring */ + entry_ptr = cache_ptr->pel_head_ptr; + while(entry_ptr) { + /* Check ring */ HDassert(entry_ptr->ring == H5C_RING_SB); - + /* Advance to next entry in pinned entry list */ entry_ptr = entry_ptr->next; + } /* end while */ } /* end else */ + HDassert(cache_ptr->dirty_index_size == 0); HDassert(cache_ptr->slist_len == 0); HDassert(cache_ptr->slist_size == 0); @@ -5167,43 +5735,59 @@ H5C__flush_invalidate_cache(H5F_t *f, unsigned flags) HDassert(cache_ptr->LRU_list_size == 0); done: + FUNC_LEAVE_NOAPI(ret_value) + } /* H5C__flush_invalidate_cache() */ /*------------------------------------------------------------------------- * Function: H5C_flush_invalidate_ring * - * Purpose: Flush and destroy the entries contained in the target - * cache and ring. + * Purpose: Flush and destroy the entries contained in the target + * cache and ring. * - * If the ring contains protected entries, the function will - * fail, as protected entries cannot be either flushed or - * destroyed. However all unprotected entries should be - * flushed and destroyed before the function returns failure. + * If the ring contains protected entries, the function will + * fail, as protected entries cannot be either flushed or + * destroyed. However all unprotected entries should be + * flushed and destroyed before the function returns failure. * - * While pinned entries can usually be flushed, they cannot - * be destroyed. However, they should be unpinned when all - * the entries that reference them have been destroyed (thus - * reduding the pinned entry's reference count to 0, allowing - * it to be unpinned). + * While pinned entries can usually be flushed, they cannot + * be destroyed. However, they should be unpinned when all + * the entries that reference them have been destroyed (thus + * reduding the pinned entry's reference count to 0, allowing + * it to be unpinned). * - * If pinned entries are present, the function makes repeated - * passes through the cache, flushing all dirty entries - * (including the pinned dirty entries where permitted) and - * destroying all unpinned entries. This process is repeated - * until either the cache is empty, or the number of pinned - * entries stops decreasing on each pass. + * If pinned entries are present, the function makes repeated + * passes through the cache, flushing all dirty entries + * (including the pinned dirty entries where permitted) and + * destroying all unpinned entries. This process is repeated + * until either the cache is empty, or the number of pinned + * entries stops decreasing on each pass. * - * If flush dependencies appear in the target ring, the - * function makes repeated passes through the cache flushing - * entries in flush dependency order. + * If flush dependencies appear in the target ring, the + * function makes repeated passes through the cache flushing + * entries in flush dependency order. * * Return: Non-negative on success/Negative on failure or if there was - * a request to flush all items and something was protected. + * a request to flush all items and something was protected. * * Programmer: John Mainzer - * 9/1/15 + * 9/1/15 + * + * Changes: Added support for the H5C__EVICT_ALLOW_LAST_PINS_FLAG. + * This flag is used to flush and evict all entries in + * the metadata cache that are not pinned -- typically, + * everything other than the superblock. + * + * ??? -- ??/??/?? + * + * A recent optimization turns off the slist unless a flush + * is in progress. This should not effect this function, as + * it is only called during a flush. Added an assertion to + * verify this. + * + * JRM -- 5/6/20 * *------------------------------------------------------------------------- */ @@ -5231,9 +5815,12 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) 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_enabled); HDassert(cache_ptr->slist_ptr); HDassert(ring > H5C_RING_UNDEFINED); HDassert(ring < H5C_RING_NTYPES); @@ -5248,8 +5835,8 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) /* The flush procedure here is a bit strange. * * In the outer while loop we make at least one pass through the - * cache, and then repeat until either all the pinned entries in - * the ring unpin themselves, or until the number of pinned entries + * cache, and then repeat until either all the pinned entries in + * the ring unpin themselves, or until the number of pinned entries * in the ring stops declining. In this later case, we scream and die. * * Since the fractal heap can dirty, resize, and/or move entries @@ -5275,19 +5862,25 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) */ /* compute the number of pinned entries in this ring */ + entry_ptr = cache_ptr->pel_head_ptr; cur_ring_pel_len = 0; - while(entry_ptr != NULL) { + + while ( entry_ptr != NULL ) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(entry_ptr->ring >= ring); if(entry_ptr->ring == ring) cur_ring_pel_len++; entry_ptr = entry_ptr->next; + } /* end while */ old_ring_pel_len = cur_ring_pel_len; + while(cache_ptr->index_ring_len[ring] > 0) { + /* first, try to flush-destroy any dirty entries. Do this by * making a scan through the slist. Note that new dirty entries * may be created by the flush call backs. Thus it is possible @@ -5305,9 +5898,9 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) /* There is also the possibility that entries will be * dirtied, resized, moved, and/or removed from the cache - * as the result of calls to the flush callbacks. We use - * the slist_len_increase and slist_size_increase increase - * fields in struct H5C_t to track these changes for purpose + * as the result of calls to the flush callbacks. We use + * the slist_len_increase and slist_size_increase increase + * fields in struct H5C_t to track these changes for purpose * of sanity checking. * * To this end, we must zero these fields before we start @@ -5322,45 +5915,53 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) * This flag is set to TRUE by H5C__flush_single_entry if the slist * is modified by a pre_serialize, serialize, or notify callback. * - * H5C_flush_invalidate_ring() uses this flag to detect any - * modifications to the slist that might corrupt the scan of + * H5C_flush_invalidate_ring() uses this flag to detect any + * modifications to the slist that might corrupt the scan of * the slist -- and restart the scan in this event. */ cache_ptr->slist_changed = FALSE; /* this done, start the scan of the slist */ restart_slist_scan = TRUE; - while(restart_slist_scan || (node_ptr != NULL)) { - if(restart_slist_scan) { + + while ( restart_slist_scan || ( node_ptr != NULL ) ) { + + if ( restart_slist_scan ) { + restart_slist_scan = FALSE; /* Start at beginning of skip list */ node_ptr = H5SL_first(cache_ptr->slist_ptr); - if(node_ptr == NULL) + + if ( node_ptr == NULL ) /* the slist is empty -- break out of inner loop */ break; /* Get cache entry for this node */ next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); - if(NULL == next_entry_ptr) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "next_entry_ptr == NULL ?!?!") + + if ( NULL == next_entry_ptr ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "next_entry_ptr == NULL ?!?!") HDassert(next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(next_entry_ptr->is_dirty); HDassert(next_entry_ptr->in_slist); HDassert(next_entry_ptr->ring >= ring); + } /* end if */ entry_ptr = next_entry_ptr; - /* It is possible that entries will be dirtied, resized, + /* It is possible that entries will be dirtied, resized, * flushed, or removed from the cache via the take ownership - * flag as the result of pre_serialize or serialized callbacks. - * + * flag as the result of pre_serialize or serialized callbacks. + * * This in turn can corrupt the scan through the slist. * - * We test for slist modifications in the pre_serialize - * and serialize callbacks, and restart the scan of the + * We test for slist modifications in the pre_serialize + * and serialize callbacks, and restart the scan of the * slist if we find them. However, best we do some extra * sanity checking just in case. */ @@ -5374,18 +5975,26 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) * from the slist. */ node_ptr = H5SL_next(node_ptr); + if(node_ptr != NULL) { + next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); + if(NULL == next_entry_ptr) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "next_entry_ptr == NULL ?!?!") + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "next_entry_ptr == NULL ?!?!") + HDassert(next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(next_entry_ptr->is_dirty); HDassert(next_entry_ptr->in_slist); HDassert(next_entry_ptr->ring >= ring); HDassert(entry_ptr != next_entry_ptr); } /* end if */ - else + else { + next_entry_ptr = NULL; + } /* Note that we now remove nodes from the slist as we flush * the associated entries, instead of leaving them there @@ -5397,22 +6006,31 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) * flush, we must keep the slist in canonical form at all * times. */ - if(((!entry_ptr->flush_me_last) || - ((entry_ptr->flush_me_last) && - (cache_ptr->num_last_entries >= cache_ptr->slist_len))) && - (entry_ptr->flush_dep_nchildren == 0) && - (entry_ptr->ring == ring)) { - if(entry_ptr->is_protected) { + if ( ( ( !entry_ptr->flush_me_last ) || + ( ( entry_ptr->flush_me_last ) && + ( cache_ptr->num_last_entries >= cache_ptr->slist_len ) ) + ) && + ( entry_ptr->flush_dep_nchildren == 0 ) && + ( entry_ptr->ring == ring ) ) { + + if ( entry_ptr->is_protected ) { + /* we have major problems -- but lets flush * everything we can before we flag an error. */ protected_entries++; + } /* end if */ - else if(entry_ptr->is_pinned) { - if(H5C__flush_single_entry(f, entry_ptr, H5C__DURING_FLUSH_FLAG) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "dirty pinned entry flush failed") + else if ( entry_ptr->is_pinned ) { + + if ( H5C__flush_single_entry(f, entry_ptr, + H5C__DURING_FLUSH_FLAG) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "dirty pinned entry flush failed") + + if ( cache_ptr->slist_changed ) { - if(cache_ptr->slist_changed) { /* The slist has been modified by something * other than the simple removal of the * of the flushed entry after the flush. @@ -5423,13 +6041,22 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) restart_slist_scan = TRUE; cache_ptr->slist_changed = FALSE; H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr); + } /* end if */ } /* end else-if */ else { - if(H5C__flush_single_entry(f, entry_ptr, (cooked_flags | H5C__DURING_FLUSH_FLAG | H5C__FLUSH_INVALIDATE_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG)) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "dirty entry flush destroy failed") - if(cache_ptr->slist_changed) { + if ( H5C__flush_single_entry(f, entry_ptr, + (cooked_flags | + H5C__DURING_FLUSH_FLAG | + H5C__FLUSH_INVALIDATE_FLAG | + H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) ) < 0) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, + "dirty entry flush destroy failed") + + if ( cache_ptr->slist_changed ) { + /* The slist has been modified by something * other than the simple removal of the * of the flushed entry after the flush. @@ -5455,9 +6082,15 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) * out from under us. */ - if(node_ptr == NULL) { - HDassert(cache_ptr->slist_len == (uint32_t)((int32_t)initial_slist_len + cache_ptr->slist_len_increase)); - HDassert(cache_ptr->slist_size == (size_t)((ssize_t)initial_slist_size + cache_ptr->slist_size_increase)); + if ( node_ptr == NULL ) { + + HDassert(cache_ptr->slist_len == + (uint32_t)((int32_t)initial_slist_len + + cache_ptr->slist_len_increase)); + + HDassert(cache_ptr->slist_size == + (size_t)((ssize_t)initial_slist_size + + cache_ptr->slist_size_increase)); } /* end if */ #endif /* H5C_DO_SANITY_CHECKS */ @@ -5481,7 +6114,9 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) cache_ptr->entries_relocated_counter = 0; next_entry_ptr = cache_ptr->il_head; - while(next_entry_ptr != NULL) { + + while ( next_entry_ptr != NULL ) { + entry_ptr = next_entry_ptr; HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(entry_ptr->ring >= ring); @@ -5490,21 +6125,31 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) HDassert((next_entry_ptr == NULL) || (next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC)); - if((!entry_ptr->flush_me_last || (entry_ptr->flush_me_last && cache_ptr->num_last_entries >= cache_ptr->slist_len)) - && entry_ptr->flush_dep_nchildren == 0 && entry_ptr->ring == ring) { - if(entry_ptr->is_protected) { - /* we have major problems -- but lets flush and - * destroy everything we can before we flag an + if ( ( ( ! entry_ptr->flush_me_last ) || + ( entry_ptr->flush_me_last && + ( cache_ptr->num_last_entries >= cache_ptr->slist_len ) ) + ) && + ( entry_ptr->flush_dep_nchildren == 0 ) && + ( entry_ptr->ring == ring ) ) { + + if ( entry_ptr->is_protected ) { + + /* we have major problems -- but lets flush and + * destroy everything we can before we flag an * error. */ protected_entries++; - if(!entry_ptr->in_slist) + + if ( ! entry_ptr->in_slist ) { + HDassert(!(entry_ptr->is_dirty)); + } } /* end if */ - else if(!(entry_ptr->is_pinned)) { - /* if *entry_ptr is dirty, it is possible - * that one or more other entries may be - * either removed from the cache, loaded + else if ( ! ( entry_ptr->is_pinned ) ) { + + /* if *entry_ptr is dirty, it is possible + * that one or more other entries may be + * either removed from the cache, loaded * into the cache, or moved to a new location * in the file as a side effect of the flush. * @@ -5513,14 +6158,14 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) * entry, allowing it to be removed also and * invalidating the next_entry_ptr. * - * If either of these happen, and one of the target - * or proxy entries happens to be the next entry in + * If either of these happen, and one of the target + * or proxy entries happens to be the next entry in * the hash bucket, we could either find ourselves * either scanning a non-existant entry, scanning * through a different bucket, or skipping an entry. * - * Neither of these are good, so restart the - * the scan at the head of the hash bucket + * Neither of these are good, so restart the + * the scan at the head of the hash bucket * after the flush if we detect that the next_entry_ptr * becomes invalid. * @@ -5530,21 +6175,29 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) */ cache_ptr->entry_watched_for_removal = next_entry_ptr; - if(H5C__flush_single_entry(f, entry_ptr, (cooked_flags | H5C__DURING_FLUSH_FLAG | H5C__FLUSH_INVALIDATE_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG)) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Entry flush destroy failed") + if ( H5C__flush_single_entry(f, entry_ptr, + (cooked_flags | + H5C__DURING_FLUSH_FLAG | + H5C__FLUSH_INVALIDATE_FLAG | + H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG)) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Entry flush destroy failed") /* Restart the index list scan if necessary. Must - * do this if the next entry is evicted, and also if + * do this if the next entry is evicted, and also if * one or more entries are inserted, loaded, or moved * as these operations can result in part of the scan * being skipped -- which can cause a spurious failure - * if this results in the size of the pinned entry + * if this results in the size of the pinned entry * failing to decline during the pass. */ - if((NULL != next_entry_ptr && NULL == cache_ptr->entry_watched_for_removal) - || (cache_ptr->entries_loaded_counter > 0) - || (cache_ptr->entries_inserted_counter > 0) - || (cache_ptr->entries_relocated_counter > 0)) { + if ( ( ( NULL != next_entry_ptr ) && + ( NULL == cache_ptr->entry_watched_for_removal ) + ) || + ( cache_ptr->entries_loaded_counter > 0 ) || + ( cache_ptr->entries_inserted_counter > 0 ) || + ( cache_ptr->entries_relocated_counter > 0 ) ) { next_entry_ptr = cache_ptr->il_head; @@ -5553,9 +6206,12 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) cache_ptr->entries_relocated_counter = 0; H5C__UPDATE_STATS_FOR_INDEX_SCAN_RESTART(cache_ptr) + } /* end if */ - else + else { + cache_ptr->entry_watched_for_removal = NULL; + } } /* end if */ } /* end if */ } /* end for loop scanning hash table */ @@ -5571,35 +6227,53 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) old_ring_pel_len = cur_ring_pel_len; entry_ptr = cache_ptr->pel_head_ptr; cur_ring_pel_len = 0; - while(entry_ptr != NULL) { + + while ( entry_ptr != NULL ) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(entry_ptr->ring >= ring); - if(entry_ptr->ring == ring) + if ( entry_ptr->ring == ring ) { + cur_ring_pel_len++; + } entry_ptr = entry_ptr->next; + } /* end while */ - /* Check if the number of pinned entries in the ring is positive, and + /* Check if the number of pinned entries in the ring is positive, and * it is not declining. Scream and die if so. */ - if(cur_ring_pel_len > 0 && cur_ring_pel_len >= old_ring_pel_len) { + if ( ( cur_ring_pel_len > 0 ) && + ( cur_ring_pel_len >= old_ring_pel_len ) ) { + /* Don't error if allowed to have pinned entries remaining */ - if(evict_flags) + if ( evict_flags ) { + HGOTO_DONE(TRUE) + } - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Pinned entry count not decreasing, cur_ring_pel_len = %d, old_ring_pel_len = %d, ring = %d", (int)cur_ring_pel_len, (int)old_ring_pel_len, (int)ring) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Pinned entry count not decreasing, cur_ring_pel_len = %d, old_ring_pel_len = %d, ring = %d", \ + (int)cur_ring_pel_len, \ + (int)old_ring_pel_len, (int)ring) } /* end if */ HDassert(protected_entries == cache_ptr->pl_len); - if(protected_entries > 0 && protected_entries == cache_ptr->index_len) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Only protected entries left in cache, protected_entries = %d", (int)protected_entries) + if ( ( protected_entries > 0 ) && + ( protected_entries == cache_ptr->index_len ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Only protected entries left in cache, protected_entries = %d",\ + (int)protected_entries) + } /* main while loop */ /* Invariants, after destroying all entries in the ring */ - for(i = (int)H5C_RING_UNDEFINED; i <= (int)ring; i++) { + for ( i = (int)H5C_RING_UNDEFINED; i <= (int)ring; i++ ) { + HDassert(cache_ptr->index_ring_len[i] == 0); HDassert(cache_ptr->index_ring_size[i] == (size_t)0); HDassert(cache_ptr->clean_index_ring_size[i] == (size_t)0); @@ -5607,41 +6281,59 @@ H5C_flush_invalidate_ring(H5F_t * f, H5C_ring_t ring, unsigned flags) HDassert(cache_ptr->slist_ring_len[i] == 0); HDassert(cache_ptr->slist_ring_size[i] == (size_t)0); + } /* end for */ HDassert(protected_entries <= cache_ptr->pl_len); - if(protected_entries > 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cache has protected entries") - else if(cur_ring_pel_len > 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't unpin all pinned entries in ring") + if ( protected_entries > 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Cache has protected entries") + + } else if ( cur_ring_pel_len > 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Can't unpin all pinned entries in ring") + } done: + FUNC_LEAVE_NOAPI(ret_value) + } /* H5C_flush_invalidate_ring() */ /*------------------------------------------------------------------------- + * * Function: H5C__flush_ring * - * Purpose: Flush the entries contained in the specified cache and - * ring. All entries in rings outside the specified ring - * must have been flushed on entry. + * Purpose: Flush the entries contained in the specified cache and + * ring. All entries in rings outside the specified ring + * must have been flushed on entry. * - * If the cache contains protected entries in the specified - * ring, the function will fail, as protected entries cannot - * be flushed. However all unprotected entries in the target - * ring should be flushed before the function returns failure. + * If the cache contains protected entries in the specified + * ring, the function will fail, as protected entries cannot + * be flushed. However all unprotected entries in the target + * ring should be flushed before the function returns failure. * - * If flush dependencies appear in the target ring, the - * function makes repeated passes through the slist flushing - * entries in flush dependency order. + * If flush dependencies appear in the target ring, the + * function makes repeated passes through the slist flushing + * entries in flush dependency order. * * Return: Non-negative on success/Negative on failure or if there was - * a request to flush all items and something was protected. + * a request to flush all items and something was protected. * * Programmer: John Mainzer - * 9/1/15 + * 9/1/15 + * + * Changes: A recent optimization turns off the slist unless a flush + * is in progress. This should not effect this function, as + * it is only called during a flush. Added an assertion to + * verify this. + * + * JRM -- 5/6/20 + * * *------------------------------------------------------------------------- */ @@ -5669,24 +6361,31 @@ H5C__flush_ring(H5F_t *f, H5C_ring_t ring, unsigned flags) HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(cache_ptr->slist_enabled); HDassert(cache_ptr->slist_ptr); HDassert((flags & H5C__FLUSH_INVALIDATE_FLAG) == 0); HDassert(ring > H5C_RING_UNDEFINED); HDassert(ring < H5C_RING_NTYPES); #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") + 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") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ ignore_protected = ( (flags & H5C__FLUSH_IGNORE_PROTECTED_FLAG) != 0 ); flush_marked_entries = ( (flags & H5C__FLUSH_MARKED_ENTRIES_FLAG) != 0 ); - if(!flush_marked_entries) - for(i = (int)H5C_RING_UNDEFINED; i < (int)ring; i++) - HDassert(cache_ptr->slist_ring_len[i] == 0); + if ( ! flush_marked_entries ) { + + for ( i = (int)H5C_RING_UNDEFINED; i < (int)ring; i++ ) { + + HDassert(cache_ptr->slist_ring_len[i] == 0); + } + } HDassert(cache_ptr->flush_in_progress); @@ -5699,17 +6398,18 @@ H5C__flush_ring(H5F_t *f, H5C_ring_t ring, unsigned flags) /* Set the cache_ptr->slist_changed to false. * - * This flag is set to TRUE by H5C__flush_single_entry if the + * This flag is set to TRUE by H5C__flush_single_entry if the * slist is modified by a pre_serialize, serialize, or notify callback. * H5C_flush_cache uses this flag to detect any modifications - * to the slist that might corrupt the scan of the slist -- and + * to the slist that might corrupt the scan of the slist -- and * restart the scan in this event. */ cache_ptr->slist_changed = FALSE; - while((cache_ptr->slist_ring_len[ring] > 0) && - (protected_entries == 0) && - (flushed_entries_last_pass)) { + while ( ( cache_ptr->slist_ring_len[ring] > 0 ) && + ( protected_entries == 0 ) && + ( flushed_entries_last_pass ) ) { + flushed_entries_last_pass = FALSE; #if H5C_DO_SANITY_CHECKS @@ -5722,8 +6422,8 @@ H5C__flush_ring(H5F_t *f, H5C_ring_t ring, unsigned flags) * * To make things more entertaining, with the advent of the * fractal heap, the entry serialize callback can cause entries - * to be dirtied, resized, and/or moved. Also, the - * pre_serialize callback can result in an entry being + * to be dirtied, resized, and/or moved. Also, the + * pre_serialize callback can result in an entry being * removed from the cache via the take ownership flag. * * To deal with this, we first make note of the initial @@ -5753,136 +6453,177 @@ H5C__flush_ring(H5F_t *f, H5C_ring_t ring, unsigned flags) restart_slist_scan = TRUE; - while((restart_slist_scan ) || (node_ptr != NULL)) { - if(restart_slist_scan) { + while ( ( restart_slist_scan ) || ( node_ptr != NULL ) ) { + + if ( restart_slist_scan ) { + restart_slist_scan = FALSE; /* Start at beginning of skip list */ node_ptr = H5SL_first(cache_ptr->slist_ptr); - if(node_ptr == NULL) + if ( node_ptr == NULL ) { + /* the slist is empty -- break out of inner loop */ break; + } /* Get cache entry for this node */ next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); - if(NULL == next_entry_ptr) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "next_entry_ptr == NULL ?!?!") + if ( NULL == next_entry_ptr ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "next_entry_ptr == NULL ?!?!") HDassert(next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(next_entry_ptr->is_dirty); HDassert(next_entry_ptr->in_slist); + } /* end if */ - + entry_ptr = next_entry_ptr; /* With the advent of the fractal heap, the free space * manager, and the version 3 cache, it is possible - * that the pre-serialize or serialize callback will - * dirty, resize, or take ownership of other entries - * in the cache. + * that the pre-serialize or serialize callback will + * dirty, resize, or take ownership of other entries + * in the cache. * * To deal with this, I have inserted code to detect any * change in the skip list not directly under the control * of this function. If such modifications are detected, - * we must re-start the scan of the skip list to avoid + * we must re-start the scan of the skip list to avoid * the possibility that the target of the next_entry_ptr * may have been flushed or deleted from the cache. * * To verify that all such possibilities have been dealt - * with, we do a bit of extra sanity checking on + * with, we do a bit of extra sanity checking on * entry_ptr. */ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(entry_ptr->in_slist); HDassert(entry_ptr->is_dirty); - if(!flush_marked_entries || entry_ptr->flush_marker) + + if ( ( ! flush_marked_entries ) || ( entry_ptr->flush_marker ) ) { + HDassert(entry_ptr->ring >= ring); + } /* Advance node pointer now, before we delete its target * from the slist. */ node_ptr = H5SL_next(node_ptr); - if(node_ptr != NULL) { + + if ( node_ptr != NULL ) { + next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); - if(NULL == next_entry_ptr) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "next_entry_ptr == NULL ?!?!") + + if ( NULL == next_entry_ptr ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "next_entry_ptr == NULL ?!?!") HDassert(next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(next_entry_ptr->is_dirty); HDassert(next_entry_ptr->in_slist); - if(!flush_marked_entries || next_entry_ptr->flush_marker) + if ( ! flush_marked_entries || next_entry_ptr->flush_marker ) { + HDassert(next_entry_ptr->ring >= ring); + } HDassert(entry_ptr != next_entry_ptr); + } /* end if */ - else + else { + next_entry_ptr = NULL; + } - if((!flush_marked_entries || entry_ptr->flush_marker) - && (!entry_ptr->flush_me_last || - (entry_ptr->flush_me_last - && (cache_ptr->num_last_entries >= cache_ptr->slist_len - || (flush_marked_entries && entry_ptr->flush_marker)))) - && (entry_ptr->flush_dep_nchildren == 0 - || entry_ptr->flush_dep_ndirty_children == 0) - && entry_ptr->ring == ring) { + if ( ( ! flush_marked_entries || entry_ptr->flush_marker ) && + ( ( ! entry_ptr->flush_me_last ) || + ( ( entry_ptr->flush_me_last ) && + ( ( cache_ptr->num_last_entries >= cache_ptr->slist_len )|| + ( flush_marked_entries && entry_ptr->flush_marker ) ) + ) + ) && + ( ( entry_ptr->flush_dep_nchildren == 0 ) || + ( entry_ptr->flush_dep_ndirty_children == 0 ) ) && + ( entry_ptr->ring == ring ) ) { HDassert(entry_ptr->flush_dep_nunser_children == 0); - if(entry_ptr->is_protected) { - /* we probably have major problems -- but lets - * flush everything we can before we decide + if ( entry_ptr->is_protected ) { + + /* we probably have major problems -- but lets + * flush everything we can before we decide * whether to flag an error. */ tried_to_flush_protected_entry = TRUE; protected_entries++; + } /* end if */ else { - if(H5C__flush_single_entry(f, entry_ptr, (flags | H5C__DURING_FLUSH_FLAG)) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush entry") - if(cache_ptr->slist_changed) { + if ( H5C__flush_single_entry(f, entry_ptr, + (flags | H5C__DURING_FLUSH_FLAG)) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Can't flush entry") + + if ( cache_ptr->slist_changed ) { + /* The slist has been modified by something - * other than the simple removal of the + * other than the simple removal of the * of the flushed entry after the flush. - * + * * This has the potential to corrupt the * scan through the slist, so restart it. */ restart_slist_scan = TRUE; cache_ptr->slist_changed = FALSE; H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr) + } /* end if */ flushed_entries_last_pass = TRUE; + } /* end else */ } /* end if */ } /* while ( ( restart_slist_scan ) || ( node_ptr != NULL ) ) */ #if H5C_DO_SANITY_CHECKS /* Verify that the slist size and length are as expected. */ - HDassert((uint32_t)((int32_t)initial_slist_len + cache_ptr->slist_len_increase) == cache_ptr->slist_len); - HDassert((size_t)((ssize_t)initial_slist_size + cache_ptr->slist_size_increase) == cache_ptr->slist_size); + HDassert((uint32_t)((int32_t)initial_slist_len + \ + cache_ptr->slist_len_increase) == cache_ptr->slist_len); + HDassert((size_t)((ssize_t)initial_slist_size + \ + cache_ptr->slist_size_increase) == cache_ptr->slist_size); #endif /* H5C_DO_SANITY_CHECKS */ + } /* while */ HDassert(protected_entries <= cache_ptr->pl_len); - if(((cache_ptr->pl_len > 0) && (!ignore_protected)) || (tried_to_flush_protected_entry)) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "cache has protected items") + if ( ( ( cache_ptr->pl_len > 0 ) && ( ! ignore_protected ) ) || + ( tried_to_flush_protected_entry ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "cache has protected items") #if H5C_DO_SANITY_CHECKS - if(!flush_marked_entries) { + if ( ! flush_marked_entries ) { + HDassert(cache_ptr->slist_ring_len[ring] == 0); HDassert(cache_ptr->slist_ring_size[ring] == 0); + } /* end if */ #endif /* H5C_DO_SANITY_CHECKS */ done: + FUNC_LEAVE_NOAPI(ret_value) + } /* H5C__flush_ring() */ @@ -5891,53 +6632,110 @@ done: * Function: H5C__flush_single_entry * * Purpose: Flush or clear (and evict if requested) the cache entry - * with the specified address and type. If the type is NULL, - * any unprotected entry at the specified address will be - * flushed (and possibly evicted). + * with the specified address and type. If the type is NULL, + * any unprotected entry at the specified address will be + * flushed (and possibly evicted). * - * Attempts to flush a protected entry will result in an - * error. + * Attempts to flush a protected entry will result in an + * error. * - * If the H5C__FLUSH_INVALIDATE_FLAG flag is set, the entry will - * be cleared and not flushed, and the call can't be part of a + * If the H5C__FLUSH_INVALIDATE_FLAG flag is set, the entry will + * be cleared and not flushed, and the call can't be part of a * sequence of flushes. * - * If the caller knows the address of the skip list node at - * which the target entry resides, it can avoid a lookup - * by supplying that address in the tgt_node_ptr parameter. - * If this parameter is NULL, the function will do a skip list - * search for the entry instead. - * - * The function does nothing silently if there is no entry - * at the supplied address, or if the entry found has the - * wrong type. + * The function does nothing silently if there is no entry + * at the supplied address, or if the entry found has the + * wrong type. * * Return: Non-negative on success/Negative on failure or if there was - * an attempt to flush a protected item. + * an attempt to flush a protected item. * * Programmer: John Mainzer, 5/5/04 * + * Modifications: + * + * JRM -- 7/21/04 + * Updated function for the addition of the hash table. + * + * QAK -- 11/26/04 + * Updated function for the switch from TBBTs to skip lists. + * + * JRM -- 1/6/05 + * Updated function to reset the flush_marker field. + * Also replace references to H5F_FLUSH_INVALIDATE and + * H5F_FLUSH_CLEAR_ONLY with references to + * H5C__FLUSH_INVALIDATE_FLAG and H5C__FLUSH_CLEAR_ONLY_FLAG + * respectively. + * + * JRM -- 6/24/05 + * Added code to remove dirty entries from the slist after + * they have been flushed. Also added a sanity check that + * will scream if we attempt a write when writes are + * completely disabled. + * + * JRM -- 7/5/05 + * Added code to call the new log_flush callback whenever + * a dirty entry is written to disk. Note that the callback + * is not called if the H5C__FLUSH_CLEAR_ONLY_FLAG is set, + * as there is no write to file in this case. + * + * JRM -- 8/21/06 + * Added code maintaining the flush_in_progress and + * destroy_in_progress fields in H5C_cache_entry_t. + * + * Also added flush_flags parameter to the call to + * type_ptr->flush() so that the flush routine can report + * whether the entry has been resized or renamed. Added + * code using the flush_flags variable to detect the case + * in which the target entry is resized during flush, and + * update the caches data structures accordingly. + * + * JRM -- 3/29/07 + * Added sanity checks on the new is_read_only and + * ro_ref_count fields. + * + * QAK -- 2/07/08 + * Separated "destroy entry" concept from "remove entry from + * cache" concept, by adding the 'take_ownership' flag and + * the "destroy_entry" variable. + * + * JRM -- 11/5/08 + * Added call to H5C__UPDATE_INDEX_FOR_ENTRY_CLEAN() to + * maintain the new clean_index_size and clean_index_size + * fields of H5C_t. + * + * + * Missing entries?? + * + * + * JRM -- 5/8/20 + * Updated sanity checks for the possibility that the slist + * is disabled. + * + * Also updated main comment to conform more closely with + * the current state of the code. + * *------------------------------------------------------------------------- */ herr_t H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) { - H5C_t * cache_ptr; /* Cache for file */ - hbool_t destroy; /* external flag */ - hbool_t clear_only; /* external flag */ - hbool_t free_file_space; /* external flag */ - hbool_t take_ownership; /* external flag */ - hbool_t del_from_slist_on_destroy; /* external flag */ - hbool_t during_flush; /* external flag */ - hbool_t write_entry; /* internal flag */ - hbool_t destroy_entry; /* internal flag */ - hbool_t generate_image; /* internal flag */ - hbool_t update_page_buffer; /* internal flag */ - hbool_t was_dirty; - hbool_t suppress_image_entry_writes = FALSE; - hbool_t suppress_image_entry_frees = FALSE; - haddr_t entry_addr = HADDR_UNDEF; - herr_t ret_value = SUCCEED; /* Return value */ + H5C_t * cache_ptr; /* Cache for file */ + hbool_t destroy; /* external flag */ + hbool_t clear_only; /* external flag */ + hbool_t free_file_space; /* external flag */ + hbool_t take_ownership; /* external flag */ + hbool_t del_from_slist_on_destroy; /* external flag */ + hbool_t during_flush; /* external flag */ + hbool_t write_entry; /* internal flag */ + hbool_t destroy_entry; /* internal flag */ + hbool_t generate_image; /* internal flag */ + hbool_t update_page_buffer; /* internal flag */ + hbool_t was_dirty; + hbool_t suppress_image_entry_writes = FALSE; + hbool_t suppress_image_entry_frees = FALSE; + haddr_t entry_addr = HADDR_UNDEF; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE @@ -5951,40 +6749,52 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) HDassert(entry_ptr->type); /* setup external flags from the flags parameter */ - destroy = ((flags & H5C__FLUSH_INVALIDATE_FLAG) != 0); - clear_only = ((flags & H5C__FLUSH_CLEAR_ONLY_FLAG) != 0); - free_file_space = ((flags & H5C__FREE_FILE_SPACE_FLAG) != 0); - take_ownership = ((flags & H5C__TAKE_OWNERSHIP_FLAG) != 0); - del_from_slist_on_destroy = ((flags & H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) != 0); - during_flush = ((flags & H5C__DURING_FLUSH_FLAG) != 0); - generate_image = ((flags & H5C__GENERATE_IMAGE_FLAG) != 0); - update_page_buffer = ((flags & H5C__UPDATE_PAGE_BUFFER_FLAG) != 0); + destroy = ((flags & H5C__FLUSH_INVALIDATE_FLAG) != 0); + clear_only = ((flags & H5C__FLUSH_CLEAR_ONLY_FLAG) != 0); + free_file_space = ((flags & H5C__FREE_FILE_SPACE_FLAG) != 0); + take_ownership = ((flags & H5C__TAKE_OWNERSHIP_FLAG) != 0); + del_from_slist_on_destroy = + ((flags & H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) != 0); + during_flush = ((flags & H5C__DURING_FLUSH_FLAG) != 0); + generate_image = ((flags & H5C__GENERATE_IMAGE_FLAG) != 0); + update_page_buffer = ((flags & H5C__UPDATE_PAGE_BUFFER_FLAG) != 0); /* Set the flag for destroying the entry, based on the 'take ownership' * and 'destroy' flags */ - if(take_ownership) + if ( take_ownership ) { + destroy_entry = FALSE; - else + + } else { + destroy_entry = destroy; + } /* we will write the entry to disk if it exists, is dirty, and if the * clear only flag is not set. */ - if(entry_ptr->is_dirty && !clear_only) + if ( entry_ptr->is_dirty && !clear_only ) { + write_entry = TRUE; - else + + } else { + write_entry = FALSE; + } - /* if we have received close warning, and we have been instructed to + /* if we have received close warning, and we have been instructed to * generate a metadata cache image, and we have actually constructed * the entry images, set suppress_image_entry_frees to TRUE. * - * Set suppress_image_entry_writes to TRUE if indicated by the + * Set suppress_image_entry_writes to TRUE if indicated by the * image_ctl flags. */ - if(cache_ptr->close_warning_received && cache_ptr->image_ctl.generate_image - && cache_ptr->num_entries_in_image > 0 && cache_ptr->image_entries) { + if ( ( cache_ptr->close_warning_received ) && + ( cache_ptr->image_ctl.generate_image ) && + ( cache_ptr->num_entries_in_image > 0 ) && + ( cache_ptr->image_entries != NULL ) ) { + /* Sanity checks */ HDassert(entry_ptr->image_up_to_date || !(entry_ptr->include_in_image)); HDassert(entry_ptr->image_ptr || !(entry_ptr->include_in_image)); @@ -5994,32 +6804,60 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) suppress_image_entry_frees = TRUE; - if(cache_ptr->image_ctl.flags & H5C_CI__SUPRESS_ENTRY_WRITES) + if ( cache_ptr->image_ctl.flags & H5C_CI__SUPRESS_ENTRY_WRITES ) { + suppress_image_entry_writes = TRUE; + + } /* end if */ } /* end if */ - /* run initial sanity checks */ -#if H5C_DO_SANITY_CHECKS - if(entry_ptr->in_slist) { - HDassert(entry_ptr->is_dirty); + /* run initial sanity checks */ +#if H5C_DO_SANITY_CHECKS + if ( cache_ptr->slist_enabled ) { - if((entry_ptr->flush_marker) && (!entry_ptr->is_dirty)) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "entry in slist failed sanity checks") - } /* end if */ - else { - HDassert(!entry_ptr->is_dirty); - HDassert(!entry_ptr->flush_marker); + if ( entry_ptr->in_slist ) { - if((entry_ptr->is_dirty) || (entry_ptr->flush_marker)) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "entry failed sanity checks") - } /* end else */ + HDassert(entry_ptr->is_dirty); + + if ( ( entry_ptr->flush_marker ) && ( ! entry_ptr->is_dirty ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "entry in slist failed sanity checks") + } /* end if */ + else { + + HDassert(!entry_ptr->is_dirty); + HDassert(!entry_ptr->flush_marker); + + if ( ( entry_ptr->is_dirty ) || ( entry_ptr->flush_marker ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "entry failed sanity checks") + + } /* end else */ + } else { /* slist is disabled */ + + HDassert( ! entry_ptr->in_slist ); + + if ( ! entry_ptr->is_dirty ) { + + if ( entry_ptr->flush_marker ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "flush marked clean entry?") + + } + } #endif /* H5C_DO_SANITY_CHECKS */ - if(entry_ptr->is_protected) { + if ( entry_ptr->is_protected ) { + HDassert(!entry_ptr->is_protected); /* Attempt to flush a protected entry -- scream and die. */ - HGOTO_ERROR(H5E_CACHE, H5E_PROTECT, FAIL, "Attempt to flush a protected entry") + HGOTO_ERROR(H5E_CACHE, H5E_PROTECT, FAIL, \ + "Attempt to flush a protected entry") + } /* end if */ /* Set entry_ptr->flush_in_progress = TRUE and set @@ -6038,104 +6876,144 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) * been requested to generate an image. In those cases, serialize the * entry. */ - if(write_entry || generate_image) { + if ( write_entry || generate_image ) { + HDassert(entry_ptr->is_dirty); - if(NULL == entry_ptr->image_ptr) { - 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 ( NULL == entry_ptr->image_ptr ) { + + 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) + entry_ptr->size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); + H5MM_memcpy(((uint8_t *)entry_ptr->image_ptr) + entry_ptr->size, + H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + } /* end if */ - if(!(entry_ptr->image_up_to_date)) { + if ( ! ( entry_ptr->image_up_to_date ) ) { + /* Sanity check */ HDassert(!entry_ptr->prefetched); /* Generate the entry's image */ - if(H5C__generate_image(f, cache_ptr, entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "can't generate entry's image") + if ( H5C__generate_image(f, cache_ptr, entry_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, \ + "can't generate entry's image") + } /* end if ( ! (entry_ptr->image_up_to_date) ) */ } /* end if */ - /* Finally, write the image to disk. - * - * Note that if the H5AC__CLASS_SKIP_WRITES flag is set in the + /* Finally, write the image to disk. + * + * Note that if the H5AC__CLASS_SKIP_WRITES flag is set in the * in the entry's type, we silently skip the write. This - * flag should only be used in test code. + * flag should only be used in test code. */ - if(write_entry) { + if ( write_entry ) { + HDassert(entry_ptr->is_dirty); #if H5C_DO_SANITY_CHECKS - if(cache_ptr->check_write_permitted && !(cache_ptr->write_permitted)) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Write when writes are always forbidden!?!?!") + if ( ( cache_ptr->check_write_permitted ) && + ( ! ( cache_ptr->write_permitted ) ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Write when writes are always forbidden!?!?!") #endif /* H5C_DO_SANITY_CHECKS */ /* Write the image to disk unless the write is suppressed. * - * This happens if both suppress_image_entry_writes and - * entry_ptr->include_in_image are TRUE, or if the + * This happens if both suppress_image_entry_writes and + * entry_ptr->include_in_image are TRUE, or if the * H5AC__CLASS_SKIP_WRITES is set in the entry's type. This * flag should only be used in test code */ - if((!suppress_image_entry_writes || !entry_ptr->include_in_image) - && (((entry_ptr->type->flags) & H5C__CLASS_SKIP_WRITES) == 0)) { + if ( ( ( ! suppress_image_entry_writes ) || + ( ! entry_ptr->include_in_image ) ) && + ( ( (entry_ptr->type->flags) & H5C__CLASS_SKIP_WRITES) == 0 ) ) { + H5FD_mem_t mem_type = H5FD_MEM_DEFAULT; #ifdef H5_HAVE_PARALLEL - if(cache_ptr->coll_write_list) { - if(H5SL_insert(cache_ptr->coll_write_list, entry_ptr, &entry_ptr->addr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "unable to insert skip list item") + if ( cache_ptr->coll_write_list ) { + + if ( H5SL_insert(cache_ptr->coll_write_list, entry_ptr, + &entry_ptr->addr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, \ + "unable to insert skip list item") } /* end if */ else { #endif /* H5_HAVE_PARALLEL */ - if(entry_ptr->prefetched) { + if ( entry_ptr->prefetched ) { + HDassert(entry_ptr->type->id == H5AC_PREFETCHED_ENTRY_ID); + mem_type = cache_ptr-> class_table_ptr[entry_ptr->prefetch_type_id]-> mem_type; } /* end if */ - else + else { + mem_type = entry_ptr->type->mem_type; + } + + if ( H5F_block_write(f, mem_type, entry_ptr->addr, + entry_ptr->size, entry_ptr->image_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Can't write image to file") - if(H5F_block_write(f, mem_type, entry_ptr->addr, entry_ptr->size, entry_ptr->image_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't write image to file") #ifdef H5_HAVE_PARALLEL } #endif /* H5_HAVE_PARALLEL */ + } /* end if */ - /* if the entry has a notify callback, notify it that we have + /* if the entry has a notify callback, notify it that we have * just flushed the entry. */ - if(entry_ptr->type->notify && - (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_FLUSH, entry_ptr) < 0 ) - HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client of entry flush") + if ( ( entry_ptr->type->notify ) && + ( (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_FLUSH, + entry_ptr) < 0 ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, \ + "can't notify client of entry flush") + } /* if ( write_entry ) */ /* At this point, all pre-serialize and serialize calls have been * made if it was appropriate to make them. Similarly, the entry * has been written to disk if desired. * - * Thus it is now safe to update the cache data structures for the + * Thus it is now safe to update the cache data structures for the * flush. */ /* start by updating the statistics */ - if(clear_only) { + if ( clear_only ) { + /* only log a clear if the entry was dirty */ - if(was_dirty) { + if ( was_dirty ) { + H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) + } /* end if */ } else if(write_entry) { + HDassert(was_dirty); /* only log a flush if we actually wrote to disk */ H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) + } /* end else if */ /* Note that the algorithm below is (very) similar to the set of operations @@ -6144,12 +7022,18 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) */ /* Update the cache internal data structures. */ - if(destroy) { + if ( destroy ) { + /* Sanity checks */ - if(take_ownership) + if ( take_ownership ) { + HDassert(!destroy_entry); - else + + } else { + HDassert(destroy_entry); + } + HDassert(!entry_ptr->is_pinned); /* Update stats, while entry is still in the cache */ @@ -6159,8 +7043,12 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) * to be removed from the cache, send a 'before eviction' notice while * the entry is still fully integrated in the cache. */ - if(entry_ptr->type->notify && (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_BEFORE_EVICT, entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry to evict") + if ( ( entry_ptr->type->notify ) && + ( (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_BEFORE_EVICT, + entry_ptr) < 0 ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, \ + "can't notify client about entry to evict") /* Update the cache internal data structures as appropriate * for a destroy. Specifically: @@ -6175,52 +7063,61 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) * * 5) Remove it from the tag list for this object * - * Finally, if the destroy_entry flag is set, discard the + * Finally, if the destroy_entry flag is set, discard the * entry. */ H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr, FAIL) - if(entry_ptr->in_slist && del_from_slist_on_destroy) + if ( ( entry_ptr->in_slist ) && ( del_from_slist_on_destroy ) ) { + H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, during_flush) + } #ifdef H5_HAVE_PARALLEL /* Check for collective read access flag */ - if(entry_ptr->coll_access) { + if ( entry_ptr->coll_access ) { + entry_ptr->coll_access = FALSE; + H5C__REMOVE_FROM_COLL_LIST(cache_ptr, entry_ptr, FAIL) + } /* end if */ #endif /* H5_HAVE_PARALLEL */ H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, FAIL) /* Remove entry from tag list */ - if(H5C__untag_entry(cache_ptr, entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry from tag list") + if ( H5C__untag_entry(cache_ptr, entry_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, \ + "can't remove entry from tag list") - /* verify that the entry is no longer part of any flush dependencies */ + /* verify that the entry is no longer part of any flush dependencies */ HDassert(entry_ptr->flush_dep_nparents == 0); - HDassert(entry_ptr->flush_dep_nchildren == 0); + HDassert(entry_ptr->flush_dep_nchildren == 0); + } /* end if */ else { + HDassert(clear_only || write_entry); HDassert(entry_ptr->is_dirty); - HDassert(entry_ptr->in_slist); + HDassert((!cache_ptr->slist_enabled) || (entry_ptr->in_slist)); /* We are either doing a flush or a clear. * * A clear and a flush are the same from the point of - * view of the replacement policy and the slist. + * view of the replacement policy and the slist. * Hence no differentiation between them. * - * JRM -- 7/7/07 + * JRM -- 7/7/07 */ H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, FAIL) H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, during_flush) - /* mark the entry as clean and update the index for - * entry clean. Also, call the clear callback + /* mark the entry as clean and update the index for + * entry clean. Also, call the clear callback * if defined. */ entry_ptr->is_dirty = FALSE; @@ -6228,20 +7125,34 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) H5C__UPDATE_INDEX_FOR_ENTRY_CLEAN(cache_ptr, entry_ptr); /* Check for entry changing status and do notifications, etc. */ - if(was_dirty) { - /* If the entry's type has a 'notify' callback send a 'entry cleaned' - * notice now that the entry is fully integrated into the cache. + if ( was_dirty ) { + + /* If the entry's type has a 'notify' callback send a + * 'entry cleaned' notice now that the entry is fully + * integrated into the cache. */ - if(entry_ptr->type->notify && - (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag cleared") + if ( ( entry_ptr->type->notify ) && + ( (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, + entry_ptr) < 0 ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, \ + "can't notify client about entry dirty flag cleared") + + /* Propagate the clean flag up the flush dependency chain + * if appropriate + */ + if ( entry_ptr->flush_dep_ndirty_children != 0 ) { - /* Propagate the clean flag up the flush dependency chain if appropriate */ - if(entry_ptr->flush_dep_ndirty_children != 0) HDassert(entry_ptr->flush_dep_ndirty_children == 0); - if(entry_ptr->flush_dep_nparents > 0) - if(H5C__mark_flush_dep_clean(entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "Can't propagate flush dep clean flag") + } + + if ( entry_ptr->flush_dep_nparents > 0 ) { + + if ( H5C__mark_flush_dep_clean(entry_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, \ + "Can't propagate flush dep clean flag") + } } /* end if */ } /* end else */ @@ -6249,45 +7160,54 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) entry_ptr->flush_in_progress = FALSE; /* capture the cache entry address for the log_flush call at the - end before the entry_ptr gets freed */ + * end before the entry_ptr gets freed + */ entry_addr = entry_ptr->addr; - /* Internal cache data structures should now be up to date, and - * consistent with the status of the entry. + /* Internal cache data structures should now be up to date, and + * consistent with the status of the entry. * * Now discard the entry if appropriate. */ - if(destroy) { + if ( destroy ) { + /* Sanity check */ HDassert(0 == entry_ptr->flush_dep_nparents); /* if both suppress_image_entry_frees and entry_ptr->include_in_image - * are true, simply set entry_ptr->image_ptr to NULL, as we have + * are true, simply set entry_ptr->image_ptr to NULL, as we have * another pointer to the buffer in an instance of H5C_image_entry_t * in cache_ptr->image_entries. * * Otherwise, free the buffer if it exists. */ - if(suppress_image_entry_frees && entry_ptr->include_in_image) + if ( suppress_image_entry_frees && entry_ptr->include_in_image ) { + entry_ptr->image_ptr = NULL; - else if(entry_ptr->image_ptr != NULL) + + } else if ( entry_ptr->image_ptr != NULL ) { + entry_ptr->image_ptr = H5MM_xfree(entry_ptr->image_ptr); + } - /* If the entry is not a prefetched entry, verify that the flush + /* If the entry is not a prefetched entry, verify that the flush * dependency parents addresses array has been transferred. * * If the entry is prefetched, the free_isr routine will dispose of * the flush dependency parents addresses array if necessary. */ - if(!entry_ptr->prefetched) { + if ( ! entry_ptr->prefetched ) { + HDassert(0 == entry_ptr->fd_parent_count); HDassert(NULL == entry_ptr->fd_parent_addrs); + } /* end if */ - /* Check whether we should free the space in the file that - * the entry occupies + /* Check whether we should free the space in the file that + * the entry occupies */ - if(free_file_space) { + if ( free_file_space ) { + hsize_t fsf_size; /* Sanity checks */ @@ -6307,29 +7227,40 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) * it to get the size of the block of file space to free. * Otherwise use entry_ptr->size. */ - if(entry_ptr->type->fsf_size) { - if((entry_ptr->type->fsf_size)((void *)entry_ptr, &fsf_size) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "unable to get file space free size") + if ( entry_ptr->type->fsf_size ) { + + if ( (entry_ptr->type->fsf_size)((void *)entry_ptr, &fsf_size) + < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, \ + "unable to get file space free size") + } /* end if */ - else /* no file space free size callback -- use entry size */ + else { /* no file space free size callback -- use entry size */ + fsf_size = entry_ptr->size; + } /* Release the space on disk */ - if(H5MF_xfree(f, entry_ptr->type->mem_type, entry_ptr->addr, fsf_size) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "unable to free file space for cache entry") + if ( H5MF_xfree(f, entry_ptr->type->mem_type, + entry_ptr->addr, fsf_size) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, \ + "unable to free file space for cache entry") + } /* end if ( free_file_space ) */ /* Reset the pointer to the cache the entry is within. -QAK */ entry_ptr->cache_ptr = NULL; - /* increment entries_removed_counter and set - * last_entry_removed_ptr. As we are likely abuut to - * free the entry, recall that last_entry_removed_ptr + /* increment entries_removed_counter and set + * last_entry_removed_ptr. As we are likely abuut to + * free the entry, recall that last_entry_removed_ptr * must NEVER be dereferenced. * * Recall that these fields are maintained to allow functions - * that perform scans of lists of entries to detect the - * unexpected removal of entries (via expunge, eviction, + * that perform scans of lists of entries to detect the + * unexpected removal of entries (via expunge, eviction, * or take ownership at present), so that they can re-start * their scans if necessary. * @@ -6339,22 +7270,32 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) */ cache_ptr->entries_removed_counter++; cache_ptr->last_entry_removed_ptr = entry_ptr; - if(entry_ptr == cache_ptr->entry_watched_for_removal) + + if ( entry_ptr == cache_ptr->entry_watched_for_removal ) { + cache_ptr->entry_watched_for_removal = NULL; + } /* Check for actually destroying the entry in memory */ /* (As opposed to taking ownership of it) */ - if(destroy_entry) { - if(entry_ptr->is_dirty) { + if ( destroy_entry ) { + + if ( entry_ptr->is_dirty ) { + /* Reset dirty flag */ entry_ptr->is_dirty = FALSE; - /* If the entry's type has a 'notify' callback send a 'entry cleaned' - * notice now that the entry is fully integrated into the cache. + /* If the entry's type has a 'notify' callback send a + * 'entry cleaned' notice now that the entry is fully + * integrated into the cache. */ - if(entry_ptr->type->notify && - (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag cleared") + if ( ( entry_ptr->type->notify ) && + ( (entry_ptr->type->notify) + (H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0 ) ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, \ + "can't notify client about entry dirty flag cleared") + } /* end if */ /* we are about to discard the in core representation -- @@ -6366,44 +7307,65 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) /* verify that the image has been freed */ HDassert(entry_ptr->image_ptr == NULL); - if(entry_ptr->type->free_icr((void *)entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "free_icr callback failed") + if ( entry_ptr->type->free_icr((void *)entry_ptr) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "free_icr callback failed") + } /* end if */ else { + HDassert(take_ownership); /* client is taking ownership of the entry. - * set bad magic here too so the cache will choke + * set bad magic here too so the cache will choke * unless the entry is re-inserted properly */ entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC; + } /* end else */ } /* if (destroy) */ - /* Check if we have to update the page buffer with cleared entries - * so it doesn't go out of date + /* Check if we have to update the page buffer with cleared entries + * so it doesn't go out of date */ - if(update_page_buffer) { + if ( update_page_buffer ) { + /* Sanity check */ HDassert(!destroy); HDassert(entry_ptr->image_ptr); - if(f->shared->page_buf && f->shared->page_buf->page_size >= entry_ptr->size) - if(H5PB_update_entry(f->shared->page_buf, entry_ptr->addr, entry_ptr->size, entry_ptr->image_ptr) > 0) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Failed to update PB with metadata cache") + if ( ( f->shared->page_buf ) && + ( f->shared->page_buf->page_size >= entry_ptr->size ) ) { + + if ( H5PB_update_entry(f->shared->page_buf, entry_ptr->addr, + entry_ptr->size, entry_ptr->image_ptr) > 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Failed to update PB with metadata cache") + } /* end if */ } /* end if */ - if(cache_ptr->log_flush) - if((cache_ptr->log_flush)(cache_ptr, entry_addr, was_dirty, flags) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "log_flush callback failed") + if ( cache_ptr->log_flush ) { + + if ( (cache_ptr->log_flush)(cache_ptr, entry_addr, + was_dirty, flags) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "log_flush callback failed") + + } /* end if */ done: - HDassert( ( ret_value != SUCCEED ) || ( destroy_entry ) || + + HDassert( ( ret_value != SUCCEED ) || ( destroy_entry ) || ( ! entry_ptr->flush_in_progress ) ); - HDassert( ( ret_value != SUCCEED ) || ( destroy_entry ) || + + HDassert( ( ret_value != SUCCEED ) || ( destroy_entry ) || ( take_ownership ) || ( ! entry_ptr->is_dirty ) ); FUNC_LEAVE_NOAPI(ret_value) + } /* H5C__flush_single_entry() */ @@ -6417,7 +7379,7 @@ done: * If exceed, adjust 'len' accordingly. * * Verify that 'len' should not exceed eoa when 'actual' is - * true i.e. 'len' is the actual length from get_load_size + * true i.e. 'len' is the actual length from get_load_size * callback with non-null image pointer. * If exceed, return error. * @@ -6438,7 +7400,7 @@ H5C__verify_len_eoa(H5F_t *f, const H5C_class_t *type, haddr_t addr, FUNC_ENTER_STATIC - /* if type == H5FD_MEM_GHEAP, H5F_block_read() forces + /* if type == H5FD_MEM_GHEAP, H5F_block_read() forces * type to H5FD_MEM_DRAW via its call to H5F__accum_read(). * Thus we do the same for purposes of computing the EOA * for sanity checks. @@ -6545,7 +7507,7 @@ H5C_load_entry(H5F_t * f, if(NULL == (image = (uint8_t *)H5MM_malloc(len + H5C_IMAGE_EXTRA_SPACE))) HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed for on disk image buffer") #if H5C_DO_MEMORY_SANITY_CHECKS - HDmemcpy(image + len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); + H5MM_memcpy(image + len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ #ifdef H5_HAVE_PARALLEL @@ -6570,7 +7532,7 @@ H5C_load_entry(H5F_t * f, /* Get the # of read attempts */ max_tries = tries = H5F_GET_READ_ATTEMPTS(f); - /* + /* * This do/while loop performs the following till the metadata checksum * is correct or the file's number of allowed read attempts are reached. * --read the metadata @@ -6583,7 +7545,7 @@ H5C_load_entry(H5F_t * f, HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "image null after H5MM_realloc()") image = (uint8_t *)new_image; #if H5C_DO_MEMORY_SANITY_CHECKS - HDmemcpy(image + len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); + H5MM_memcpy(image + len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ } /* end if */ @@ -6627,7 +7589,7 @@ H5C_load_entry(H5F_t * f, HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "image null after H5MM_realloc()") image = (uint8_t *)new_image; #if H5C_DO_MEMORY_SANITY_CHECKS - HDmemcpy(image + actual_len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); + H5MM_memcpy(image + actual_len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ if(actual_len > len) { @@ -6870,8 +7832,8 @@ H5C__make_space_in_cache(H5F_t *f, size_t space_needed, hbool_t write_permitted) HDassert(cache_ptr->index_size == (cache_ptr->clean_index_size + cache_ptr->dirty_index_size)); /* check to see if cache_ptr->msic_in_progress is TRUE. If it, this - * is a re-entrant call via a client callback called in the make - * space in cache process. To avoid an infinite recursion, set + * is a re-entrant call via a client callback called in the make + * space in cache process. To avoid an infinite recursion, set * reentrant_call to TRUE, and goto done. */ if(cache_ptr->msic_in_progress) { @@ -6943,9 +7905,9 @@ H5C__make_space_in_cache(H5F_t *f, size_t space_needed, hbool_t write_permitted) } #endif /* H5C_COLLECT_CACHE_STATS */ - /* reset entries_removed_counter and - * last_entry_removed_ptr prior to the call to - * H5C__flush_single_entry() so that we can spot + /* reset entries_removed_counter and + * last_entry_removed_ptr prior to the call to + * H5C__flush_single_entry() so that we can spot * unexpected removals of entries from the cache, * and set the restart_scan flag if proceeding * would be likely to cause us to scan an entry @@ -6962,7 +7924,7 @@ H5C__make_space_in_cache(H5F_t *f, size_t space_needed, hbool_t write_permitted) restart_scan = TRUE; - } else if ( (cache_ptr->index_size + space_needed) > cache_ptr->max_cache_size + } else if ( (cache_ptr->index_size + space_needed) > cache_ptr->max_cache_size #ifdef H5_HAVE_PARALLEL && !(entry_ptr->coll_access) #endif /* H5_HAVE_PARALLEL */ @@ -7120,7 +8082,7 @@ H5C__make_space_in_cache(H5F_t *f, size_t space_needed, hbool_t write_permitted) prev_ptr = entry_ptr->aux_prev; - if ( ( !(entry_ptr->prefetched_dirty) ) + if ( ( !(entry_ptr->prefetched_dirty) ) #ifdef H5_HAVE_PARALLEL && ( ! (entry_ptr->coll_access) ) #endif /* H5_HAVE_PARALLEL */ @@ -7170,7 +8132,7 @@ done: * * Changes: * - * Added code to verify that the LRU contains no pinned + * Added code to verify that the LRU contains no pinned * entries. JRM -- 4/25/14 * *------------------------------------------------------------------------- @@ -7250,7 +8212,7 @@ H5C_validate_lru_list(H5C_t * cache_ptr) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed") } - if ( ( entry_ptr->is_pinned ) || + if ( ( entry_ptr->is_pinned ) || ( entry_ptr->pinned_from_client ) || ( entry_ptr->pinned_from_cache ) ) { @@ -7286,7 +8248,7 @@ done: * * Function: H5C_validate_pinned_entry_list * - * Purpose: Debugging function that scans the pinned entry list for + * Purpose: Debugging function that scans the pinned entry list for * errors. * * If an error is detected, the function generates a @@ -7418,7 +8380,7 @@ done: * * Function: H5C_validate_protected_entry_list * - * Purpose: Debugging function that scans the protected entry list for + * Purpose: Debugging function that scans the protected entry list for * errors. * * If an error is detected, the function generates a @@ -7543,11 +8505,11 @@ done: * * Function: H5C_entry_in_skip_list * - * Purpose: Debugging function that scans skip list to see if it - * is in present. We need this, as it is possible for + * Purpose: Debugging function that scans skip list to see if it + * is in present. We need this, as it is possible for * an entry to be in the skip list twice. * - * Return: FALSE if the entry is not in the skip list, and TRUE + * Return: FALSE if the entry is not in the skip list, and TRUE * if it is. * * Programmer: John Mainzer, 11/1/14 @@ -7609,11 +8571,21 @@ H5C_entry_in_skip_list(H5C_t * cache_ptr, H5C_cache_entry_t *target_ptr) * Programmer: Mike McGreevy * November 3, 2010 * + * Changes: Modified function to setup the slist before calling + * H%C_flush_cache(), and take it down afterwards. Note + * that the slist need not be empty after the call to + * H5C_flush_cache() since we are only flushing marked + * entries. Thus must set the clear_slist parameter + * of H5C_set_slist_enabled to TRUE. + * + * JRM -- 5/6/20 + * *------------------------------------------------------------------------- */ + herr_t H5C__flush_marked_entries(H5F_t * f) -{ +{ herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE @@ -7621,12 +8593,31 @@ H5C__flush_marked_entries(H5F_t * f) /* Assertions */ HDassert(f != NULL); + + /* Enable the slist, as it is needed in the flush */ + if ( H5C_set_slist_enabled(f->shared->cache, TRUE, FALSE) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "set slist enabled failed") + + /* Flush all marked entries */ - if(H5C_flush_cache(f, H5C__FLUSH_MARKED_ENTRIES_FLAG | H5C__FLUSH_IGNORE_PROTECTED_FLAG) < 0) + if ( H5C_flush_cache(f, H5C__FLUSH_MARKED_ENTRIES_FLAG | + H5C__FLUSH_IGNORE_PROTECTED_FLAG) < 0 ) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush cache") + /* Disable the slist. Set the clear_slist parameter to TRUE + * since we called H5C_flush_cache() with the + * H5C__FLUSH_MARKED_ENTRIES_FLAG. + */ + if ( H5C_set_slist_enabled(f->shared->cache, FALSE, TRUE) < 0 ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "disable slist failed") + done: + FUNC_LEAVE_NOAPI(ret_value) + } /* H5C__flush_marked_entries */ @@ -7635,7 +8626,7 @@ done: * Function: H5C_cork * * Purpose: To cork/uncork/get cork status of an object depending on "action": - * H5C__SET_CORK: + * H5C__SET_CORK: * To cork the object * Return error if the object is already corked * H5C__UNCORK: @@ -7644,7 +8635,7 @@ done: * H5C__GET_CORKED: * To retrieve the cork status of an object in * the parameter "corked" - * + * * Return: Success: Non-negative * Failure: Negative * @@ -7654,7 +8645,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5C_cork(H5C_t *cache_ptr, haddr_t obj_addr, unsigned action, hbool_t *corked) +H5C_cork(H5C_t *cache_ptr, haddr_t obj_addr, unsigned action, hbool_t *corked) { H5C_tag_info_t *tag_info; /* Points to a tag info struct */ herr_t ret_value = SUCCEED; @@ -7836,8 +8827,8 @@ done: /*------------------------------------------------------------------------- * Function: H5C__mark_flush_dep_serialized() * - * Purpose: Decrement the flush_dep_nunser_children fields of all the - * target entry's flush dependency parents in response to + * Purpose: Decrement the flush_dep_nunser_children fields of all the + * target entry's flush dependency parents in response to * the target entry becoming serialized. * * Return: Non-negative on success/Negative on failure @@ -7886,7 +8877,7 @@ done: * Function: H5C__mark_flush_dep_unserialized() * * Purpose: Increment the flush_dep_nunser_children fields of all the - * target entry's flush dependency parents in response to + * target entry's flush dependency parents in response to * the target entry becoming unserialized. * * Return: Non-negative on success/Negative on failure @@ -7912,7 +8903,7 @@ H5C__mark_flush_dep_unserialized(H5C_cache_entry_t * entry_ptr) /* Sanity check */ HDassert(entry_ptr->flush_dep_parent); HDassert(entry_ptr->flush_dep_parent[u]->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); - HDassert(entry_ptr->flush_dep_parent[u]->flush_dep_nunser_children < + HDassert(entry_ptr->flush_dep_parent[u]->flush_dep_nunser_children < entry_ptr->flush_dep_parent[u]->flush_dep_nchildren); /* increment parents number of usserialized children */ @@ -7972,11 +8963,11 @@ H5C__assert_flush_dep_nocycle(const H5C_cache_entry_t * entry, /*------------------------------------------------------------------------- * Function: H5C__serialize_cache * - * Purpose: Serialize (i.e. construct an on disk image) for all entries - * in the metadata cache including clean entries. + * 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. + * must be observed in the serialization process. * * Note also that entries may be loaded, flushed, evicted, * expunged, relocated, resized, or removed from the cache @@ -7984,17 +8975,17 @@ H5C__assert_flush_dep_nocycle(const H5C_cache_entry_t * entry, * 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). + * 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 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 + * 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 + * However, I gather that other uses for the routine are * under consideration. * * Return: Non-negative on success/Negative on failure or if there was @@ -8065,10 +9056,10 @@ H5C__serialize_cache(H5F_t *f) #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ #ifndef NDEBUG - /* if this is a debug build, set the serialization_count field of + /* 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 + * 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). */ @@ -8084,10 +9075,10 @@ H5C__serialize_cache(H5F_t *f) } /* end block */ #endif /* NDEBUG */ - /* set cache_ptr->serialization_in_progress to TRUE, and back + /* 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 + * 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); @@ -8165,16 +9156,16 @@ done: * * 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 + * 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 + * 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 @@ -8209,76 +9200,76 @@ H5C__serialize_ring(H5F_t *f, H5C_ring_t ring) /* 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 + * 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 + * 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, + * 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 + * 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 + * 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 + * 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. - * + * 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 invariant 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 + * 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. + * possible. * * Do this by maintaining a count of the number of times each entry is - * serialized during a cache serialization. If any flush dependency + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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. + * 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 + * 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) { @@ -8296,7 +9287,7 @@ H5C__serialize_ring(H5F_t *f, H5C_ring_t ring) 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 + * that it is assigned to either the target or an inner * ring. */ HDassert((entry_ptr->ring >= ring) || (entry_ptr->image_up_to_date)); @@ -8363,9 +9354,9 @@ H5C__serialize_ring(H5F_t *f, H5C_ring_t ring) cache_ptr->entries_relocated_counter = 0; /* 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 + * 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; @@ -8418,7 +9409,7 @@ done: /*------------------------------------------------------------------------- * Function: H5C__serialize_single_entry * - * Purpose: Serialize the cache entry pointed to by the entry_ptr + * Purpose: Serialize the cache entry pointed to by the entry_ptr * parameter. * * Return: Non-negative on success/Negative on failure @@ -8459,7 +9450,7 @@ H5C__serialize_single_entry(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry 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); + H5MM_memcpy(((uint8_t *)entry_ptr->image_ptr) + image_size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ } /* end if */ @@ -8482,13 +9473,13 @@ done: * * Purpose: Serialize an entry and generate its image. * - * Note: This may cause the entry to be re-sized and/or moved in - * the cache. + * Note: This may cause the entry to be re-sized and/or moved in + * the cache. * - * As we will not update the metadata cache's data structures - * until we we finish the write, we must touch up these - * data structures for size and location changes even if we - * are about to delete the entry from the cache (i.e. on a + * As we will not update the metadata cache's data structures + * until we we finish the write, we must touch up these + * data structures for size and location changes even if we + * are about to delete the entry from the cache (i.e. on a * flush destroy). * * Return: Non-negative on success/Negative on failure @@ -8496,14 +9487,18 @@ done: * Programmer: Mohamad Chaarawi * 2/10/16 * + * Changes: Updated sanity checks for the possibility that the skip + * list is disabled. + * JRM 5/16/20 + * *------------------------------------------------------------------------- */ herr_t H5C__generate_image(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr) { - haddr_t new_addr = HADDR_UNDEF; - haddr_t old_addr = HADDR_UNDEF; - size_t new_len = 0; + haddr_t new_addr = HADDR_UNDEF; + haddr_t old_addr = HADDR_UNDEF; + size_t new_len = 0; unsigned serialize_flags = H5C__SERIALIZE_NO_FLAGS_SET; herr_t ret_value = SUCCEED; @@ -8524,16 +9519,24 @@ H5C__generate_image(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr) old_addr = entry_ptr->addr; /* Call client's pre-serialize callback, if there's one */ - if(entry_ptr->type->pre_serialize && - (entry_ptr->type->pre_serialize)(f, (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") + if ( ( entry_ptr->type->pre_serialize ) && + ( (entry_ptr->type->pre_serialize)(f, (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) { + 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)") + 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 @@ -8562,28 +9565,40 @@ H5C__generate_image(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr) * 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 occurred in parallel case") + if ( cache_ptr->aux_ptr != NULL ) + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "resize/move in serialize occurred in parallel case") #endif /* If required, resize the buffer and update the entry and the cache - * data structures */ - if(serialize_flags & H5C__SERIALIZE_RESIZED_FLAG) { + * data structures + */ + 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 ( 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); + H5MM_memcpy(((uint8_t *)entry_ptr->image_ptr) + new_len, + H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ /* Update statistics for resizing the entry */ - H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_len); + 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)); + 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 * flushing it. Thus we must update the replacement policy data @@ -8592,27 +9607,34 @@ H5C__generate_image(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr) */ H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_len); - /* As we haven't updated the cache data structures for + /* As we haven't updated the cache data structures for * for the flush or flush destroy yet, the entry should - * be in the slist. Thus update it for the size change. + * be in the slist if the slist is enabled. Since + * H5C__UPDATE_SLIST_FOR_SIZE_CHANGE() is a no-op if the + * slist is enabled, call it un-conditionally. */ HDassert(entry_ptr->is_dirty); - HDassert(entry_ptr->in_slist); - H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, new_len); + HDassert((entry_ptr->in_slist) || (!cache_ptr->slist_enabled)); + + 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, udate the entry and the cache data structures - * for a move + /* If required, udate the entry and the cache data structures + * for a move */ - if(serialize_flags & H5C__SERIALIZE_MOVED_FLAG) { + if ( serialize_flags & H5C__SERIALIZE_MOVED_FLAG ) { + /* Update stats and 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) { + 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); @@ -8623,30 +9645,43 @@ H5C__generate_image(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr) /* And then reinsert in the index and slist */ 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 */ + 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) */ /* Serialize object into buffer */ - if(entry_ptr->type->serialize(f, entry_ptr->image_ptr, entry_ptr->size, (void *)entry_ptr) < 0) + 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) + entry_ptr->size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE)); + HDassert(0 == HDmemcmp(((uint8_t *)entry_ptr->image_ptr) + entry_ptr->size,\ + 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 + /* 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 serialization status to fd parents") + + 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 serialization status to fd parents") + } done: FUNC_LEAVE_NOAPI(ret_value) @@ -8762,8 +9797,8 @@ H5C_remove_entry(void *_entry) if(entry == cache->entry_watched_for_removal) cache->entry_watched_for_removal = NULL; - /* Internal cache data structures should now be up to date, and - * consistent with the status of the entry. + /* Internal cache data structures should now be up to date, and + * consistent with the status of the entry. * * Now clean up internal cache fields if appropriate. */ |