diff options
author | John Mainzer <mainzer@hdfgroup.org> | 2008-02-18 05:28:04 (GMT) |
---|---|---|
committer | John Mainzer <mainzer@hdfgroup.org> | 2008-02-18 05:28:04 (GMT) |
commit | cd571e4a45e5af71ae608388141e6b28a16f8171 (patch) | |
tree | 27a6b76035cd03c2b13946730225b34f0f03d98d /src/H5C2.c | |
parent | d3e926b897b42d27e1c5f8533a8a413c448738e2 (diff) | |
download | hdf5-cd571e4a45e5af71ae608388141e6b28a16f8171.zip hdf5-cd571e4a45e5af71ae608388141e6b28a16f8171.tar.gz hdf5-cd571e4a45e5af71ae608388141e6b28a16f8171.tar.bz2 |
[svn-r14594] Ported flash cache size increase code into the journaling branch --
note that both the H5C and H5C2 code have been updated.
Also checked in code to track journaling status in the super block.
Note that this code has not been tested -- but as best I can tell,
it does not break the existing regression tests.
Tested serial (debug and production) on Phoenix. Also tested parallel
on kagiso.
Note that regression test fails on kagiso (but not on phoenix) if
the cache2 serial tests are configured to use the core file driver.
Thus this code is check in with the core file driver optimization
of the cache2 tests disabled. To turn it on, set the USE_CORE_DRIVER
#define to TRUE.
Diffstat (limited to 'src/H5C2.c')
-rw-r--r-- | src/H5C2.c | 599 |
1 files changed, 554 insertions, 45 deletions
@@ -2588,6 +2588,10 @@ static herr_t H5C2__autoadjust__ageout__remove_all_markers(H5C2_t * cache_ptr); static herr_t H5C2__autoadjust__ageout__remove_excess_markers(H5C2_t * cache_ptr); +static herr_t H5C2__flash_increase_cache_size(H5C2_t * cache_ptr, + size_t old_entry_size, + size_t new_entry_size); + static herr_t H5C2_flush_single_entry(H5F_t * f, hid_t dxpl_id, H5C2_t * cache_ptr, @@ -2850,6 +2854,11 @@ done: * Added initialization for the new is_read_only and * ro_ref_count fields. * + * JRM -- 12/31/07 + * Added initialization for the new flash cache size increase + * related fields of H5C2_t. + * + * *------------------------------------------------------------------------- */ @@ -2969,6 +2978,8 @@ H5C2_create(const H5F_t * f, cache_ptr->dLRU_tail_ptr = NULL; cache_ptr->size_increase_possible = FALSE; + cache_ptr->flash_size_increase_possible = FALSE; + cache_ptr->flash_size_increase_threshold = 0; cache_ptr->size_decrease_possible = FALSE; cache_ptr->resize_enabled = FALSE; cache_ptr->cache_full = FALSE; @@ -2989,6 +3000,10 @@ H5C2_create(const H5F_t * f, (cache_ptr->resize_ctl).apply_max_increment = TRUE; (cache_ptr->resize_ctl).max_increment = H5C2__DEF_AR_MAX_INCREMENT; + (cache_ptr->resize_ctl).flash_incr_mode = H5C2_flash_incr__off; + (cache_ptr->resize_ctl).flash_multiple = 1.0; + (cache_ptr->resize_ctl).flash_threshold = 0.25; + (cache_ptr->resize_ctl).decr_mode = H5C2_decr__off; (cache_ptr->resize_ctl).upper_hr_threshold = H5C2__DEF_AR_UPPER_THRESHHOLD; (cache_ptr->resize_ctl).decrement = H5C2__DEF_AR_DECREMENT; @@ -3008,9 +3023,10 @@ H5C2_create(const H5F_t * f, for ( i = 0; i < H5C2__MAX_EPOCH_MARKERS; i++ ) { (cache_ptr->epoch_marker_active)[i] = FALSE; - +#ifndef NDEBUG ((cache_ptr->epoch_markers)[i]).magic = H5C2__H5C2_CACHE_ENTRY_T_MAGIC; +#endif /* NDEBUG */ ((cache_ptr->epoch_markers)[i]).addr = (haddr_t)i; ((cache_ptr->epoch_markers)[i]).size = (size_t)0; ((cache_ptr->epoch_markers)[i]).type = &epoch_marker_class_2; @@ -3096,6 +3112,9 @@ done: * Updated function for display the new prefix field of * H5C2_t in output. * + * JRM 12/31/07 + * Updated function to handle flash size increases. + * *------------------------------------------------------------------------- */ void @@ -3142,6 +3161,25 @@ H5C2_def_auto_resize_rpt_fcn(H5C2_t * cache_ptr, new_min_clean_size); break; + case flash_increase2: + HDassert( old_max_cache_size < new_max_cache_size ); + + HDfprintf(stdout, + "%sflash cache resize(%d) -- size threshold = %Zu.\n", + cache_ptr->prefix, + (int)((cache_ptr->resize_ctl).flash_incr_mode), + cache_ptr->flash_size_increase_threshold); + + HDfprintf(stdout, + "%s cache size increased from (%Zu/%Zu) to (%Zu/%Zu).\n", + cache_ptr->prefix, + old_max_cache_size, + old_min_clean_size, + new_max_cache_size, + new_min_clean_size); + break; + + case decrease2: HDassert( old_max_cache_size > new_max_cache_size ); @@ -3571,6 +3609,21 @@ done: * handle the situation, but one can argue that I should * just scream and die if I ever detect the condidtion. * + * JRM -- 10/13/07 + * 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 I should just scream and die if I + * ever detect the condidtion. + * *------------------------------------------------------------------------- */ herr_t @@ -3651,19 +3704,27 @@ H5C2_flush_cache(H5C2_t * cache_ptr, { flushed_entries_last_pass = FALSE; node_ptr = H5SL_first(cache_ptr->slist_ptr); + if ( node_ptr != NULL ) { + next_entry_ptr = (H5C2_cache_entry_t *)H5SL_item(node_ptr); if ( next_entry_ptr == NULL ) { + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "next_entry_ptr == NULL 1 ?!?!"); } +#ifndef NDEBUG HDassert( next_entry_ptr->magic == H5C2__H5C2_CACHE_ENTRY_T_MAGIC ); +#endif /* NDEBUG */ HDassert( next_entry_ptr->is_dirty ); HDassert( next_entry_ptr->in_slist ); + } else { + next_entry_ptr = NULL; + } HDassert( node_ptr != NULL ); @@ -3742,14 +3803,16 @@ H5C2_flush_cache(H5C2_t * cache_ptr, * If the entry has been evicted, we flag an error and * exit. */ - +#ifndef NDEBUG if ( entry_ptr->magic != H5C2__H5C2_CACHE_ENTRY_T_MAGIC ) { HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "entry_ptr->magic invalid ?!?!"); - } else if ( ( ! entry_ptr->is_dirty ) || - ( ! entry_ptr->in_slist ) ) { + } else +#endif /* NDEBUG */ + if ( ( ! entry_ptr->is_dirty ) || + ( ! entry_ptr->in_slist ) ) { /* the s-list has been modified out from under us. * set node_ptr to NULL and break out of the loop. @@ -3762,15 +3825,20 @@ H5C2_flush_cache(H5C2_t * cache_ptr, * from the slist. */ node_ptr = H5SL_next(node_ptr); + if ( node_ptr != NULL ) { + next_entry_ptr = (H5C2_cache_entry_t *)H5SL_item(node_ptr); if ( next_entry_ptr == NULL ) { + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "next_entry_ptr == NULL 2 ?!?!"); } +#ifndef NDEBUG HDassert( next_entry_ptr->magic == H5C2__H5C2_CACHE_ENTRY_T_MAGIC ); +#endif /* NDEBUG */ HDassert( next_entry_ptr->is_dirty ); HDassert( next_entry_ptr->in_slist ); } else { @@ -3823,6 +3891,7 @@ H5C2_flush_cache(H5C2_t * cache_ptr, HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ "dirty pinned entry flush failed.") } + flushed_entries_last_pass = TRUE; } } else { #if H5C2_DO_SANITY_CHECKS @@ -4580,6 +4649,9 @@ done: * JRM -- 10/12/07 * Added initialization for the new magic field. * + * JRM -- 12/31/07 + * Added code supporting flash cache size increases. + * *------------------------------------------------------------------------- */ @@ -4592,6 +4664,7 @@ H5C2_insert_entry(H5C2_t * cache_ptr, void * thing, unsigned int flags) { + /* const char * fcn_name = "H5C2_insert_entry()"; */ herr_t result; herr_t ret_value = SUCCEED; /* Return value */ hbool_t insert_pinned; @@ -4628,9 +4701,9 @@ H5C2_insert_entry(H5C2_t * cache_ptr, insert_pinned = ( (flags & H5C2__PIN_ENTRY_FLAG) != 0 ); entry_ptr = (H5C2_cache_entry_t *)thing; - +#ifndef NDEBUG entry_ptr->magic = H5C2__H5C2_CACHE_ENTRY_T_MAGIC; - +#endif /* NDEBUG */ entry_ptr->addr = addr; entry_ptr->type = type; @@ -4664,6 +4737,19 @@ H5C2_insert_entry(H5C2_t * cache_ptr, H5C2__RESET_CACHE_ENTRY_STATS(entry_ptr) + if ( ( cache_ptr->flash_size_increase_possible ) && + ( entry_ptr->size > cache_ptr->flash_size_increase_threshold ) ) { + + result = H5C2__flash_increase_cache_size(cache_ptr, 0, + entry_ptr->size); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, \ + "H5C2__flash_increase_cache_size failed.") + } + } + if ( ( cache_ptr->evictions_enabled ) && ( (cache_ptr->index_size + entry_ptr->size) > cache_ptr->max_cache_size ) ) { @@ -5151,10 +5237,13 @@ done: * * Modifications: * - * None + * Added code to do a flash cache size increase if + * appropriate. + * JRM -- 1/11/08 * *------------------------------------------------------------------------- */ + herr_t H5C2_mark_pinned_entry_dirty(H5C2_t * cache_ptr, void * thing, @@ -5162,6 +5251,8 @@ H5C2_mark_pinned_entry_dirty(H5C2_t * cache_ptr, size_t new_size) { herr_t ret_value = SUCCEED; /* Return value */ + herr_t result; + size_t size_increase; H5C2_cache_entry_t * entry_ptr; FUNC_ENTER_NOAPI(H5C2_mark_pinned_entry_dirty, FAIL) @@ -5191,10 +5282,33 @@ H5C2_mark_pinned_entry_dirty(H5C2_t * cache_ptr, /* update for change in entry size if necessary */ if ( ( size_changed ) && ( entry_ptr->size != new_size ) ) { + /* do a flash cache size increase if appropriate */ + if ( cache_ptr->flash_size_increase_possible ) { + + if ( new_size > entry_ptr->size ) { + + size_increase = new_size - entry_ptr->size; + + if ( size_increase >= + cache_ptr->flash_size_increase_threshold ) { + + result = H5C2__flash_increase_cache_size(cache_ptr, + entry_ptr->size, + new_size); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "H5C2__flash_increase_cache_size failed.") + } + } + } + } + /* update the protected entry list */ H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr->pel_len), \ - (cache_ptr->pel_size), \ - (entry_ptr->size), (new_size)); + (cache_ptr->pel_size), \ + (entry_ptr->size), (new_size)); /* update the hash table */ H5C2__UPDATE_INDEX_FOR_SIZE_CHANGE((cache_ptr), (entry_ptr->size),\ @@ -5528,7 +5642,9 @@ done: * * Modifications: * - * None + * Added code to apply a flash cache size increment if + * appropriate. + * JRM -- 1/11/08 * *------------------------------------------------------------------------- */ @@ -5537,8 +5653,11 @@ H5C2_resize_pinned_entry(H5C2_t * cache_ptr, void * thing, size_t new_size) { + /* const char * fcn_name = "H5C2_resize_pinned_entry()"; */ herr_t ret_value = SUCCEED; /* Return value */ + herr_t result; H5C2_cache_entry_t * entry_ptr; + size_t size_increase; FUNC_ENTER_NOAPI(H5C2_resize_pinned_entry, FAIL) @@ -5574,6 +5693,29 @@ H5C2_resize_pinned_entry(H5C2_t * cache_ptr, /* update for change in entry size if necessary */ if ( entry_ptr->size != new_size ) { + /* do a flash cache size increase if appropriate */ + if ( cache_ptr->flash_size_increase_possible ) { + + if ( new_size > entry_ptr->size ) { + + size_increase = new_size - entry_ptr->size; + + if ( size_increase >= + cache_ptr->flash_size_increase_threshold ) { + + result = H5C2__flash_increase_cache_size(cache_ptr, + entry_ptr->size, + new_size); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "H5C2__flash_increase_cache_size failed.") + } + } + } + } + /* update the protected entry list */ H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr->pel_len), \ (cache_ptr->pel_size), \ @@ -5761,7 +5903,7 @@ done: * of cache entries. * * JRM -- 7/27/07 - * Added code supporting the new evictions_enabled fieled + * Added code supporting the new evictions_enabled field * in H5C2_t. * * JRM -- 7/11/07 @@ -5771,6 +5913,10 @@ done: * fields. Gained the len parameter. Also internal * changes supporting the revised API. * + * JRM -- 1/3/08 + * Added to do a flash cache size increase if appropriate + * when a large entry is loaded. + * *------------------------------------------------------------------------- */ @@ -5848,6 +5994,22 @@ H5C2_protect(H5C2_t * cache_ptr, entry_ptr = (H5C2_cache_entry_t *)thing; + /* If the entry is very large, and we are configured to allow it, + * we may wish to perform a flash cache size increase. + */ + if ( ( cache_ptr->flash_size_increase_possible ) && + ( entry_ptr->size > cache_ptr->flash_size_increase_threshold ) ) { + + result = H5C2__flash_increase_cache_size(cache_ptr, 0, + entry_ptr->size); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, \ + "H5C2__flash_increase_cache_size failed.") + } + } + /* try to free up some space if necessary and if * evictions are permitted */ @@ -6149,6 +6311,10 @@ done: * if the new configuration forces an immediate reduction * in cache size. * + * JRM -- 12/31/07 + * Added code supporting the new flash cache size increase + * code. + * *------------------------------------------------------------------------- */ @@ -6156,6 +6322,7 @@ herr_t H5C2_set_cache_auto_resize_config(H5C2_t * cache_ptr, H5C2_auto_size_ctl_t *config_ptr) { + /* const char *fcn_name = "H5C2_set_cache_auto_resize_config()"; */ herr_t ret_value = SUCCEED; /* Return value */ herr_t result; size_t new_max_cache_size; @@ -6210,8 +6377,10 @@ H5C2_set_cache_auto_resize_config(H5C2_t * cache_ptr, "conflicting threshold fields in new config.") } - cache_ptr->size_increase_possible = TRUE; /* will set to FALSE if needed */ - cache_ptr->size_decrease_possible = TRUE; /* will set to FALSE if needed */ + /* will set the increase possible fields to FALSE later if needed */ + cache_ptr->size_increase_possible = TRUE; + cache_ptr->flash_size_increase_possible = TRUE; + cache_ptr->size_decrease_possible = TRUE; switch ( config_ptr->incr_mode ) { @@ -6233,6 +6402,11 @@ H5C2_set_cache_auto_resize_config(H5C2_t * cache_ptr, HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown incr_mode?!?!?.") } + /* logically, this is were configuration for flash cache size increases + * should go. However, this configuration depends on max_cache_size, so + * we wait until the end of the function, when this field is set. + */ + switch ( config_ptr->decr_mode ) { case H5C2_decr__off: @@ -6277,9 +6451,14 @@ H5C2_set_cache_auto_resize_config(H5C2_t * cache_ptr, if ( config_ptr->max_size == config_ptr->min_size ) { cache_ptr->size_increase_possible = FALSE; + cache_ptr->flash_size_increase_possible = FALSE; cache_ptr->size_decrease_possible = FALSE; } + /* flash_size_increase_possible is intentionally omitted from the + * following: + */ + cache_ptr->resize_enabled = cache_ptr->size_increase_possible || cache_ptr->size_decrease_possible; @@ -6367,6 +6546,37 @@ H5C2_set_cache_auto_resize_config(H5C2_t * cache_ptr, } } + /* configure flash size increase facility. We wait until the + * end of the function, as we need the max_cache_size set before + * we start to keep things simple. + * + * If we haven't already ruled out flash cache size increases above, + * go ahead and configure it. + */ + + if ( cache_ptr->flash_size_increase_possible ) { + + switch ( config_ptr->flash_incr_mode ) + { + case H5C2_flash_incr__off: + cache_ptr->flash_size_increase_possible = FALSE; + break; + + case H5C2_flash_incr__add_space: + cache_ptr->flash_size_increase_possible = TRUE; + cache_ptr->flash_size_increase_threshold = + (size_t) + (((double)(cache_ptr->max_cache_size)) * + ((cache_ptr->resize_ctl).flash_threshold)); + break; + + default: /* should be unreachable */ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Unknown flash_incr_mode?!?!?.") + break; + } + } + done: FUNC_LEAVE_NOAPI(ret_value) @@ -7272,6 +7482,9 @@ done: * *cache_ptr), and one of its dxpl ids. Also internal * changes supporting the revised API. * + * JRM -- 12/31/07 + * Modified funtion to support flash cache resizes. + * *------------------------------------------------------------------------- */ herr_t @@ -7294,6 +7507,8 @@ H5C2_unprotect(H5C2_t * cache_ptr, hbool_t clear_entry = FALSE; #endif /* H5_HAVE_PARALLEL */ herr_t ret_value = SUCCEED; /* Return value */ + herr_t result; + size_t size_increase = 0; H5C2_cache_entry_t * entry_ptr; H5C2_cache_entry_t * test_entry_ptr; @@ -7439,6 +7654,29 @@ H5C2_unprotect(H5C2_t * cache_ptr, /* update for change in entry size if necessary */ if ( ( size_changed ) && ( entry_ptr->size != new_size ) ) { + /* do a flash cache size increase if appropriate */ + if ( cache_ptr->flash_size_increase_possible ) { + + if ( new_size > entry_ptr->size ) { + + size_increase = new_size - entry_ptr->size; + + if ( size_increase >= + cache_ptr->flash_size_increase_threshold ) { + + result = H5C2__flash_increase_cache_size(cache_ptr, + entry_ptr->size, + new_size); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "H5C2__flash_increase_cache_size failed.") + } + } + } + } + /* update the protected list */ H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr->pl_len), \ (cache_ptr->pl_size), \ @@ -7614,7 +7852,9 @@ done: * * Modifications: * - * None. + * Added validation for the flash increment fields. + * + * JRM -- 12/31/07 * *------------------------------------------------------------------------- */ @@ -7724,6 +7964,33 @@ H5C2_validate_resize_config(H5C2_auto_size_ctl_t * config_ptr, */ } /* H5C2_incr__threshold */ + switch ( config_ptr->flash_incr_mode ) + { + case H5C2_flash_incr__off: + /* nothing to do here */ + break; + + case H5C2_flash_incr__add_space: + if ( ( config_ptr->flash_multiple < 0.1 ) || + ( config_ptr->flash_multiple > 10.0 ) ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "flash_multiple must be in the range [0.1, 10.0]"); + } + + if ( ( config_ptr->flash_threshold < 0.1 ) || + ( config_ptr->flash_threshold > 1.0 ) ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "flash_threshold must be in the range [0.1, 1.0]"); + } + break; + + default: + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "Invalid flash_incr_mode"); + break; + } } /* H5C2_RESIZE_CFG__VALIDATE_INCREMENT */ @@ -7870,6 +8137,9 @@ done: * passed through to other calls, and are no longer * needed. * + * JRM -- 1/5/08 + * Added support for flash cache size increases. + * *------------------------------------------------------------------------- */ @@ -8147,6 +8417,31 @@ H5C2__auto_adjust_cache_size(H5C2_t * cache_ptr, cache_ptr->size_decreased = TRUE; } + + /* update flash cache size increase fields as appropriate */ + if ( cache_ptr->flash_size_increase_possible ) { + + switch ( (cache_ptr->resize_ctl).flash_incr_mode ) + { + case H5C2_flash_incr__off: + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "flash_size_increase_possible but H5C2_flash_incr__off?!") + break; + + case H5C2_flash_incr__add_space: + cache_ptr->flash_size_increase_threshold = + (size_t) + (((double)(cache_ptr->max_cache_size)) * + ((cache_ptr->resize_ctl).flash_threshold)); + break; + + default: /* should be unreachable */ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Unknown flash_incr_mode?!?!?.") + break; + } + } } if ( (cache_ptr->resize_ctl).rpt_fcn != NULL ) { @@ -8568,7 +8863,7 @@ H5C2__autoadjust__ageout__evict_aged_out_entries(hid_t dxpl_id, } if ( prev_ptr != NULL ) { - +#ifndef NDEBUG if ( prev_ptr->magic != H5C2__H5C2_CACHE_ENTRY_T_MAGIC ) { /* something horrible has happened to *prev_ptr -- @@ -8577,13 +8872,15 @@ H5C2__autoadjust__ageout__evict_aged_out_entries(hid_t dxpl_id, HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "*prev_ptr corrupt") - } else if ( ( prev_ptr->is_dirty != prev_is_dirty ) - || - ( prev_ptr->next != next_ptr ) - || - ( prev_ptr->is_protected ) - || - ( prev_ptr->is_pinned ) ) { + } else +#endif /* NDEBUG */ + if ( ( prev_ptr->is_dirty != prev_is_dirty ) + || + ( prev_ptr->next != next_ptr ) + || + ( prev_ptr->is_protected ) + || + ( prev_ptr->is_pinned ) ) { /* something has happened to the LRU -- start over * from the tail. @@ -8951,6 +9248,177 @@ done: /*------------------------------------------------------------------------- + * + * Function: H5C2__flash_increase_cache_size + * + * Purpose: If there is not at least new_entry_size - old_entry_size + * bytes of free space in the cache and the current + * max_cache_size is less than (cache_ptr->resize_ctl).max_size, + * perform a flash increase in the cache size and then reset + * the full cache hit rate statistics, and exit. + * + * Return: Non-negative on success/Negative on failure. + * + * Programmer: John Mainzer, 12/31/07 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +static herr_t +H5C2__flash_increase_cache_size(H5C2_t * cache_ptr, + size_t old_entry_size, + size_t new_entry_size) +{ + /* const char * fcn_name = "H5C2__flash_increase_cache_size()";*/ + herr_t ret_value = SUCCEED; /* Return value */ + size_t new_max_cache_size = 0; + size_t old_max_cache_size = 0; + size_t new_min_clean_size = 0; + size_t old_min_clean_size = 0; + size_t space_needed; + enum H5C2_resize_status status = flash_increase2; /* may change */ + double hit_rate; + + FUNC_ENTER_NOAPI_NOINIT(H5C2__flash_increase_cache_size) + HDassert( cache_ptr ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( cache_ptr->flash_size_increase_possible ); + HDassert( new_entry_size > cache_ptr->flash_size_increase_threshold ); + HDassert( old_entry_size < new_entry_size ); + + if ( old_entry_size >= new_entry_size ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "old_entry_size >= new_entry_size") + } + + space_needed = new_entry_size - old_entry_size; + + if ( ( (cache_ptr->index_size + space_needed) > + cache_ptr->max_cache_size ) && + ( cache_ptr->max_cache_size < (cache_ptr->resize_ctl).max_size ) ) { + + /* we have work to do */ + + switch ( (cache_ptr->resize_ctl).flash_incr_mode ) + { + case H5C2_flash_incr__off: + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "flash_size_increase_possible but H5C2_flash_incr__off?!") + break; + + case H5C2_flash_incr__add_space: + if ( cache_ptr->index_size < cache_ptr->max_cache_size ) { + + HDassert( (cache_ptr->max_cache_size - + cache_ptr->index_size) + < space_needed ); + space_needed -= cache_ptr->max_cache_size - + cache_ptr->index_size; + } + space_needed = + (size_t)(((double)space_needed) * + (cache_ptr->resize_ctl).flash_multiple); + + new_max_cache_size = cache_ptr->max_cache_size + space_needed; + + break; + + default: /* should be unreachable */ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Unknown flash_incr_mode?!?!?.") + break; + } + + if ( new_max_cache_size > (cache_ptr->resize_ctl).max_size ) { + + new_max_cache_size = (cache_ptr->resize_ctl).max_size; + } + + HDassert( new_max_cache_size > cache_ptr->max_cache_size ); + + new_min_clean_size = (size_t) + ((double)new_max_cache_size * + ((cache_ptr->resize_ctl).min_clean_fraction)); + + HDassert( new_min_clean_size <= new_max_cache_size ); + + old_max_cache_size = cache_ptr->max_cache_size; + old_min_clean_size = cache_ptr->min_clean_size; + + cache_ptr->max_cache_size = new_max_cache_size; + cache_ptr->min_clean_size = new_min_clean_size; + + /* update flash cache size increase fields as appropriate */ + HDassert ( cache_ptr->flash_size_increase_possible ); + + switch ( (cache_ptr->resize_ctl).flash_incr_mode ) + { + case H5C2_flash_incr__off: + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "flash_size_increase_possible but H5C2_flash_incr__off?!") + break; + + case H5C2_flash_incr__add_space: + cache_ptr->flash_size_increase_threshold = + (size_t) + (((double)(cache_ptr->max_cache_size)) * + ((cache_ptr->resize_ctl).flash_threshold)); + break; + + default: /* should be unreachable */ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Unknown flash_incr_mode?!?!?.") + break; + } + + /* note that we don't cycle the epoch markers. We can + * argue either way as to whether we should, but for now + * we don't. + */ + + if ( (cache_ptr->resize_ctl).rpt_fcn != NULL ) { + + /* get the hit rate for the reporting function. Should still + * be good as we havent reset the hit rate statistics. + */ + if ( H5C2_get_cache_hit_rate(cache_ptr, &hit_rate) != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't get hit rate.") + } + + (*((cache_ptr->resize_ctl).rpt_fcn)) + (cache_ptr, + H5C2__CURR_AUTO_RESIZE_RPT_FCN_VER, + hit_rate, + status, + old_max_cache_size, + new_max_cache_size, + old_min_clean_size, + new_min_clean_size); + } + + if ( H5C2_reset_cache_hit_rate_stats(cache_ptr) != SUCCEED ) { + + /* this should be impossible... */ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_reset_cache_hit_rate_stats failed.") + } + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C2__flash_increase_cache_size() */ + + + +/*------------------------------------------------------------------------- * Function: H5C2_flush_invalidate_cache * * Purpose: Flush and destroy the entries contained in the target @@ -8991,12 +9459,27 @@ done: * entries being dirtied, resized, and/or renamed inside * flush callbacks. Updated function to support this. * - * -- JRM 8/27/06 - * * Reworked argument list and code to reflect the * removal of the secondary dxpl id, and the decision * to store f in H5C2_t, removing the need to pass it * in all the time. + * -- 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 I should just scream and die if I + * ever detect the condidtion. + * + * -- JRM 10/13/07 * *------------------------------------------------------------------------- */ @@ -9112,8 +9595,10 @@ H5C2_flush_invalidate_cache(hid_t dxpl_id, HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "next_entry_ptr == NULL 1 ?!?!"); } - - HDassert( next_entry_ptr->magic == H5C2__H5C2_CACHE_ENTRY_T_MAGIC ); +#ifndef NDEBUG + HDassert( next_entry_ptr->magic == + H5C2__H5C2_CACHE_ENTRY_T_MAGIC ); +#endif /* NDEBUG */ HDassert( next_entry_ptr->is_dirty ); HDassert( next_entry_ptr->in_slist ); @@ -9180,14 +9665,16 @@ H5C2_flush_invalidate_cache(hid_t dxpl_id, * If the entry has been evicted, we flag an error and * exit. */ - +#ifndef NDEBUG if ( entry_ptr->magic != H5C2__H5C2_CACHE_ENTRY_T_MAGIC ) { HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "entry_ptr->magic is invalid ?!?!"); - } else if ( ( ! entry_ptr->is_dirty ) || - ( ! entry_ptr->in_slist ) ) { + } else +#endif /* NDEBUG */ + if ( ( ! entry_ptr->is_dirty ) || + ( ! entry_ptr->in_slist ) ) { /* the s-list has been modified out from under us. * break out of the loop. @@ -9208,9 +9695,10 @@ H5C2_flush_invalidate_cache(hid_t dxpl_id, HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "next_entry_ptr == NULL 2 ?!?!"); } - +#ifndef NDEBUG HDassert( next_entry_ptr->magic == H5C2__H5C2_CACHE_ENTRY_T_MAGIC ); +#endif /* NDEBUG */ HDassert( next_entry_ptr->is_dirty ); HDassert( next_entry_ptr->in_slist ); @@ -9345,15 +9833,15 @@ H5C2_flush_invalidate_cache(hid_t dxpl_id, while ( next_entry_ptr != NULL ) { entry_ptr = next_entry_ptr; - +#ifndef NDEBUG HDassert( entry_ptr->magic == H5C2__H5C2_CACHE_ENTRY_T_MAGIC ); - +#endif /* NDEBUG */ next_entry_ptr = entry_ptr->ht_next; - +#ifndef NDEBUG HDassert ( ( next_entry_ptr == NULL ) || ( next_entry_ptr->magic == H5C2__H5C2_CACHE_ENTRY_T_MAGIC ) ); - +#endif /* NDEBUG */ if ( entry_ptr->is_protected ) { /* we have major problems -- but lets flush and destroy @@ -9405,6 +9893,7 @@ H5C2_flush_invalidate_cache(hid_t dxpl_id, * we are accessing a deallocated piece of dynamically * allocated memory, so we just scream and die. */ +#ifndef NDEBUG if ( ( next_entry_ptr != NULL ) && ( next_entry_ptr->magic != H5C2__H5C2_CACHE_ENTRY_T_MAGIC ) ) { @@ -9415,6 +9904,7 @@ H5C2_flush_invalidate_cache(hid_t dxpl_id, HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "next_entry_ptr->magic is invalid?!?!?.") } +#endif /* NDEBUG */ } /* end while loop scanning hash table bin */ } /* end for loop scanning hash table */ @@ -10203,8 +10693,9 @@ H5C2_flush_single_entry(H5F_t * f, * set the magic field to bad magic so we can detect a * freed entry if we see one. */ +#ifndef NDEBUG entry_ptr->magic = H5C2__H5C2_CACHE_ENTRY_T_BAD_MAGIC; - +#endif /* NDEBUG */ if ( type_ptr->free_icr(entry_ptr->addr, entry_ptr->size, (void *)entry_ptr) != SUCCEED ) { @@ -10423,8 +10914,9 @@ H5C2_load_entry(H5F_t * f, HDassert( ( dirty == FALSE ) || ( type->id == 4 ) ); HDassert( entry_ptr->size < H5C2_MAX_ENTRY_SIZE ); - +#ifndef NDEBUG entry_ptr->magic = H5C2__H5C2_CACHE_ENTRY_T_MAGIC; +#endif /* NDEBUG */ entry_ptr->addr = addr; entry_ptr->size = len; entry_ptr->image_ptr = image_ptr; @@ -10547,6 +11039,7 @@ H5C2_make_space_in_cache(hid_t dxpl_id, size_t empty_space; #endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ hbool_t prev_is_dirty = FALSE; + hbool_t entry_is_epoch_maker = FALSE; H5C2_cache_entry_t * entry_ptr; H5C2_cache_entry_t * prev_ptr; H5C2_cache_entry_t * next_ptr; @@ -10585,6 +11078,8 @@ H5C2_make_space_in_cache(hid_t dxpl_id, if ( (entry_ptr->type)->id != H5C2__EPOCH_MARKER_TYPE ) { + entry_is_epoch_maker = FALSE; + if ( entry_ptr->is_dirty ) { result = H5C2_flush_single_entry(cache_ptr->f, @@ -10610,6 +11105,7 @@ H5C2_make_space_in_cache(hid_t dxpl_id, /* Skip epoch markers. Set result to SUCCEED to avoid * triggering the error code below. */ + entry_is_epoch_maker = TRUE; result = SUCCEED; } @@ -10620,7 +11116,7 @@ H5C2_make_space_in_cache(hid_t dxpl_id, } if ( prev_ptr != NULL ) { - +#ifndef NDEBUG if ( prev_ptr->magic != H5C2__H5C2_CACHE_ENTRY_T_MAGIC ) { /* something horrible has happened to *prev_ptr -- @@ -10629,6 +11125,16 @@ H5C2_make_space_in_cache(hid_t dxpl_id, HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "*prev_ptr corrupt 1") + } else +#endif /* NDEBUG */ + if ( entry_is_epoch_maker ) { + + /* epoch markers don't get flushed, so the sanity checks + * on normal entries will fail -- thus just set entry_ptr + * to prev_ptr and go on. + */ + entry_ptr = prev_ptr; + } else if ( ( prev_ptr->is_dirty != prev_is_dirty ) || ( prev_ptr->next != next_ptr ) @@ -10659,6 +11165,7 @@ H5C2_make_space_in_cache(hid_t dxpl_id, #if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + entries_examined = 0; initial_list_len = cache_ptr->dLRU_list_len; entry_ptr = cache_ptr->dLRU_tail_ptr; @@ -10707,7 +11214,7 @@ H5C2_make_space_in_cache(hid_t dxpl_id, } if ( prev_ptr != NULL ) { - +#ifndef NDEBUG if (prev_ptr->magic != H5C2__H5C2_CACHE_ENTRY_T_MAGIC) { /* something horrible has happened to *prev_ptr -- @@ -10717,13 +11224,15 @@ H5C2_make_space_in_cache(hid_t dxpl_id, HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "*prev_ptr corrupt 2") - } else if ( ( ! ( prev_ptr->is_dirty ) ) - || - ( prev_ptr->aux_next != next_ptr ) - || - ( prev_ptr->is_protected ) - || - ( prev_ptr->is_pinned ) ) { + } else +#endif /* #ifndef NDEBUG */ + if ( ( ! ( prev_ptr->is_dirty ) ) + || + ( prev_ptr->aux_next != next_ptr ) + || + ( prev_ptr->is_protected ) + || + ( prev_ptr->is_pinned ) ) { /* something has happened to the dirty LRU -- start over * from the tail. |