From 2d6bb5932951242d23ccef420a328a033f3b4efa Mon Sep 17 00:00:00 2001 From: John Mainzer Date: Wed, 18 Oct 2006 05:51:26 -0500 Subject: [svn-r12774] Modified flush code in the metadata cache to allow it to handle flush callbacks which can dirty other entries, and resize and/or rename the target entry. This feature is needed by the fractal heap code. Also added associated test code. H5Commit tested. Test failed on heping, but the error appears to be a syntax error in an un-related file. Tests on copper & sol passed, along with tests on phoenix. --- src/H5ACprivate.h | 4 + src/H5B2cache.c | 29 +- src/H5Bcache.c | 10 +- src/H5C.c | 961 +++++++-- src/H5Cpkg.h | 61 +- src/H5Cprivate.h | 18 +- src/H5FScache.c | 20 +- src/H5Gnode.c | 10 +- src/H5HFcache.c | 29 +- src/H5HG.c | 11 +- src/H5HL.c | 10 +- src/H5Ocache.c | 10 +- test/cache.c | 5825 +++++++++++++++++++++++++++++++++++++++++++++++++-- test/cache_common.c | 911 +++++++- test/cache_common.h | 215 +- 15 files changed, 7694 insertions(+), 430 deletions(-) diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h index fd6a073..dab3cf2 100644 --- a/src/H5ACprivate.h +++ b/src/H5ACprivate.h @@ -114,6 +114,10 @@ typedef enum { * Note that the space allocated on disk may not be contiguous. */ +#define H5AC_CALLBACK__NO_FLAGS_SET H5C_CALLBACK__NO_FLAGS_SET +#define H5AC_CALLBACK__SIZE_CHANGED_FLAG H5C_CALLBACK__SIZE_CHANGED_FLAG +#define H5AC_CALLBACK__RENAMED_FLAG H5C_CALLBACK__RENAMED_FLAG + typedef H5C_load_func_t H5AC_load_func_t; typedef H5C_flush_func_t H5AC_flush_func_t; typedef H5C_dest_func_t H5AC_dest_func_t; diff --git a/src/H5B2cache.c b/src/H5B2cache.c index 9019765..e484529 100644 --- a/src/H5B2cache.c +++ b/src/H5B2cache.c @@ -62,15 +62,15 @@ /* Metadata cache callbacks */ static H5B2_t *H5B2_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_type, void *udata); -static herr_t H5B2_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_t *b); +static herr_t H5B2_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_t *b, unsigned UNUSED * flags_ptr); static herr_t H5B2_cache_hdr_clear(H5F_t *f, H5B2_t *b, hbool_t destroy); static herr_t H5B2_cache_hdr_size(const H5F_t *f, const H5B2_t *bt, size_t *size_ptr); static H5B2_internal_t *H5B2_cache_internal_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_nrec, void *_shared); -static herr_t H5B2_cache_internal_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_internal_t *i); +static herr_t H5B2_cache_internal_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_internal_t *i, unsigned UNUSED * flags_ptr); static herr_t H5B2_cache_internal_clear(H5F_t *f, H5B2_internal_t *i, hbool_t destroy); static herr_t H5B2_cache_internal_size(const H5F_t *f, const H5B2_internal_t *i, size_t *size_ptr); static H5B2_leaf_t *H5B2_cache_leaf_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_nrec, void *_shared); -static herr_t H5B2_cache_leaf_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_leaf_t *l); +static herr_t H5B2_cache_leaf_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_leaf_t *l, unsigned UNUSED * flags_ptr); static herr_t H5B2_cache_leaf_clear(H5F_t *f, H5B2_leaf_t *l, hbool_t destroy); static herr_t H5B2_cache_leaf_size(const H5F_t *f, const H5B2_leaf_t *l, size_t *size_ptr); @@ -248,11 +248,16 @@ done: * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Feb 1 2005 + * Changes: JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. * *------------------------------------------------------------------------- */ static herr_t -H5B2_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_t *bt2) +H5B2_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_t *bt2, unsigned UNUSED * flags_ptr) { herr_t ret_value = SUCCEED; /* Return value */ @@ -579,11 +584,16 @@ done: * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Feb 3 2005 + * Changes: JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. * *------------------------------------------------------------------------- */ static herr_t -H5B2_cache_internal_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_internal_t *internal) +H5B2_cache_internal_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_internal_t *internal, unsigned UNUSED * flags_ptr) { herr_t ret_value = SUCCEED; /* Return value */ @@ -909,10 +919,17 @@ done: * koziol@ncsa.uiuc.edu * Feb 2 2005 * + * Changes: JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. + * + * *------------------------------------------------------------------------- */ static herr_t -H5B2_cache_leaf_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_leaf_t *leaf) +H5B2_cache_leaf_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_leaf_t *leaf, unsigned UNUSED * flags_ptr) { herr_t ret_value = SUCCEED; /* Return value */ diff --git a/src/H5Bcache.c b/src/H5Bcache.c index 6f8e259..554ec11 100644 --- a/src/H5Bcache.c +++ b/src/H5Bcache.c @@ -54,7 +54,7 @@ static herr_t H5B_serialize(const H5F_t *f, const H5B_t *bt); /* Metadata cache callbacks */ static H5B_t *H5B_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_type, void *udata); -static herr_t H5B_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B_t *b); +static herr_t H5B_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B_t *b, unsigned UNUSED * flags_ptr); static herr_t H5B_clear(H5F_t *f, H5B_t *b, hbool_t destroy); static herr_t H5B_compute_size(const H5F_t *f, const H5B_t *bt, size_t *size_ptr); @@ -258,10 +258,16 @@ done: * matzke@llnl.gov * Jun 23 1997 * + * Changes: JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. + * *------------------------------------------------------------------------- */ static herr_t -H5B_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B_t *bt) +H5B_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B_t *bt, unsigned UNUSED * flags_ptr) { H5B_shared_t *shared; /* Pointer to shared B-tree info */ herr_t ret_value = SUCCEED; /* Return value */ diff --git a/src/H5C.c b/src/H5C.c index 8e4bb0e..498cc2f 100644 --- a/src/H5C.c +++ b/src/H5C.c @@ -559,10 +559,22 @@ if ( ( (entry_ptr) == NULL ) || \ if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; -#define H5C__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr) \ +#define H5C__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr) \ + if ( cache_ptr->flush_in_progress ) { \ + ((cache_ptr)->cache_flush_renames[(entry_ptr)->type->id])++; \ + } \ + if ( entry_ptr->flush_in_progress ) { \ + ((cache_ptr)->entry_flush_renames[(entry_ptr)->type->id])++; \ + } \ (((cache_ptr)->renames)[(entry_ptr)->type->id])++; #define H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size)\ + if ( cache_ptr->flush_in_progress ) { \ + ((cache_ptr)->cache_flush_size_changes[(entry_ptr)->type->id])++; \ + } \ + if ( entry_ptr->flush_in_progress ) { \ + ((cache_ptr)->entry_flush_size_changes[(entry_ptr)->type->id])++; \ + } \ if ( (entry_ptr)->size < (new_size) ) { \ ((cache_ptr)->size_increases[(entry_ptr)->type->id])++; \ if ( (cache_ptr)->index_size > (cache_ptr)->max_index_size ) \ @@ -571,7 +583,7 @@ if ( ( (entry_ptr) == NULL ) || \ (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; \ if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size ) \ (cache_ptr)->max_pl_size = (cache_ptr)->pl_size; \ - } else { \ + } else if ( (entry_ptr)->size > (new_size) ) { \ ((cache_ptr)->size_decreases[(entry_ptr)->type->id])++; \ } @@ -1077,9 +1089,49 @@ if ( ( (cache_ptr) == NULL ) || \ * JRM -- 6/27/06 * Added fail_val parameter. * + * JRM -- 8/25/06 + * Added the H5C_DO_SANITY_CHECKS version of the macro. + * + * This version maintains the slist_len_increase and + * slist_size_increase fields that are used in sanity + * checks in the flush routines. + * + * All this is needed as the fractal heap needs to be + * able to dirty, resize and/or rename entries during the + * flush. + * *------------------------------------------------------------------------- */ +#if H5C_DO_SANITY_CHECKS + +#define H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( H5F_addr_defined((entry_ptr)->addr) ); \ + HDassert( !((entry_ptr)->in_slist) ); \ + \ + if ( H5SL_insert((cache_ptr)->slist_ptr, entry_ptr, &(entry_ptr)->addr) \ + < 0 ) \ + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, (fail_val), \ + "Can't insert entry in skip list") \ + \ + (entry_ptr)->in_slist = TRUE; \ + (cache_ptr)->slist_len++; \ + (cache_ptr)->slist_size += (entry_ptr)->size; \ + (cache_ptr)->slist_len_increase++; \ + (cache_ptr)->slist_size_increase += (entry_ptr)->size; \ + \ + HDassert( (cache_ptr)->slist_len > 0 ); \ + HDassert( (cache_ptr)->slist_size > 0 ); \ + \ +} /* H5C__INSERT_ENTRY_IN_SLIST */ + +#else /* H5C_DO_SANITY_CHECKS */ + #define H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val) \ { \ HDassert( (cache_ptr) ); \ @@ -1103,6 +1155,8 @@ if ( ( (cache_ptr) == NULL ) || \ \ } /* H5C__INSERT_ENTRY_IN_SLIST */ +#endif /* H5C_DO_SANITY_CHECKS */ + /*------------------------------------------------------------------------- * @@ -1169,11 +1223,21 @@ if ( ( (cache_ptr) == NULL ) || \ * * Modifications: * - * None. + * JRM -- 8/27/06 + * Added the H5C_DO_SANITY_CHECKS version of the macro. + * + * This version maintains the slist_size_increase field + * that are used in sanity checks in the flush routines. + * + * All this is needed as the fractal heap needs to be + * able to dirty, resize and/or rename entries during the + * flush. * *------------------------------------------------------------------------- */ +#if H5C_DO_SANITY_CHECKS + #define H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \ { \ HDassert( (cache_ptr) ); \ @@ -1188,11 +1252,37 @@ if ( ( (cache_ptr) == NULL ) || \ (cache_ptr)->slist_size -= (old_size); \ (cache_ptr)->slist_size += (new_size); \ \ + (cache_ptr)->slist_size_increase -= (int64_t)(old_size); \ + (cache_ptr)->slist_size_increase += (int64_t)(new_size); \ + \ HDassert( (new_size) <= (cache_ptr)->slist_size ); \ HDassert( ( (cache_ptr)->slist_len > 1 ) || \ ( (cache_ptr)->slist_size == (new_size) ) ); \ } /* H5C__REMOVE_ENTRY_FROM_SLIST */ +#else /* H5C_DO_SANITY_CHECKS */ + +#define H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \ + HDassert( (old_size) > 0 ); \ + HDassert( (new_size) > 0 ); \ + HDassert( (old_size) <= (cache_ptr)->slist_size ); \ + HDassert( (cache_ptr)->slist_len > 0 ); \ + HDassert( ((cache_ptr)->slist_len > 1) || \ + ( (cache_ptr)->slist_size == (old_size) ) ); \ + \ + (cache_ptr)->slist_size -= (old_size); \ + (cache_ptr)->slist_size += (new_size); \ + \ + HDassert( (new_size) <= (cache_ptr)->slist_size ); \ + HDassert( ( (cache_ptr)->slist_len > 1 ) || \ + ( (cache_ptr)->slist_size == (new_size) ) ); \ +} /* H5C__REMOVE_ENTRY_FROM_SLIST */ + +#endif /* H5C_DO_SANITY_CHECKS */ + /************************************************************************** * @@ -1997,6 +2087,127 @@ if ( ( (cache_ptr) == NULL ) || \ /*------------------------------------------------------------------------- * + * Macro: H5C__UPDATE_RP_FOR_SIZE_CHANGE + * + * Purpose: Update the replacement policy data structures for a + * size change of the specified cache entry. + * + * To do this, determine if the entry is pinned. If it is, + * update the size of the pinned entry list. + * + * If it isn't pinned, the entry must handled by the + * replacement policy. Update the appropriate replacement + * policy data structures. + * + * At present, we only support the modified LRU policy, so + * this function deals with that case unconditionally. If + * we ever support other replacement policies, the function + * should switch on the current policy and act accordingly. + * + * Return: N/A + * + * Programmer: John Mainzer, 8/23/06 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_size) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( new_size > 0 ); \ + \ + if ( (entry_ptr)->is_pinned ) { \ + \ + H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + } else { \ + \ + /* modified LRU specific code */ \ + \ + /* Update the size of the LRU list */ \ + \ + H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->LRU_list_len, \ + (cache_ptr)->LRU_list_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + /* Similarly, update the size of the clean or dirty LRU list as \ + * appropriate. At present, the entry must be clean, but that \ + * could change. \ + */ \ + \ + if ( (entry_ptr)->is_dirty ) { \ + \ + H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->dLRU_list_len, \ + (cache_ptr)->dLRU_list_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + } else { \ + \ + H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->cLRU_list_len, \ + (cache_ptr)->cLRU_list_size, \ + (entry_ptr)->size, \ + (new_size)); \ + } \ + \ + /* End modified LRU specific code. */ \ + } \ + \ +} /* H5C__UPDATE_RP_FOR_SIZE_CHANGE */ + +#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_size) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( new_size > 0 ); \ + \ + if ( (entry_ptr)->is_pinned ) { \ + \ + H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + } else { \ + \ + /* modified LRU specific code */ \ + \ + /* Update the size of the LRU list */ \ + \ + H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->LRU_list_len, \ + (cache_ptr)->LRU_list_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + /* End modified LRU specific code. */ \ + } \ + \ +} /* H5C__UPDATE_RP_FOR_SIZE_CHANGE */ + +#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/*------------------------------------------------------------------------- + * * Macro: H5C__UPDATE_RP_FOR_UNPIN * * Purpose: Update the replacement policy data structures for an @@ -2352,7 +2563,8 @@ static herr_t H5C_verify_not_in_index(H5C_t * cache_ptr, static void *H5C_epoch_marker_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata1, void *udata2); static herr_t H5C_epoch_marker_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, + unsigned *flags_ptr); static herr_t H5C_epoch_marker_dest(H5F_t *f, void *thing); static herr_t H5C_epoch_marker_clear(H5F_t *f, void *thing, hbool_t dest); static herr_t H5C_epoch_marker_size(const H5F_t *f, const void *thing, size_t *size_ptr); @@ -2377,11 +2589,11 @@ const H5C_class_t epoch_marker_class = ***************************************************************************/ static void * -H5C_epoch_marker_load(UNUSED H5F_t *f, - UNUSED hid_t dxpl_id, - UNUSED haddr_t addr, - UNUSED const void *udata1, - UNUSED void *udata2) +H5C_epoch_marker_load(H5F_t UNUSED * f, + hid_t UNUSED dxpl_id, + haddr_t UNUSED addr, + const void UNUSED * udata1, + void UNUSED * udata2) { void * ret_value = NULL; /* Return value */ @@ -2395,11 +2607,12 @@ done: } static herr_t -H5C_epoch_marker_flush(UNUSED H5F_t *f, - UNUSED hid_t dxpl_id, - UNUSED hbool_t dest, - UNUSED haddr_t addr, - UNUSED void *thing) +H5C_epoch_marker_flush(H5F_t UNUSED *f, + hid_t UNUSED dxpl_id, + hbool_t UNUSED dest, + haddr_t UNUSED addr, + void UNUSED *thing, + unsigned UNUSED * flags_ptr) { herr_t ret_value = FAIL; /* Return value */ @@ -2413,8 +2626,8 @@ done: } static herr_t -H5C_epoch_marker_dest(UNUSED H5F_t *f, - UNUSED void *thing) +H5C_epoch_marker_dest(H5F_t UNUSED * f, + void UNUSED * thing) { herr_t ret_value = FAIL; /* Return value */ @@ -2428,9 +2641,9 @@ done: } static herr_t -H5C_epoch_marker_clear(UNUSED H5F_t *f, - UNUSED void *thing, - UNUSED hbool_t dest) +H5C_epoch_marker_clear(H5F_t UNUSED * f, + void UNUSED * thing, + hbool_t UNUSED dest) { herr_t ret_value = FAIL; /* Return value */ @@ -2444,9 +2657,9 @@ done: } static herr_t -H5C_epoch_marker_size(UNUSED const H5F_t *f, - UNUSED const void *thing, - UNUSED size_t *size_ptr) +H5C_epoch_marker_size(const H5F_t UNUSED * f, + const void UNUSED * thing, + size_t UNUSED * size_ptr) { herr_t ret_value = FAIL; /* Return value */ @@ -2518,6 +2731,15 @@ done: * 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. + * *------------------------------------------------------------------------- */ @@ -2572,6 +2794,8 @@ H5C_create(size_t max_cache_size, cache_ptr->magic = H5C__H5C_T_MAGIC; + cache_ptr->flush_in_progress = FALSE; + cache_ptr->trace_file_ptr = NULL; cache_ptr->aux_ptr = aux_ptr; @@ -2593,6 +2817,11 @@ H5C_create(size_t max_cache_size, cache_ptr->slist_len = 0; cache_ptr->slist_size = (size_t)0; +#if H5C_DO_SANITY_CHECKS + cache_ptr->slist_len_increase = 0; + cache_ptr->slist_size_increase = 0; +#endif /* H5C_DO_SANITY_CHECKS */ + for ( i = 0; i < H5C__HASH_TABLE_LEN; i++ ) { (cache_ptr->index)[i] = NULL; @@ -2754,7 +2983,7 @@ H5C_def_auto_resize_rpt_fcn(H5C_t * cache_ptr, #ifndef NDEBUG int32_t version, #else /* NDEBUG */ - UNUSED int32_t version, + int32_t UNUSED version, #endif /* NDEBUG */ double hit_rate, enum H5C_resize_status status, @@ -3193,9 +3422,18 @@ done: * Note that even with this flag set, it is still an error * to try to flush a protected entry. * - * JRM -- 3/25/065 + * JRM -- 3/25/06 * Updated function to handle pinned entries. * + * JRM -- 8/19/06 + * Added code managing the new flush_in_progress field of + * H5C_t. + * + * Also reworked function to allow for the possibility that + * entries will be dirtied, resized, or renamed during flush + * callbacks. As a result, we may have to make multiple + * passes through the skip list before the cache is flushed. + * *------------------------------------------------------------------------- */ herr_t @@ -3208,18 +3446,20 @@ H5C_flush_cache(H5F_t * f, herr_t status; herr_t ret_value = SUCCEED; hbool_t destroy; + hbool_t flushed_entries_last_pass; hbool_t flush_marked_entries; hbool_t first_flush = TRUE; hbool_t ignore_protected; hbool_t tried_to_flush_protected_entry = FALSE; + int32_t passes = 0; int32_t protected_entries = 0; H5SL_node_t * node_ptr = NULL; H5C_cache_entry_t * entry_ptr = NULL; #if H5C_DO_SANITY_CHECKS - int32_t actual_slist_len = 0; - int32_t initial_slist_len = 0; - size_t actual_slist_size = 0; - size_t initial_slist_size = 0; + int64_t flushed_entries_count; + size_t flushed_entries_size; + int64_t initial_slist_len; + size_t initial_slist_size; #endif /* H5C_DO_SANITY_CHECKS */ FUNC_ENTER_NOAPI(H5C_flush_cache, FAIL) @@ -3241,6 +3481,10 @@ H5C_flush_cache(H5F_t * f, HDassert( ! ( destroy && ignore_protected ) ); + HDassert( ! ( cache_ptr->flush_in_progress ) ); + + cache_ptr->flush_in_progress = TRUE; + if ( destroy ) { status = H5C_flush_invalidate_cache(f, @@ -3258,103 +3502,160 @@ H5C_flush_cache(H5F_t * f, "flush invalidate failed.") } } else { - - if ( cache_ptr->slist_len == 0 ) { - - node_ptr = NULL; - HDassert( cache_ptr->slist_size == 0 ); - - } else { - + /* When we are only flushing marked entries, the slist will usually + * still contain entries when we have flushed everything we should. + * Thus we track whether we have flushed any entries in the last + * pass, and terminate if we haven't. + */ + + flushed_entries_last_pass = TRUE; + + while ( ( passes < H5C__MAX_PASSES_ON_FLUSH ) && + ( cache_ptr->slist_len != 0 ) && + ( protected_entries == 0 ) && + ( flushed_entries_last_pass ) ) + { + flushed_entries_last_pass = FALSE; node_ptr = H5SL_first(cache_ptr->slist_ptr); + + HDassert( node_ptr != NULL ); #if H5C_DO_SANITY_CHECKS - /* H5C_flush_single_entry() now removes dirty entries from the - * slist as it flushes them. Thus for sanity checks we must - * make note of the initial slist length and size before we - * do any flushes. - */ + /* For sanity checking, try to verify that the skip list has + * the expected size and number of entries at the end of each + * internal while loop (see below). + * + * Doing this get a bit tricky, as depending on flags, we may + * or may not flush all the entries in the slist. + * + * To make things more entertaining, with the advent of the + * fractal heap, the entry flush callback can cause entries + * to be dirtied, resized, and/or renamed. + * + * To deal with this, we first make note of the initial + * skip list length and size: + */ initial_slist_len = cache_ptr->slist_len; initial_slist_size = cache_ptr->slist_size; -#endif /* H5C_DO_SANITY_CHECKS */ - - } - - while ( node_ptr != NULL ) - { - entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); - - /* increment node pointer now, before we delete its target - * from the slist. - */ - node_ptr = H5SL_next(node_ptr); - - HDassert( entry_ptr != NULL ); - HDassert( entry_ptr->in_slist ); -#if H5C_DO_SANITY_CHECKS - actual_slist_len++; - actual_slist_size += entry_ptr->size; + /* We then zero counters that we use to track the number + * and total size of entries flushed: + */ + flushed_entries_count = 0; + flushed_entries_size = 0; + + /* As mentioned above, there is the possibility that + * entries will be dirtied, resized, and/or flushed during + * our pass through the skip list. To capture the number + * of entries added, and the skip list size delta, + * zero the slist_len_increase and slist_size_increase of + * the cache's instance of H5C_t. These fields will be + * updated elsewhere to account for slist insertions and/or + * dirty entry size changes. + */ + cache_ptr->slist_len_increase = 0; + cache_ptr->slist_size_increase = 0; + + /* at the end of the loop, use these values to compute the + * expected slist length and size and compare this with the + * value recorded in the cache's instance of H5C_t. + */ #endif /* H5C_DO_SANITY_CHECKS */ - if ( ( ! flush_marked_entries ) || ( entry_ptr->flush_marker ) ) { + while ( node_ptr != NULL ) + { + entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); - if ( entry_ptr->is_protected ) { + /* increment node pointer now, before we delete its target + * from the slist. + */ + node_ptr = H5SL_next(node_ptr); - /* 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++; + HDassert( entry_ptr != NULL ); + HDassert( entry_ptr->in_slist ); - } else { + if ( ( ! flush_marked_entries ) || + ( entry_ptr->flush_marker ) ) { - status = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - cache_ptr, - NULL, - entry_ptr->addr, - flags, - &first_flush, - FALSE); - if ( status < 0 ) { + if ( entry_ptr->is_protected ) { - /* This shouldn't happen -- if it does, we are toast so - * just scream and die. + /* we probably have major problems -- but lets flush + * everything we can before we decide whether to flag + * an error. */ - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ - "Can't flush entry.") + tried_to_flush_protected_entry = TRUE; + protected_entries++; + + } else { +#if H5C_DO_SANITY_CHECKS + flushed_entries_count++; + flushed_entries_size += entry_ptr->size; +#endif /* H5C_DO_SANITY_CHECKS */ + status = H5C_flush_single_entry(f, + primary_dxpl_id, + secondary_dxpl_id, + cache_ptr, + NULL, + entry_ptr->addr, + flags, + &first_flush, + FALSE); + if ( status < 0 ) { + + /* This shouldn't happen -- if it does, we are + * toast so just scream and die. + */ + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Can't flush entry.") + } + flushed_entries_last_pass = TRUE; } } - } - } /* while */ + } /* while ( node_ptr != NULL ) */ #if H5C_DO_SANITY_CHECKS - HDassert( actual_slist_len == initial_slist_len ); - HDassert( actual_slist_size == initial_slist_size ); - - if ( ! flush_marked_entries ) { + /* Verify that the slist size and length are as expected. */ - HDassert( cache_ptr->slist_len == 0 ); - HDassert( cache_ptr->slist_size == 0 ); - } + HDassert( (initial_slist_len + cache_ptr->slist_len_increase - + flushed_entries_count) == cache_ptr->slist_len ); + HDassert( (initial_slist_size + cache_ptr->slist_size_increase - + flushed_entries_size) == cache_ptr->slist_size ); #endif /* H5C_DO_SANITY_CHECKS */ + passes++; + + } /* 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_PROTECT, FAIL, \ + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ "cache has protected items") } - } + + if ( ( cache_ptr->slist_len != 0 ) && + ( passes >= H5C__MAX_PASSES_ON_FLUSH ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "flush pass limit exceeded.") + } + +#if H5C_DO_SANITY_CHECKS + if ( ! flush_marked_entries ) { + + HDassert( cache_ptr->slist_len == 0 ); + HDassert( cache_ptr->slist_size == 0 ); + } +#endif /* H5C_DO_SANITY_CHECKS */ + + } done: + cache_ptr->flush_in_progress = FALSE; FUNC_LEAVE_NOAPI(ret_value) @@ -3964,6 +4265,10 @@ done: * JRM -- 8/9/06 * Added code supporting insertion of pinned entries. * + * JRM -- 8/21/06 + * Added initialization for the new flush_in_progress and + * destroy_in_progress fields. + * *------------------------------------------------------------------------- */ @@ -4040,6 +4345,9 @@ H5C_insert_entry(H5F_t * f, entry_ptr->clear_on_unprotect = FALSE; #endif /* H5_HAVE_PARALLEL */ + entry_ptr->flush_in_progress = FALSE; + entry_ptr->destroy_in_progress = FALSE; + entry_ptr->ht_next = NULL; entry_ptr->ht_prev = NULL; @@ -4702,6 +5010,15 @@ done: * JRM -- 4/27/06 * Updated function to support renaming of pinned entries. * + * JRM -- 8/24/06 + * Updated function to refrain from alterning the index, the + * replacement policy data structures, and skip list when + * the function is called within the flush callback for the + * target entry and the target entry is being destroyed. + * + * Note that in this case H5C_flush_single_entry() will handle + * all these details for us. + * *------------------------------------------------------------------------- */ @@ -4715,6 +5032,9 @@ H5C_rename_entry(H5C_t * cache_ptr, hbool_t was_dirty; H5C_cache_entry_t * entry_ptr = NULL; H5C_cache_entry_t * test_entry_ptr = NULL; +#if H5C_DO_SANITY_CHECKS + hbool_t removed_entry_from_slist = FALSE; +#endif /* H5C_DO_SANITY_CHECKS */ FUNC_ENTER_NOAPI(H5C_rename_entry, FAIL) @@ -4733,7 +5053,6 @@ H5C_rename_entry(H5C_t * cache_ptr, } #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ - H5C__SEARCH_INDEX(cache_ptr, old_addr, entry_ptr, FAIL) if ( ( entry_ptr == NULL ) || ( entry_ptr->type != type ) ) { @@ -4768,7 +5087,7 @@ H5C_rename_entry(H5C_t * cache_ptr, } } - /* If we get this far, we have work to do. Remove *entry_ptr from + /* If we get this far we have work to do. Remove *entry_ptr from * the hash table (and skip list if necessary), change its address to the * new address, mark it as dirty (if it isn't already) and then re-insert. * @@ -4777,26 +5096,69 @@ H5C_rename_entry(H5C_t * cache_ptr, * * Note that we do not check the size of the cache, or evict anything. * Since this is a simple re-name, cache size should be unaffected. + * + * Check to see if the target entry is in the process of being destroyed + * before we delete from the index, etc. If it is, all we do is + * change the addr. If the entry is only in the process of being flushed, + * don't mark it as dirty either, lest we confuse the flush call back. */ - H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr) + if ( ! ( entry_ptr->destroy_in_progress ) ) { + + H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr) - if ( entry_ptr->in_slist ) { + if ( entry_ptr->in_slist ) { + + HDassert( cache_ptr->slist_ptr ); + + H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) + +#if H5C_DO_SANITY_CHECKS - HDassert( cache_ptr->slist_ptr ); + removed_entry_from_slist = TRUE; - H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) +#endif /* H5C_DO_SANITY_CHECKS */ + } } entry_ptr->addr = new_addr; - was_dirty = entry_ptr->is_dirty; - entry_ptr->is_dirty = TRUE; - H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL) + if ( ! ( entry_ptr->destroy_in_progress ) ) { + + was_dirty = entry_ptr->is_dirty; - H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) + if ( ! ( entry_ptr->flush_in_progress ) ) { - H5C__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, was_dirty, FAIL) + entry_ptr->is_dirty = TRUE; + } + + H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL) + + if ( ! ( entry_ptr->flush_in_progress ) ) { + + H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) + +#if H5C_DO_SANITY_CHECKS + + if ( removed_entry_from_slist ) { + + /* we just removed the entry from the slist. Thus we + * must touch up cache_ptr->slist_len_increase and + * cache_ptr->slist_size_increase to keep from skewing + * the sanity checks. + */ + HDassert( cache_ptr->slist_len_increase > 1 ); + HDassert( cache_ptr->slist_size_increase > entry_ptr->size ); + + cache_ptr->slist_len_increase -= 1; + cache_ptr->slist_size_increase -= entry_ptr->size; + } + +#endif /* H5C_DO_SANITY_CHECKS */ + + H5C__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, was_dirty, FAIL) + } + } H5C__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr) @@ -5773,6 +6135,9 @@ done: * JRM -- 8/9/06 * More code supporting pinned entry related stats. * + * JRM -- 8/23/06 + * Added code supporting new flush related statistics. + * *------------------------------------------------------------------------- */ @@ -5797,8 +6162,12 @@ H5C_stats(H5C_t * cache_ptr, int64_t total_flushes = 0; int64_t total_evictions = 0; int64_t total_renames = 0; + int64_t total_entry_flush_renames = 0; + int64_t total_cache_flush_renames = 0; int64_t total_size_increases = 0; int64_t total_size_decreases = 0; + int64_t total_entry_flush_size_changes = 0; + int64_t total_cache_flush_size_changes = 0; int64_t total_pins = 0; int64_t total_unpins = 0; int64_t total_dirty_pins = 0; @@ -5839,8 +6208,16 @@ H5C_stats(H5C_t * cache_ptr, total_flushes += cache_ptr->flushes[i]; total_evictions += cache_ptr->evictions[i]; total_renames += cache_ptr->renames[i]; + total_entry_flush_renames + += cache_ptr->entry_flush_renames[i]; + total_cache_flush_renames + += cache_ptr->cache_flush_renames[i]; total_size_increases += cache_ptr->size_increases[i]; total_size_decreases += cache_ptr->size_decreases[i]; + total_entry_flush_size_changes + += cache_ptr->entry_flush_size_changes[i]; + total_cache_flush_size_changes + += cache_ptr->cache_flush_size_changes[i]; total_pins += cache_ptr->pins[i]; total_unpins += cache_ptr->unpins[i]; total_dirty_pins += cache_ptr->dirty_pins[i]; @@ -5981,11 +6358,22 @@ H5C_stats(H5C_t * cache_ptr, (long)total_pinned_insertions, (long)total_renames); + HDfprintf(stdout, + "%s Total entry / cache flush renames = %ld / %ld\n", + cache_ptr->prefix, + (long)total_entry_flush_renames, + (long)total_cache_flush_renames); + HDfprintf(stdout, "%s Total entry size incrs / decrs = %ld / %ld\n", cache_ptr->prefix, (long)total_size_increases, (long)total_size_decreases); + HDfprintf(stdout, "%s Ttl entry/cache flush size changes = %ld / %ld\n", + cache_ptr->prefix, + (long)total_entry_flush_size_changes, + (long)total_cache_flush_size_changes); + HDfprintf(stdout, "%s Total entry pins (dirty) / unpins = %ld (%ld) / %ld\n", cache_ptr->prefix, @@ -6058,12 +6446,25 @@ H5C_stats(H5C_t * cache_ptr, (long)(cache_ptr->renames[i])); HDfprintf(stdout, + "%s entry / cache flush renames = %ld / %ld\n", + cache_ptr->prefix, + (long)(cache_ptr->entry_flush_renames[i]), + (long)(cache_ptr->cache_flush_renames[i])); + + HDfprintf(stdout, "%s size increases / decreases = %ld / %ld\n", cache_ptr->prefix, (long)(cache_ptr->size_increases[i]), (long)(cache_ptr->size_decreases[i])); HDfprintf(stdout, + "%s entry/cache flush size changes = %ld / %ld\n", + cache_ptr->prefix, + (long)(cache_ptr->entry_flush_size_changes[i]), + (long)(cache_ptr->cache_flush_size_changes[i])); + + + HDfprintf(stdout, "%s entry pins / unpins = %ld / %ld\n", cache_ptr->prefix, (long)(cache_ptr->pins[i]), @@ -6135,6 +6536,9 @@ done: * JRM - 8/9/06 * Further updates for pin related statistics. * + * JRM 8/23/08 + * Added initialization code for new flush related statistics. + * *------------------------------------------------------------------------- */ @@ -6159,6 +6563,8 @@ H5C_stats__reset(H5C_t * cache_ptr) cache_ptr->flushes[i] = 0; cache_ptr->evictions[i] = 0; cache_ptr->renames[i] = 0; + cache_ptr->entry_flush_renames[i] = 0; + cache_ptr->cache_flush_renames[i] = 0; cache_ptr->pins[i] = 0; cache_ptr->unpins[i] = 0; cache_ptr->dirty_pins[i] = 0; @@ -6166,6 +6572,8 @@ H5C_stats__reset(H5C_t * cache_ptr) cache_ptr->pinned_clears[i] = 0; cache_ptr->size_increases[i] = 0; cache_ptr->size_decreases[i] = 0; + cache_ptr->entry_flush_size_changes[i] = 0; + cache_ptr->cache_flush_size_changes[i] = 0; } cache_ptr->total_ht_insertions = 0; @@ -7971,7 +8379,11 @@ done: * * Modifications: * - * None. + * 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 * *------------------------------------------------------------------------- */ @@ -7984,6 +8396,7 @@ H5C_flush_invalidate_cache(H5F_t * f, { herr_t status; herr_t ret_value = SUCCEED; + hbool_t done = FALSE; hbool_t first_flush = TRUE; hbool_t first_pass = TRUE; hbool_t have_pinned_entries; @@ -7991,13 +8404,14 @@ H5C_flush_invalidate_cache(H5F_t * f, int32_t i; int32_t cur_pel_len; int32_t old_pel_len; + int32_t passes = 0; unsigned cooked_flags; H5SL_node_t * node_ptr = NULL; H5C_cache_entry_t * entry_ptr = NULL; H5C_cache_entry_t * next_entry_ptr = NULL; #if H5C_DO_SANITY_CHECKS - int32_t actual_slist_len = 0; - int32_t initial_slist_len = 0; + int64_t actual_slist_len = 0; + int64_t initial_slist_len = 0; size_t actual_slist_size = 0; size_t initial_slist_size = 0; #endif /* H5C_DO_SANITY_CHECKS */ @@ -8026,15 +8440,51 @@ H5C_flush_invalidate_cache(H5F_t * f, } } + /* The flush proceedure 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 + * unpin themselves, or until the number of pinned entries stops + * declining. In this later case, we scream and die. + * + * Since the fractal heap can dirty, resize, and/or rename entries + * in is flush callback, it is possible that the cache will still + * contain dirty entries at this point. If so, we must make up to + * H5C__MAX_PASSES_ON_FLUSH more passes through the skip list + * to allow it to empty. If is is not empty at this point, we again + * scream and die. + * + * Further, since clean entries can be dirtied, resized, and/or renamed + * as the result of a flush call back (either the entries own, or that + * for some other cache entry), we can no longer promise to flush + * the cache entries in increasing address order. + * + * Instead, we just do the best we can -- making a pass through + * the skip list, and then a pass through the "clean" entries, and + * then repeating as needed. Thus it is quite possible that an + * entry will be evicted from the cache only to be re-loaded later + * in the flush process (From what Quincey tells me, the pin + * mechanism makes this impossible, but even it it is true now, + * we shouldn't count on it in the future.) + * + * The bottom line is that entries will probably be flushed in close + * to increasing address order, but there are no guarantees. + */ + cur_pel_len = cache_ptr->pel_len; old_pel_len = cache_ptr->pel_len; - while ( ( first_pass ) || - ( ( cur_pel_len < old_pel_len ) && ( protected_entries == 0 ) ) ) + while ( ! done ) { + first_pass = FALSE; + have_pinned_entries = ( cur_pel_len > 0 ); - /* first, try to flush-destroy any dirty entries */ + /* 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 + * that the slist will not be empty after we finish the scan. + */ if ( cache_ptr->slist_len == 0 ) { @@ -8045,18 +8495,36 @@ H5C_flush_invalidate_cache(H5F_t * f, node_ptr = H5SL_first(cache_ptr->slist_ptr); + } #if H5C_DO_SANITY_CHECKS - /* Depending on circumstances, H5C_flush_single_entry() will - * remove dirty entries from the slist as it flushes them. - * Thus for sanity checks we must make note of the initial - * slist length and size before we do any flushes. - */ - initial_slist_len = cache_ptr->slist_len; - initial_slist_size = cache_ptr->slist_size; + /* Depending on circumstances, H5C_flush_single_entry() will + * remove dirty entries from the slist as it flushes them. + * Thus for sanity checks we must make note of the initial + * slist length and size before we do any flushes. + */ + initial_slist_len = cache_ptr->slist_len; + initial_slist_size = cache_ptr->slist_size; + + /* There is also the possibility that entries will be + * dirtied, resized, and/or renamed 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 + * the pass through the slist. + */ + cache_ptr->slist_len_increase = 0; + cache_ptr->slist_size_increase = 0; + + /* Finally, reset the actual_slist_len and actual_slist_size + * fields to zero, as these fields are used to accumulate + * the slist lenght and size that we see as we scan through + * the slist. + */ + actual_slist_len = 0; + actual_slist_size = 0; #endif /* H5C_DO_SANITY_CHECKS */ - } - while ( node_ptr != NULL ) { /* Note that we now remove nodes from the slist as we flush @@ -8064,14 +8532,10 @@ H5C_flush_invalidate_cache(H5F_t * f, * until we are done, and then destroying all nodes in * the slist. * - * While this optimization is still easy if everything works, - * the addition of pinned entries and multiple passes - * through the cache to allow entries to unpin themselves - * complicates error recover greatly. - * - * Given these complications, I've decided to ommit this - * this optimization for now. It can be re-implemented - * later if needed. + * While this optimization used to be easy, with the possibility + * of new entries being added to the slist in the midst of the + * flush, we must keep the slist in cannonical form at all + * times. */ entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); @@ -8085,6 +8549,16 @@ H5C_flush_invalidate_cache(H5F_t * f, HDassert( entry_ptr->in_slist ); #if H5C_DO_SANITY_CHECKS + /* update actual_slist_len & actual_slist_size before + * the flush. Note that the entry will be removed + * from the slist after the flush, and thus may be + * resized by the flush callback. This is OK, as + * we will catch the size delta in + * cache_ptr->slist_size_increase. + * + * Note that we include pinned entries in this count, even + * though we will not actually flush them. + */ actual_slist_len++; actual_slist_size += entry_ptr->size; #endif /* H5C_DO_SANITY_CHECKS */ @@ -8103,8 +8577,11 @@ H5C_flush_invalidate_cache(H5F_t * f, * H5C_flush_single_entry() to destroy the entry * as pinned entries can't be evicted. */ - if ( TRUE ) { /* insert test here */ /* JRM */ - + if ( TRUE ) { /* When we get to multithreaded cache, + * we will need either locking code, and/or + * a test to see if the entry is in flushable + * condition here. + */ status = H5C_flush_single_entry(f, primary_dxpl_id, @@ -8114,12 +8591,13 @@ H5C_flush_invalidate_cache(H5F_t * f, entry_ptr->addr, H5C__NO_FLAGS_SET, &first_flush, - TRUE); + FALSE); if ( status < 0 ) { /* This shouldn't happen -- if it does, we are toast * so just scream and die. */ + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ "dirty pinned entry flush failed.") } @@ -8141,6 +8619,7 @@ H5C_flush_invalidate_cache(H5F_t * f, /* This shouldn't happen -- if it does, we are toast so * just scream and die. */ + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ "dirty entry flush destroy failed.") } @@ -8148,14 +8627,27 @@ H5C_flush_invalidate_cache(H5F_t * f, } /* end while loop scanning skip list */ #if H5C_DO_SANITY_CHECKS - HDassert( actual_slist_len == initial_slist_len ); - HDassert( actual_slist_size == initial_slist_size ); + /* It is possible that entries were added to the slist during + * the scan, either before or after scan pointer. The following + * asserts take this into account. + */ + + HDassert( (actual_slist_len + cache_ptr->slist_len) == + (initial_slist_len + cache_ptr->slist_len_increase) ); + HDassert( (actual_slist_size + cache_ptr->slist_size) == + (initial_slist_size + cache_ptr->slist_size_increase) ); #endif /* H5C_DO_SANITY_CHECKS */ /* Since we are doing a destroy, we must make a pass through * the hash table and try to flush - destroy all entries that - * remain. Note that all remaining entries entries must be - * clean, so this will not result in any writes to disk. + * remain. + * + * It used to be that all entries remaining in the cache at + * this point had to be clean, but with the fractal heap mods + * this may not be the case. If so, we will flush entries out + * of increasing address order. + * + * Writes to disk are possible here. */ for ( i = 0; i < H5C__HASH_TABLE_LEN; i++ ) { @@ -8171,17 +8663,14 @@ H5C_flush_invalidate_cache(H5F_t * f, /* we have major problems -- but lets flush and destroy * everything we can before we flag an error. */ + protected_entries++; if ( ! entry_ptr->in_slist ) { - protected_entries++; HDassert( !(entry_ptr->is_dirty) ); } } else if ( ! ( entry_ptr->is_pinned ) ) { - HDassert( !(entry_ptr->is_dirty) ); - HDassert( !(entry_ptr->in_slist) ); - status = H5C_flush_single_entry(f, primary_dxpl_id, secondary_dxpl_id, @@ -8197,8 +8686,9 @@ H5C_flush_invalidate_cache(H5F_t * f, /* This shouldn't happen -- if it does, we are toast so * just scream and die. */ + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ - "Clean entry flush destroy failed.") + "Entry flush destroy failed.") } } /* We can't do anything if the entry is pinned. The @@ -8212,15 +8702,50 @@ H5C_flush_invalidate_cache(H5F_t * f, } /* end while loop scanning hash table bin */ } /* end for loop scanning hash table */ - HDassert( protected_entries == cache_ptr->pl_len ); - old_pel_len = cur_pel_len; cur_pel_len = cache_ptr->pel_len; - first_pass = FALSE; + if ( ( cur_pel_len > 0 ) && ( cur_pel_len >= old_pel_len ) ) { + + /* The number of pinned entries is positive, and it is not + * declining. Scream and die. + */ + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Can't unpin all pinned entries 1.") + + } else if ( ( cur_pel_len == 0 ) && ( old_pel_len == 0 ) ) { + + /* increment the pass count */ + passes++; + } + + if ( passes >= H5C__MAX_PASSES_ON_FLUSH ) { + + /* we have exceeded the maximum number of passes through the + * cache to flush and destroy all entries. Scream and die. + */ + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Maximum passes on flush exceeded.") + } + if ( cache_ptr->index_len <= 0 ) { + + done = TRUE; + HDassert( cache_ptr->index_size == 0 ); + HDassert( cache_ptr->slist_len == 0 ); + HDassert( cache_ptr->slist_size == 0 ); + HDassert( cache_ptr->pel_len == 0 ); + HDassert( cache_ptr->pel_size == 0 ); + HDassert( cache_ptr->pl_len == 0 ); + HDassert( cache_ptr->pl_size == 0 ); + HDassert( cache_ptr->LRU_list_len == 0 ); + HDassert( cache_ptr->LRU_list_size == 0 ); + } } /* main while loop */ + HDassert( protected_entries <= cache_ptr->pl_len ); if ( protected_entries > 0 ) { @@ -8231,7 +8756,7 @@ H5C_flush_invalidate_cache(H5F_t * f, } else if ( cur_pel_len > 0 ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ - "Can't unpin all pinned entries.") + "Can't unpin all pinned entries 2.") } @@ -8313,6 +8838,17 @@ done: * 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. + * *------------------------------------------------------------------------- */ static herr_t @@ -8332,10 +8868,12 @@ H5C_flush_single_entry(H5F_t * f, herr_t ret_value = SUCCEED; /* Return value */ herr_t status; int type_id; + unsigned flush_flags = H5C_CALLBACK__NO_FLAGS_SET; H5C_cache_entry_t * entry_ptr = NULL; FUNC_ENTER_NOAPI_NOINIT(H5C_flush_single_entry) + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); HDassert( cache_ptr->skip_file_checks || f ); @@ -8351,6 +8889,8 @@ H5C_flush_single_entry(H5F_t * f, #if H5C_DO_SANITY_CHECKS if ( entry_ptr != NULL ) { + HDassert( ! ( ( destroy ) && ( entry_ptr->is_pinned ) ) ); + if ( entry_ptr->in_slist ) { if ( ( ( entry_ptr->flush_marker ) && ( ! entry_ptr->is_dirty ) ) || @@ -8396,6 +8936,11 @@ H5C_flush_single_entry(H5F_t * f, { /* we have work to do */ + /* We will set flush_in_progress back to FALSE at the end if the + * entry still exists at that point. + */ + entry_ptr->flush_in_progress = TRUE; + #ifdef H5_HAVE_PARALLEL #ifndef NDEBUG @@ -8456,13 +9001,21 @@ H5C_flush_single_entry(H5F_t * f, /* Always remove the entry from the hash table on a destroy. On a * flush with destroy, it is cheaper to discard the skip list all at * once rather than remove the entries one by one, so we only delete - * from the list if requested. + * from the slist only if requested. * * We must do deletions now as the callback routines will free the * entry if destroy is true. + * + * Note that it is possible that the entry will be renamed during + * its call to flush. This will upset H5C_rename_entry() if we + * don't tell it that it doesn't have to worry about updating the + * index and SLIST. Use the destroy_in_progress field for this + * purpose. */ if ( destroy ) { + entry_ptr->destroy_in_progress = TRUE; + H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr) if ( ( entry_ptr->in_slist ) && @@ -8606,14 +9159,15 @@ H5C_flush_single_entry(H5F_t * f, if ( *first_flush_ptr && entry_ptr->is_dirty ) { status = (entry_ptr->type->flush)(f, primary_dxpl_id, destroy, - entry_ptr->addr, entry_ptr); + entry_ptr->addr, entry_ptr, + &flush_flags); *first_flush_ptr = FALSE; } else { status = (entry_ptr->type->flush)(f, secondary_dxpl_id, destroy, entry_ptr->addr, - entry_ptr); + entry_ptr, &flush_flags); } if ( status < 0 ) { @@ -8621,6 +9175,43 @@ H5C_flush_single_entry(H5F_t * f, HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ "unable to flush entry") } +#ifdef H5_HAVE_PARALLEL + if ( flush_flags != H5C_CALLBACK__NO_FLAGS_SET ) { + + /* In the parallel case, flush operations can + * cause problems. If they occur, scream and + * die. + * + * At present, in the parallel case, the aux_ptr + * will only be set if there is more than one + * process. Thus we can use this to detect + * the parallel case. + * + * This works for now, but if we start using the + * aux_ptr for other purposes, we will have to + * change this test accordingly. + * + * NB: While this test detects entryies that attempt + * to resize or rename themselves during a flush + * in the parallel case, it will not detect an + * entry that dirties, resizes, and/or renames + * other entries during its flush. + * + * From what Quincey tells me, this test is + * sufficient for now, as any flush routine that + * does the latter will also do the former. + * + * If that ceases to be the case, further + * tests will be necessary. + */ + if ( cache_ptr->aux_ptr != NULL ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Flush operation occured in the parallel case.") + + } + } +#endif /* H5_HAVE_PARALLEL */ } if ( ( ! destroy ) && ( entry_ptr->in_slist ) ) { @@ -8628,11 +9219,79 @@ H5C_flush_single_entry(H5F_t * f, H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) } - if ( ! destroy ) { + if ( ! destroy ) { /* i.e. if the entry still exists */ HDassert( !(entry_ptr->is_dirty) ); HDassert( !(entry_ptr->flush_marker) ); HDassert( !(entry_ptr->in_slist) ); + HDassert( !(entry_ptr->is_protected) ); + + if ( (flush_flags & H5C_CALLBACK__SIZE_CHANGED_FLAG) != 0 ) { + + /* The entry size changed as a result of the flush. + * + * Most likely, the entry was compressed, and the + * new version is of a different size than the old. + * + * In any case, we must update entry and cache size + * accordingly. + */ + size_t new_size; + + if ( (entry_ptr->type->size)(f, (void *)entry_ptr, &new_size) + < 0 ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGETSIZE, FAIL, \ + "Can't get entry size after flush") + } + + if ( new_size != entry_ptr->size ) { + + HDassert( entry_ptr->size < H5C_MAX_ENTRY_SIZE ); + + /* update the hash table for the size change*/ + H5C__UPDATE_INDEX_FOR_SIZE_CHANGE((cache_ptr), \ + (entry_ptr->size),\ + (new_size)); + + /* The entry can't be protected since we just flushed it. + * Thus we must update the replacement policy data + * structures for the size change. The macro deals + * with the pinned case. + */ + H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, \ + new_size) + + /* The entry can't be in the slist, so no need to update + * the slist for the size change. + */ + + /* update stats for the size change */ + H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, \ + entry_ptr, \ + new_size) + + /* finally, update the entry size proper */ + entry_ptr->size = new_size; + } + } + + if ( (flush_flags & H5C_CALLBACK__RENAMED_FLAG) != 0 ) { + + /* The entry was renamed as the result of the flush. + * + * Most likely, the entry was compressed, and the + * new version is larger than the old and thus had + * to be relocated. + * + * At preset, all processing for this case is + * handled elsewhere. But lets keep the if statement + * around just in case. + */ + + } + + entry_ptr->flush_in_progress = FALSE; } if ( cache_ptr->log_flush ) { @@ -8682,6 +9341,10 @@ done: * the case, as our code will attempt to repair errors * on load. * + * JRM - 8/21/06 + * Added initialization for the new flush_in_progress and + * destroy in progress fields. + * *------------------------------------------------------------------------- */ @@ -8695,7 +9358,7 @@ H5C_load_entry(H5F_t * f, #ifndef NDEBUG hbool_t skip_file_checks) #else /* NDEBUG */ - UNUSED hbool_t skip_file_checks) + hbool_t UNUSED skip_file_checks) #endif /* NDEBUG */ { void * thing = NULL; @@ -8751,6 +9414,8 @@ H5C_load_entry(H5F_t * f, #ifdef H5_HAVE_PARALLEL entry_ptr->clear_on_unprotect = FALSE; #endif /* H5_HAVE_PARALLEL */ + entry_ptr->flush_in_progress = FALSE; + entry_ptr->destroy_in_progress = FALSE; if ( (type->size)(f, thing, &(entry_ptr->size)) < 0 ) { diff --git a/src/H5Cpkg.h b/src/H5Cpkg.h index 7895315..4dd3547 100644 --- a/src/H5Cpkg.h +++ b/src/H5Cpkg.h @@ -42,6 +42,17 @@ /* Get needed headers */ #include "H5SLprivate.h" /* Skip lists */ +/* With the introduction of the fractal heap, it is now possible for + * entries to be dirtied, resized, and/or renamed in the flush callbacks. + * As a result, on flushes, it may be necessary to make multiple passes + * through the slist before it is empty. The H5C__MAX_PASSES_ON_FLUSH + * #define is used to set an upper limit on the number of passes. + * The current value was obtained via personal communication with + * Quincey. I have applied a fudge factor of 2. + */ + +#define H5C__MAX_PASSES_ON_FLUSH 4 + #define H5C__HASH_TABLE_LEN (64 * 1024) /* must be a power of 2 */ @@ -87,6 +98,9 @@ * magic: Unsigned 32 bit integer always set to H5C__H5C_T_MAGIC. This * field is used to validate pointers to instances of H5C_t. * + * flush_in_progress: Boolean flag indicating whether a flush is in + * progress. + * * trace_file_ptr: File pointer pointing to the trace file, which is used * to record cache operations for use in simulations and design * studies. This field will usually be NULL, indicating that @@ -222,6 +236,19 @@ * don't use this at present, I hope that this will allow * some optimizations when I get to it. * + * With the addition of the fractal heap, the cache must now deal with + * the case in which entries may be dirtied, renamed, or have their sizes + * changed during a flush. To allow sanity checks in this situation, the + * following two fields have been added. They are only compiled in when + * H5C_DO_SANITY_CHECKS is TRUE. + * + * slist_len_increase: Number of entries that have been added to the + * slist since the last time this field was set to zero. + * + * slist_size_increase: Total size of all entries that have been added + * to the slist since the last time this field was set to + * zero. + * * * When a cache entry is protected, it must be removed from the LRU * list(s) as it cannot be either flushed or evicted until it is unprotected. @@ -570,6 +597,16 @@ * id equal to the array index has been renamed in the current * epoch. * + * entry_flush_renames: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. + * The cells are used to record the number of times an entry + * with type id equal to the array index has been renamed + * during its flush callback in the current epoch. + * + * cache_flush_renames: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. + * The cells are used to record the number of times an entry + * with type id equal to the array index has been renamed + * during a cache flush in the current epoch. + * * pins: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells * are used to record the number of times an entry with type * id equal to the array index has been pinned in the current @@ -595,7 +632,6 @@ * with type id equal to the array index has been cleared while * pinned in the current epoch. * - * * size_increases: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. * The cells are used to record the number of times an entry * with type id equal to the array index has increased in @@ -606,6 +642,16 @@ * with type id equal to the array index has decreased in * size in the current epoch. * + * entry_flush_size_changes: Array of int64 of length + * H5C__MAX_NUM_TYPE_IDS + 1. The cells are used to record + * the number of times an entry with type id equal to the + * array index has changed size while in its flush callback. + * + * cache_flush_size_changes: Array of int64 of length + * H5C__MAX_NUM_TYPE_IDS + 1. The cells are used to record + * the number of times an entry with type id equal to the + * array index has changed size during a cache flush + * * total_ht_insertions: Number of times entries have been inserted into the * hash table in the current epoch. * @@ -719,6 +765,8 @@ struct H5C_t { uint32_t magic; + hbool_t flush_in_progress; + FILE * trace_file_ptr; void * aux_ptr; @@ -742,7 +790,10 @@ struct H5C_t int32_t slist_len; size_t slist_size; H5SL_t * slist_ptr; - +#if H5C_DO_SANITY_CHECKS + int64_t slist_len_increase; + int64_t slist_size_increase; +#endif /* H5C_DO_SANITY_CHECKS */ int32_t pl_len; size_t pl_size; @@ -798,6 +849,8 @@ struct H5C_t int64_t flushes[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t evictions[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t renames[H5C__MAX_NUM_TYPE_IDS + 1]; + int64_t entry_flush_renames[H5C__MAX_NUM_TYPE_IDS + 1]; + int64_t cache_flush_renames[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t pins[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t unpins[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t dirty_pins[H5C__MAX_NUM_TYPE_IDS + 1]; @@ -805,6 +858,10 @@ struct H5C_t int64_t pinned_clears[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t size_increases[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t size_decreases[H5C__MAX_NUM_TYPE_IDS + 1]; + int64_t entry_flush_size_changes + [H5C__MAX_NUM_TYPE_IDS + 1]; + int64_t cache_flush_size_changes + [H5C__MAX_NUM_TYPE_IDS + 1]; int64_t total_ht_insertions; int64_t total_ht_deletions; diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h index 63393ec..2c97853 100644 --- a/src/H5Cprivate.h +++ b/src/H5Cprivate.h @@ -60,7 +60,7 @@ */ #if H5C_COLLECT_CACHE_STATS -#define H5C_COLLECT_CACHE_ENTRY_STATS 0 +#define H5C_COLLECT_CACHE_ENTRY_STATS 1 #else @@ -116,6 +116,10 @@ typedef struct H5C_t H5C_t; * Note that the space allocated on disk may not be contiguous. */ +#define H5C_CALLBACK__NO_FLAGS_SET 0x0 +#define H5C_CALLBACK__SIZE_CHANGED_FLAG 0x1 +#define H5C_CALLBACK__RENAMED_FLAG 0x2 + typedef void *(*H5C_load_func_t)(H5F_t *f, hid_t dxpl_id, haddr_t addr, @@ -125,7 +129,8 @@ typedef herr_t (*H5C_flush_func_t)(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, - void *thing); + void *thing, + unsigned * flags_ptr); typedef herr_t (*H5C_dest_func_t)(H5F_t *f, void *thing); typedef herr_t (*H5C_clear_func_t)(H5F_t *f, @@ -312,6 +317,13 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t * cache_ptr, * the unprotect, the entry's is_dirty flag is reset by flushing * it with the H5C__FLUSH_CLEAR_ONLY_FLAG. * + * flush_in_progress: Boolean flag that is set to true iff the entry + * is in the process of being flushed. This allows the cache + * to detect when a call is the result of a flush callback. + * + * destroy_in_progress: Boolean flag that is set to true iff the entry + * is in the process of being flushed and destroyed. + * * * Fields supporting the hash table: * @@ -425,6 +437,8 @@ typedef struct H5C_cache_entry_t #ifdef H5_HAVE_PARALLEL hbool_t clear_on_unprotect; #endif /* H5_HAVE_PARALLEL */ + hbool_t flush_in_progress; + hbool_t destroy_in_progress; /* fields supporting the hash table: */ diff --git a/src/H5FScache.c b/src/H5FScache.c index fdf54e8..73341f2 100644 --- a/src/H5FScache.c +++ b/src/H5FScache.c @@ -75,11 +75,11 @@ static herr_t H5FS_sinfo_serialize_node_cb(void *_item, void UNUSED *key, void * /* Metadata cache callbacks */ static H5FS_t *H5FS_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata, void *udata2); -static herr_t H5FS_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_t *fspace); +static herr_t H5FS_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_t *fspace, unsigned UNUSED * flags_ptr); static herr_t H5FS_cache_hdr_clear(H5F_t *f, H5FS_t *fspace, hbool_t destroy); static herr_t H5FS_cache_hdr_size(const H5F_t *f, const H5FS_t *fspace, size_t *size_ptr); static H5FS_sinfo_t *H5FS_cache_sinfo_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata, void *udata2); -static herr_t H5FS_cache_sinfo_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_sinfo_t *sinfo); +static herr_t H5FS_cache_sinfo_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_sinfo_t *sinfo, unsigned UNUSED * flags_ptr); static herr_t H5FS_cache_sinfo_clear(H5F_t *f, H5FS_sinfo_t *sinfo, hbool_t destroy); static herr_t H5FS_cache_sinfo_size(const H5F_t *f, const H5FS_sinfo_t *sinfo, size_t *size_ptr); @@ -271,10 +271,17 @@ done: * koziol@ncsa.uiuc.edu * May 2 2006 * + * Changes: JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. + * + * *------------------------------------------------------------------------- */ static herr_t -H5FS_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_t *fspace) +H5FS_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_t *fspace, unsigned UNUSED * flags_ptr) { herr_t ret_value = SUCCEED; /* Return value */ @@ -823,10 +830,15 @@ done: * koziol@ncsa.uiuc.edu * July 31 2006 * + * Changes: JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. *------------------------------------------------------------------------- */ static herr_t -H5FS_cache_sinfo_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_sinfo_t *sinfo) +H5FS_cache_sinfo_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_sinfo_t *sinfo, unsigned UNUSED * flags_ptr) { herr_t ret_value = SUCCEED; /* Return value */ diff --git a/src/H5Gnode.c b/src/H5Gnode.c index cbbfeae..8d534a8 100644 --- a/src/H5Gnode.c +++ b/src/H5Gnode.c @@ -75,7 +75,7 @@ static herr_t H5G_node_shared_free(void *shared); static H5G_node_t *H5G_node_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_udata1, void *_udata2); static herr_t H5G_node_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5G_node_t *sym); + H5G_node_t *sym, unsigned UNUSED * flags_ptr); static herr_t H5G_node_dest(H5F_t *f, H5G_node_t *sym); static herr_t H5G_node_clear(H5F_t *f, H5G_node_t *sym, hbool_t destroy); static herr_t H5G_compute_size(const H5F_t *f, const H5G_node_t *sym, size_t *size_ptr); @@ -446,10 +446,16 @@ done: * Pedro Vicente, 18 Sep 2002 * Added `id to name' support. * + * JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. + * *------------------------------------------------------------------------- */ static herr_t -H5G_node_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5G_node_t *sym) +H5G_node_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5G_node_t *sym, unsigned UNUSED * flags_ptr) { uint8_t *buf = NULL; size_t size; diff --git a/src/H5HFcache.c b/src/H5HFcache.c index c1df3c7..41e79e6 100644 --- a/src/H5HFcache.c +++ b/src/H5HFcache.c @@ -68,15 +68,15 @@ static herr_t H5HF_dtable_decode(H5F_t *f, const uint8_t **pp, H5HF_dtable_t *dt /* Metadata cache (H5AC) callbacks */ static H5HF_hdr_t *H5HF_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata, void *udata2); -static herr_t H5HF_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_hdr_t *hdr); +static herr_t H5HF_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_hdr_t *hdr, unsigned UNUSED * flags_ptr); static herr_t H5HF_cache_hdr_clear(H5F_t *f, H5HF_hdr_t *hdr, hbool_t destroy); static herr_t H5HF_cache_hdr_size(const H5F_t *f, const H5HF_hdr_t *hdr, size_t *size_ptr); static H5HF_indirect_t *H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata, void *udata2); -static herr_t H5HF_cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_indirect_t *iblock); +static herr_t H5HF_cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_indirect_t *iblock, unsigned UNUSED * flags_ptr); static herr_t H5HF_cache_iblock_clear(H5F_t *f, H5HF_indirect_t *iblock, hbool_t destroy); static herr_t H5HF_cache_iblock_size(const H5F_t *f, const H5HF_indirect_t *iblock, size_t *size_ptr); static H5HF_direct_t *H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata, void *udata2); -static herr_t H5HF_cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_direct_t *dblock); +static herr_t H5HF_cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_direct_t *dblock, unsigned UNUSED * flags_ptr); static herr_t H5HF_cache_dblock_clear(H5F_t *f, H5HF_direct_t *dblock, hbool_t destroy); static herr_t H5HF_cache_dblock_size(const H5F_t *f, const H5HF_direct_t *dblock, size_t *size_ptr); @@ -432,11 +432,16 @@ done: * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Feb 24 2006 + * Changes: JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. * *------------------------------------------------------------------------- */ static herr_t -H5HF_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_hdr_t *hdr) +H5HF_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_hdr_t *hdr, unsigned UNUSED * flags_ptr) { herr_t ret_value = SUCCEED; /* Return value */ @@ -878,10 +883,16 @@ done: * koziol@ncsa.uiuc.edu * Mar 6 2006 * + * Changes: JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. + * *------------------------------------------------------------------------- */ static herr_t -H5HF_cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_indirect_t *iblock) +H5HF_cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_indirect_t *iblock, unsigned UNUSED * flags_ptr) { herr_t ret_value = SUCCEED; /* Return value */ @@ -1282,10 +1293,16 @@ done: * koziol@ncsa.uiuc.edu * Feb 27 2006 * + * Changes: JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. + * *------------------------------------------------------------------------- */ static herr_t -H5HF_cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_direct_t *dblock) +H5HF_cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_direct_t *dblock, unsigned UNUSED * flags_ptr) { herr_t ret_value = SUCCEED; /* Return value */ diff --git a/src/H5HG.c b/src/H5HG.c index cc88a04..b15077f 100644 --- a/src/H5HG.c +++ b/src/H5HG.c @@ -126,7 +126,7 @@ static void *H5HG_peek(H5F_t *f, hid_t dxpl_id, H5HG_t *hobj); static H5HG_heap_t *H5HG_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata1, void *udata2); static herr_t H5HG_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, - H5HG_heap_t *heap); + H5HG_heap_t *heap, unsigned UNUSED * flags_ptr); static herr_t H5HG_dest(H5F_t *f, H5HG_heap_t *heap); static herr_t H5HG_clear(H5F_t *f, H5HG_heap_t *heap, hbool_t destroy); static herr_t H5HG_compute_size(const H5F_t *f, const H5HG_heap_t *heap, size_t *size_ptr); @@ -506,10 +506,17 @@ done: * Quincey Koziol, 2002-7-180 * Added dxpl parameter to allow more control over I/O from metadata * cache. + * + * JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. + * *------------------------------------------------------------------------- */ static herr_t -H5HG_flush (H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HG_heap_t *heap) +H5HG_flush (H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HG_heap_t *heap, unsigned UNUSED * flags_ptr) { herr_t ret_value=SUCCEED; /* Return value */ diff --git a/src/H5HL.c b/src/H5HL.c index add2b77..c2cfc01 100644 --- a/src/H5HL.c +++ b/src/H5HL.c @@ -66,7 +66,7 @@ static herr_t H5HL_minimize_heap_space(H5F_t *f, hid_t dxpl_id, H5HL_t *heap); /* Metadata cache callbacks */ static H5HL_t *H5HL_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata1, void *udata2); -static herr_t H5HL_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, H5HL_t *heap); +static herr_t H5HL_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, H5HL_t *heap, unsigned UNUSED * flags_ptr); static herr_t H5HL_dest(H5F_t *f, H5HL_t *heap); static herr_t H5HL_clear(H5F_t *f, H5HL_t *heap, hbool_t destroy); static herr_t H5HL_compute_size(const H5F_t *f, const H5HL_t *heap, size_t *size_ptr); @@ -550,10 +550,16 @@ H5HL_serialize(H5F_t *f, H5HL_t *heap, uint8_t *buf) * Instead, disk space allocation/deallocation is now done at * insert/remove time. * + * John Mainzer, 2006-08-21 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. + * *------------------------------------------------------------------------- */ static herr_t -H5HL_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HL_t *heap) +H5HL_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HL_t *heap, unsigned UNUSED * flags_ptr) { herr_t ret_value = SUCCEED; /* Return value */ diff --git a/src/H5Ocache.c b/src/H5Ocache.c index d0f479d..1ac9550 100644 --- a/src/H5Ocache.c +++ b/src/H5Ocache.c @@ -63,7 +63,7 @@ /* Metadata cache callbacks */ static H5O_t *H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_udata1, void *_udata2); -static herr_t H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5O_t *oh); +static herr_t H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5O_t *oh, unsigned UNUSED * flags_ptr); static herr_t H5O_clear(H5F_t *f, H5O_t *oh, hbool_t destroy); static herr_t H5O_size(const H5F_t *f, const H5O_t *oh, size_t *size_ptr); @@ -518,10 +518,16 @@ done: * matzke@llnl.gov * Aug 5 1997 * + * Changes: JRM -- 8/21/06 + * Added the flags_ptr parameter. This parameter exists to + * allow the flush routine to report to the cache if the + * entry is resized or renamed as a result of the flush. + * *flags_ptr is set to H5C_CALLBACK__NO_FLAGS_SET on entry. + * *------------------------------------------------------------------------- */ static herr_t -H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t UNUSED addr, H5O_t *oh) +H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t UNUSED addr, H5O_t *oh, unsigned UNUSED * flags_ptr) { herr_t ret_value = SUCCEED; /* Return value */ diff --git a/test/cache.c b/test/cache.c index 440b5e3..ac9d198 100644 --- a/test/cache.c +++ b/test/cache.c @@ -75,6 +75,19 @@ static void check_flush_cache__pinned_single_entry_test(H5C_t * cache_ptr, hbool_t expected_cleared, hbool_t expected_flushed, hbool_t expected_destroyed); +static void check_flush_cache__flush_ops(H5C_t * cache_ptr); +static void check_flush_cache__flush_op_test(H5C_t * cache_ptr, + int test_num, + unsigned int flush_flags, + int spec_size, + struct fo_flush_cache_test_spec spec[], + int init_expected_index_len, + size_t init_expected_index_size, + int expected_index_len, + size_t expected_index_size, + int check_size, + struct fo_flush_entry_check check[]); +static void check_flush_cache__flush_op_eviction_test(H5C_t * cache_ptr); static void check_flush_protected_err(void); static void check_get_entry_status(void); static void check_expunge_entry(void); @@ -2366,6 +2379,11 @@ check_flush_cache(void) if ( pass ) { + check_flush_cache__flush_ops(cache_ptr); + } + + if ( pass ) { + takedown_cache(cache_ptr, FALSE, FALSE); } @@ -4280,6 +4298,13 @@ check_flush_cache__multi_entry_test(H5C_t * cache_ptr, test_entry_t * base_addr; test_entry_t * entry_ptr; +#if 0 /* JRM */ + /* This gets used a lot, so lets leave it in. */ + + HDfprintf(stdout, "check_flush_cache__multi_entry_test: test %d\n", + test_num); +#endif /* JRM */ + if ( cache_ptr == NULL ) { pass = FALSE; @@ -4430,270 +4455,5663 @@ check_flush_cache__multi_entry_test(H5C_t * cache_ptr, if ( result < 0 ) { - pass = FALSE; - HDsnprintf(msg, (size_t)128, - "Flush failed on cleanup in multi entry test #%d.", - test_num); - failure_mssg = msg; - } - else if ( ( cache_ptr->index_len != 0 ) || - ( cache_ptr->index_size != 0 ) ) { + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Flush failed on cleanup in multi entry test #%d.", + test_num); + failure_mssg = msg; + } + else if ( ( cache_ptr->index_len != 0 ) || + ( cache_ptr->index_size != 0 ) ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Unexpected cache len/size after cleanup in multi entry test #%d.", + test_num); + failure_mssg = msg; + + } + } + + i = 0; + while ( ( pass ) && ( i < spec_size ) ) + { + base_addr = entries[spec[i].entry_type]; + entry_ptr = &(base_addr[spec[i].entry_index]); + + entry_ptr->loaded = FALSE; + entry_ptr->cleared = FALSE; + entry_ptr->flushed = FALSE; + entry_ptr->destroyed = FALSE; + + i++; + } + + return; + +} /* check_flush_cache__multi_entry_test() */ + + +/*------------------------------------------------------------------------- + * Function: check_flush_cache__pe_multi_entry_test() + * + * Purpose: Run a multi entry flush cache test. + * + * Return: void + * + * Programmer: John Mainzer + * 4/5/06 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +static void +check_flush_cache__pe_multi_entry_test(H5C_t * cache_ptr, + int test_num, + unsigned int flush_flags, + int spec_size, + struct pe_flush_cache_test_spec spec[]) +{ + /* const char * fcn_name = "check_flush_cache__pe_multi_entry_test"; */ + static char msg[128]; + herr_t result; + int i; + int j; + size_t total_entry_size = 0; + test_entry_t * base_addr; + test_entry_t * entry_ptr; + +#if 0 /* JRM */ + /* This is useful debugging code. Leave it in for now. */ + + HDfprintf(stdout, "check_flush_cache__pe_multi_entry_test: test %d\n", + test_num); +#endif /* JRM */ + + if ( cache_ptr == NULL ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "cache_ptr NULL on entry to pe multi entry test #%d.", + test_num); + failure_mssg = msg; + } + else if ( ( cache_ptr->index_len != 0 ) || + ( cache_ptr->index_size != 0 ) ) { + + pass = FALSE; + + HDsnprintf(msg, (size_t)128, + "cache not empty at beginning of pe multi entry test #%d.", + test_num); + failure_mssg = msg; + } + else if ( ( spec_size < 1 ) || ( spec == NULL ) ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "missing/bad test spec on entry to pe multi entry test #%d.", + test_num); + failure_mssg = msg; + } + + i = 0; + while ( ( pass ) && ( i < spec_size ) ) + { + if ( ( spec[i].entry_num != i ) || + ( spec[i].entry_type < 0 ) || + ( spec[i].entry_type >= NUMBER_OF_ENTRY_TYPES ) || + ( spec[i].entry_index < 0 ) || + ( spec[i].entry_index > max_indices[spec[i].entry_type] ) || + ( spec[i].num_pins < 0 ) || + ( spec[i].num_pins > MAX_PINS ) ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "bad data in spec[%d] on entry to pe multi entry test #%d.", + i, test_num); + failure_mssg = msg; + } + i++; + } + + i = 0; + while ( ( pass ) && ( i < spec_size ) ) + { + if ( spec[i].insert_flag ) { + + insert_entry(cache_ptr, spec[i].entry_type, spec[i].entry_index, + spec[i].dirty_flag, spec[i].flags); + + } else { + + protect_entry(cache_ptr, spec[i].entry_type, spec[i].entry_index); + + unprotect_entry(cache_ptr, spec[i].entry_type, spec[i].entry_index, + (int)(spec[i].dirty_flag), spec[i].flags); + } + + total_entry_size += entry_sizes[spec[i].entry_type]; + + for ( j = 0; j < spec[i].num_pins; j++ ) + { + create_pinned_entry_dependency(cache_ptr, + spec[i].entry_type, + spec[i].entry_index, + spec[i].pin_type[j], + spec[i].pin_idx[j]); + } + + i++; + } + + if ( pass ) { + + result = H5C_flush_cache(NULL, -1, -1, cache_ptr, flush_flags); + + if ( result < 0 ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "flush with flags 0x%x failed in pe multi entry test #%d.", + flush_flags, test_num); + failure_mssg = msg; + } + } + + i = 0; + while ( ( pass ) && ( i < spec_size ) ) + { + base_addr = entries[spec[i].entry_type]; + entry_ptr = &(base_addr[spec[i].entry_index]); + + if ( ( entry_ptr->loaded != spec[i].expected_loaded ) || + ( entry_ptr->cleared != spec[i].expected_cleared ) || + ( entry_ptr->flushed != spec[i].expected_flushed ) || + ( entry_ptr->destroyed != spec[i].expected_destroyed ) ) { + +#if 0 /* This is useful debugging code. Lets keep it around. */ + + HDfprintf(stdout, + "loaded = %d(%d), clrd = %d(%d), flshd = %d(%d), dest = %d(%d)\n", + (int)(entry_ptr->loaded), + (int)(spec[i].expected_loaded), + (int)(entry_ptr->cleared), + (int)(spec[i].expected_cleared), + (int)(entry_ptr->flushed), + (int)(spec[i].expected_flushed), + (int)(entry_ptr->destroyed), + (int)(spec[i].expected_destroyed)); + +#endif + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Bad status on entry %d after flush in pe multi entry test #%d.", + i, test_num); + failure_mssg = msg; + } + i++; + } + + if ( pass ) { + + if ( ( ( (flush_flags & H5C__FLUSH_INVALIDATE_FLAG) == 0 ) + && + ( ( cache_ptr->index_len != spec_size ) + || + ( cache_ptr->index_size != total_entry_size ) + ) + ) + || + ( ( (flush_flags & H5C__FLUSH_INVALIDATE_FLAG) != 0 ) + && + ( ( cache_ptr->index_len != 0 ) + || + ( cache_ptr->index_size != 0 ) + ) + ) + ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Unexpected cache len/size after flush in pe multi entry test #%d.", + test_num); + failure_mssg = msg; + } + } + + /* clean up the cache to prep for the next test */ + if ( pass ) { + + result = H5C_flush_cache(NULL, -1, -1, cache_ptr, + H5C__FLUSH_INVALIDATE_FLAG); + + if ( result < 0 ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Flush failed on cleanup in pe multi entry test #%d.", + test_num); + failure_mssg = msg; + } + else if ( ( cache_ptr->index_len != 0 ) || + ( cache_ptr->index_size != 0 ) ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Unexpected cache len/size after cleanup in pe multi entry test #%d.", + test_num); + failure_mssg = msg; + + } + } + + i = 0; + while ( ( pass ) && ( i < spec_size ) ) + { + base_addr = entries[spec[i].entry_type]; + entry_ptr = &(base_addr[spec[i].entry_index]); + + entry_ptr->loaded = FALSE; + entry_ptr->cleared = FALSE; + entry_ptr->flushed = FALSE; + entry_ptr->destroyed = FALSE; + + i++; + } + + return; + +} /* check_flush_cache__pe_multi_entry_test() */ + + +/*------------------------------------------------------------------------- + * Function: check_flush_cache__flush_ops() + * + * Purpose: Run the flush ops cache tests. + * + * These are tests that test the cache's ability to handle + * the case in which the flush callback dirties, resizes, + * and/or renames entries. + * + * Do nothing if pass is FALSE on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 9/3/06 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +static void +check_flush_cache__flush_ops(H5C_t * cache_ptr) +{ + /* const char * fcn_name = "check_flush_cache__flush_ops"; */ + + if ( cache_ptr == NULL ) { + + pass = FALSE; + failure_mssg = "cache_ptr NULL on entry to flush ops test."; + } + else if ( ( cache_ptr->index_len != 0 ) || + ( cache_ptr->index_size != 0 ) ) { + + pass = FALSE; + failure_mssg = "cache not empty at beginning of flush ops test."; + } + + if ( pass ) /* test #1 */ + { + /* start with a very simple test, in which there are two entries + * resident in cache, and the second entry dirties the first in + * the flush callback. No size changes, and no flush flags. + */ + int test_num = 1; + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 2; + int init_expected_index_len = 2; + size_t init_expected_index_size = 2 * PICO_ENTRY_SIZE; + int expected_index_len = 2; + size_t expected_index_size = 2 * PICO_ENTRY_SIZE; + struct fo_flush_cache_test_spec spec[2] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ 0, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ (size_t)0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + + if ( pass ) /* test #2 */ + { + /* Same as test 1, only this time set the flush invalidate flag. + * Note that we must repeat all tests with the flush invalidate flag + * as this triggers a different set of code to execute the flush. + * + * Create two entries resident in cache, and have the second entry + * dirty the first in the flush callback. + */ + int test_num = 2; + unsigned int flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + int spec_size = 2; + int init_expected_index_len = 2; + size_t init_expected_index_size = 2 * PICO_ENTRY_SIZE; + int expected_index_len = 0; + size_t expected_index_size = 0; + struct fo_flush_cache_test_spec spec[2] = + { + { + /* entry_num = */ 0, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 1, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, PICO_ENTRY_TYPE,0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ (size_t)0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + + if ( pass ) /* test #3 */ + { + /* Single entry test verifying that the cache can handle the case in + * which the call back function resizes the entry for which it has + * been called. + */ + int test_num = 3; + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = VARIABLE_ENTRY_SIZE / 4; + int expected_index_len = 1; + size_t expected_index_size = VARIABLE_ENTRY_SIZE / 2; + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__SIZE_CHANGED_FLAG, + /* new_size = */ VARIABLE_ENTRY_SIZE / 4, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ (size_t)0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + + if ( pass ) /* test #4 */ + { + /* Repeat test #4 with the flush invalidate flag. + * + * Single entry test verifying that the cache can handle the case in + * which the call back function resizes the entry for which it has + * been called. + */ + int test_num = 4; + unsigned int flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = VARIABLE_ENTRY_SIZE / 4; + int expected_index_len = 0; + size_t expected_index_size = 0; + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__SIZE_CHANGED_FLAG, + /* new_size = */ VARIABLE_ENTRY_SIZE / 4, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ (size_t)0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + + if ( pass ) /* test #5 & #6 */ + { + /* Single entry test verifying that the cache can handle the case in + * which the call back function renames the entry for which it has + * been called. + * + * Run this entry twice, as the first run moves the entry to its + * alternate address, and the second moves it back. + */ + int test_num = 5; /* and 6 */ + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = VARIABLE_ENTRY_SIZE; + int expected_index_len = 1; + size_t expected_index_size = VARIABLE_ENTRY_SIZE; + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ (size_t)0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + + /* this change forces the rename to move the target entry back to its + * main address. The first test moved it to its alternate address. + * + * Note that these two tests are not the same, as in the first test, + * the renamed entry is moved forward in the slist. In the second + * it is moved backwards. + * + * Since there is only one entry in the cache, this doesn't really + * matter in this case. But we will do similar tests later with + * other entries in the cache. + */ + if ( pass ) { + + spec[0].flush_ops[0].flag = TRUE; + test_num = 6; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + } + + if ( pass ) /* test #7 & #8 */ + { + /* Run tests 5 & 6 again, using the flush invalidate flag on the + * second test. + * + * Single entry test verifying that the cache can handle the case in + * which the call back function renames the entry for which it has + * been called. + * + * Run this entry twice, as the first run moves the entry to its + * alternate address, and the second moves it back. + */ + int test_num = 7; /* and 8 */ + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = VARIABLE_ENTRY_SIZE; + int expected_index_len = 1; + size_t expected_index_size = VARIABLE_ENTRY_SIZE; + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ (size_t)0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + + /* this change forces the rename to move the target entry back to its + * main address. The first test moved it to its alternate address. + * + * Note that these two tests are not the same, as in the first test, + * the renamed entry is moved forward in the slist. In the second + * it is moved backwards. + * + * Since there is only one entry in the cache, this doesn't really + * matter in this case. But we will do similar tests later with + * other entries in the cache. + */ + + if ( pass ) { + + test_num = 8; + flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + expected_index_len = 0; + expected_index_size = 0; + spec[0].flush_ops[0].flag = TRUE; + spec[0].expected_destroyed = TRUE; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + } + + if ( pass ) /* test #9 & #10 */ + { + /* Single entry test verifying that the cache can handle the case in + * which the call back function both resizes and renames the entry + * for which it has been called. + * + * Again, we run this entry twice, as the first run moves the entry to its + * alternate address, and the second moves it back. + */ + int test_num = 9; /* and 10 */ + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = VARIABLE_ENTRY_SIZE / 2; + int expected_index_len = 1; + size_t expected_index_size = VARIABLE_ENTRY_SIZE / 4; + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__SIZE_CHANGED_FLAG, + /* new_size = */ VARIABLE_ENTRY_SIZE / 2, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 2, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ (size_t)0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + + /* this change forces the rename to move the target entry back to its + * main address. The first test moved it to its alternate address. + * + * Note that these two tests are not the same, as in the first test, + * the renamed entry is moved forward in the slist. In the second + * it is moved backwards. + * + * Since there is only one entry in the cache, this doesn't really + * matter in this case. But we will do similar tests later with + * other entries in the cache. + */ + if ( pass ) { + + spec[0].flush_ops[0].flag = TRUE; + test_num = 10; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + } + + if ( pass ) /* test #11 & #12 */ + { + /* Repeat the previous test with the flush invalidate flag on the + * second test. + * + * Single entry test verifying that the cache can handle the case in + * which the call back function both resizes and renames the entry + * for which it has been called. + * + * Again, we run this entry twice, as the first run moves the entry to its + * alternate address, and the second moves it back. + */ + int test_num = 11; /* and 12 */ + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = VARIABLE_ENTRY_SIZE / 2; + int expected_index_len = 1; + size_t expected_index_size = VARIABLE_ENTRY_SIZE / 4; + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__SIZE_CHANGED_FLAG, + /* new_size = */ VARIABLE_ENTRY_SIZE / 2, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 2, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ (size_t)0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + + /* this change forces the rename to move the target entry back to its + * main address. The first test moved it to its alternate address. + * + * Note that these two tests are not the same, as in the first test, + * the renamed entry is moved forward in the slist. In the second + * it is moved backwards. + * + * Since there is only one entry in the cache, this doesn't really + * matter in this case. But we will do similar tests later with + * other entries in the cache. + */ + if ( pass ) { + + test_num = 12; + flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + expected_index_len = 0; + expected_index_size = 0; + spec[0].flush_ops[1].flag = TRUE; + spec[0].expected_destroyed = TRUE; + + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + } + + if ( pass ) /* test #13 */ + { + /* Test the ability of the cache to handle the case in which + * the flush function of an entry that is resident in cache + * dirties two entries that are not in cache. No size + * changes. + * + * At present, I am assured that this case will never occur, but + * lets make sure we can handle it regardless. + */ + int test_num = 13; + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = 1 * PICO_ENTRY_SIZE; + int expected_index_len = 3; + size_t expected_index_size = 3 * PICO_ENTRY_SIZE; + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 2, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, 0, 0, FALSE, 0 }, + { FLUSH_OP__DIRTY, 0, 2, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 2; + struct fo_flush_entry_check checks[2] = + { + { + /* entry_num = */ 0, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 0, + /* expected_size = */ PICO_ENTRY_SIZE, + /* in_cache = */ TRUE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 2, + /* expected_size = */ PICO_ENTRY_SIZE, + /* in_cache = */ TRUE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + + if ( pass ) /* test #14 */ + { + /* Repeat previous test with the flush invalidate flag. + * + * Test the ability of the cache to handle the case in which + * the flush function of an entry that is resident in cache + * dirties two entries that are not in cache. No size + * changes. + * + * At present, I am assured that this case will never occur, but + * lets make sure we can handle it regardless. + */ + int test_num = 14; + unsigned int flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = 1 * PICO_ENTRY_SIZE; + int expected_index_len = 0; + size_t expected_index_size = (size_t)0; + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 2, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, 0, 0, FALSE, 0 }, + { FLUSH_OP__DIRTY, 0, 2, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + int check_size = 2; + struct fo_flush_entry_check checks[2] = + { + { + /* entry_num = */ 0, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 0, + /* expected_size = */ PICO_ENTRY_SIZE, + /* in_cache = */ FALSE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 1, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 2, + /* expected_size = */ PICO_ENTRY_SIZE, + /* in_cache = */ FALSE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + + if ( pass ) /* test #15 */ + { + /* Test the ability of the cache to handle the case in which + * the flush function of an entry that is resident in cache + * resizes and dirties two entries that are not in cache. + * + * At present, I am assured that this case will never occur, but + * lets make sure we can handle it regardless. + */ + int test_num = 15; + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = 1 * VARIABLE_ENTRY_SIZE; + int expected_index_len = 3; + size_t expected_index_size = VARIABLE_ENTRY_SIZE + + (VARIABLE_ENTRY_SIZE / 4) + + (VARIABLE_ENTRY_SIZE / 2); + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 4, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 2, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 2; + struct fo_flush_entry_check checks[2] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 4, + /* in_cache = */ TRUE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ TRUE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + + if ( pass ) /* test #16 */ + { + /* Repeat previous test with the flush invalidate flag. + * + * Test the ability of the cache to handle the case in which + * the flush function of an entry that is resident in cache + * resizes and dirties two entries that are not in cache. + * + * At present, I am assured that this case will never occur, but + * lets make sure we can handle it regardless. + */ + int test_num = 16; + unsigned int flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = 1 * VARIABLE_ENTRY_SIZE; + int expected_index_len = 0; + size_t expected_index_size = (size_t)0; + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 4, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 2, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + int check_size = 2; + struct fo_flush_entry_check checks[2] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 4, + /* in_cache = */ FALSE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ FALSE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + + if ( pass ) /* test #17 & #18 */ + { + /* Test the ability of the cache to handle the case in which + * the flush function of an entry that is resident in cache + * resizes, dirties, and renames two entries that are not in cache. + * + * At present, I am assured that this case will never occur, but + * lets make sure we can handle it regardless. + */ + int test_num = 17; /* and 18 */ + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = 1 * VARIABLE_ENTRY_SIZE; + int expected_index_len = 3; + size_t expected_index_size = VARIABLE_ENTRY_SIZE + + (VARIABLE_ENTRY_SIZE / 4) + + (VARIABLE_ENTRY_SIZE / 2); + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 6, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 2, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 2; + struct fo_flush_entry_check checks[2] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 4, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + + /* this change forces the renames to move the target entries back to + * their main address. The first test moved them to their alternate + * address. + * + * Note that these two tests are not the same, as in the first test, + * the renamed entries are moved forward in the slist. In the second + * they are moved backwards. + */ + if ( pass ) { + + test_num = 18; + spec[0].flush_ops[2].flag = TRUE; + spec[0].flush_ops[5].flag = TRUE; + checks[0].at_main_addr = TRUE; + checks[1].at_main_addr = TRUE; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + } + + if ( pass ) /* test #19 & #20 */ + { + /* Repeat the above test with the flush invalidate flag on the + * second test. + * + * Test the ability of the cache to handle the case in which + * the flush function of an entry that is resident in cache + * resizes, dirties, and renames two entries that are not in cache. + * + * At present, I am assured that this case will never occur, but + * lets make sure we can handle it regardless. + */ + int test_num = 19; /* and 20 */ + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 1; + int init_expected_index_len = 1; + size_t init_expected_index_size = 1 * VARIABLE_ENTRY_SIZE; + int expected_index_len = 3; + size_t expected_index_size = VARIABLE_ENTRY_SIZE + + (VARIABLE_ENTRY_SIZE / 4) + + (VARIABLE_ENTRY_SIZE / 2); + struct fo_flush_cache_test_spec spec[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 6, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 2, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 2; + struct fo_flush_entry_check checks[2] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 4, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + + /* this change forces the renames to move the target entries back to + * their main address. The first test moved them to their alternate + * address. + * + * Note that these two tests are not the same, as in the first test, + * the renamed entries are moved forward in the slist. In the second + * they are moved backwards. + */ + if ( pass ) { + + test_num = 20; + flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + expected_index_len = 0; + expected_index_size = (size_t)0; + spec[0].expected_destroyed = TRUE; + spec[0].flush_ops[2].flag = TRUE; + spec[0].flush_ops[5].flag = TRUE; + checks[0].at_main_addr = TRUE; + checks[0].in_cache = FALSE; + checks[0].expected_destroyed = TRUE; + checks[1].at_main_addr = TRUE; + checks[1].in_cache = FALSE; + checks[1].expected_destroyed = TRUE; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + } + + if ( pass ) /* test #21 */ + { + /* Now mix things up a bit. + * + * Load several entries, two of which have flush functions that + * resize, dirty, and rename two entries that are not in the + * cache. Mark only one of these entries, and then flush the + * cache with the flush marked entries flag. + * + * This is the only test in which we test the + * H5C__FLUSH_MARKED_ENTRIES_FLAG. The hope is that since + * we test the two features extensively by themselves, so + * it should be sufficient to verify that they play together + * as expected. + */ + int test_num = 21; + unsigned int flush_flags = H5C__FLUSH_MARKED_ENTRIES_FLAG; + int spec_size = 4; + int init_expected_index_len = 4; + size_t init_expected_index_size = (2 * VARIABLE_ENTRY_SIZE) + (2 * PICO_ENTRY_SIZE); + int expected_index_len = 6; + size_t expected_index_size = (2 * VARIABLE_ENTRY_SIZE) + + (VARIABLE_ENTRY_SIZE / 4) + + (VARIABLE_ENTRY_SIZE / 2) + + (2 * PICO_ENTRY_SIZE); + struct fo_flush_cache_test_spec spec[4] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG | H5C__SET_FLUSH_MARKER_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 6, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 2, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 11, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 6, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 10, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 10, FALSE, 0 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 10, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 12, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 12, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 12, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 2, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG | H5C__SET_FLUSH_MARKER_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 3, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 4; + struct fo_flush_entry_check checks[4] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 4, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ TRUE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ TRUE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 2, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 10, + /* expected_size = */ VARIABLE_ENTRY_SIZE, + /* in_cache = */ FALSE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 3, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 12, + /* expected_size = */ VARIABLE_ENTRY_SIZE, + /* in_cache = */ FALSE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + reset_entries(); + } + + if ( pass ) /* test #22 */ + { + /* Mix things up some more. + * + * Load lots of entries, some of which have flush functions that + * resize, dirty, and rename two entries that are not in the + * cache. + * + * Also load entries that have flush ops on entries that are in + * cache. + */ + int test_num = 22; + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 6; + int init_expected_index_len = 6; + size_t init_expected_index_size = (2 * VARIABLE_ENTRY_SIZE) + (4 * PICO_ENTRY_SIZE); + int expected_index_len = 10; + size_t expected_index_size = (2 * VARIABLE_ENTRY_SIZE) + + (2 * (VARIABLE_ENTRY_SIZE / 4)) + + (2 * (VARIABLE_ENTRY_SIZE / 2)) + + (4 * PICO_ENTRY_SIZE); + struct fo_flush_cache_test_spec spec[6] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 6, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 2, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 11, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 6, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 10, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 10, FALSE, 0 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 10, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 12, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 12, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 12, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 2, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 3, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 4, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 10, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, PICO_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 5, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 20, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, PICO_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 4; + struct fo_flush_entry_check checks[4] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 4, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 2, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 10, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 4, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 3, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 12, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + reset_entries(); + } + + if ( pass ) /* test #23 */ + { + /* Repeat test #23 with the flush invalidate flag set. + * + * Mix things up some more. + * + * Load lots of entries, some of which have flush functions that + * resize, dirty, and rename two entries that are not in the + * cache. + * + * Also load entries that have flush ops on entries that are in + * cache. + */ + int test_num = 23; + unsigned int flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + int spec_size = 6; + int init_expected_index_len = 6; + size_t init_expected_index_size = (2 * VARIABLE_ENTRY_SIZE) + (4 * PICO_ENTRY_SIZE); + int expected_index_len = 0; + size_t expected_index_size = 0; + struct fo_flush_cache_test_spec spec[6] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 6, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 2, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 2, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 11, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 6, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 10, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 10, FALSE, 0 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 10, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 12, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 12, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 12, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 2, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 0, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 3, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 1, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 4, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 10, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, PICO_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 5, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 20, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, PICO_ENTRY_TYPE, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + int check_size = 4; + struct fo_flush_entry_check checks[4] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 0, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 4, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 2, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 10, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 4, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 3, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 12, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + reset_entries(); + } + + /* So much for tests involving only flush operations. + * + * Now create some tests mixing flush ops and pins. + */ + if ( pass ) /* test #24 */ + { + /* Pico entries 50 and 150 pin pico entry 100, and also dirty + * pico entry 100 on flush. + */ + int test_num = 24; + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 3; + int init_expected_index_len = 3; + size_t init_expected_index_size = 3 * PICO_ENTRY_SIZE; + int expected_index_len = 3; + size_t expected_index_size = 3 * PICO_ENTRY_SIZE; + struct fo_flush_cache_test_spec spec[3] = + { + { + /* entry_num = */ 0, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 100, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 50, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 1, + /* pin_type = */ {PICO_ENTRY_TYPE, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {100, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, PICO_ENTRY_TYPE, 100, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 2, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 150, + /* insert_flag = */ TRUE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 1, + /* pin_type = */ {PICO_ENTRY_TYPE, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {100, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, PICO_ENTRY_TYPE, 100, FALSE, 0 }, + { FLUSH_OP__DIRTY, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ (size_t)0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + + if ( pass ) /* test #25 */ + { + /* Repeat the previous test with the flush invalidate flag. + * + * Pico entries 50 and 150 pin pico entry 100, and also dirty + * pico entry 100 on flush. + */ + int test_num = 25; + unsigned int flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + int spec_size = 3; + int init_expected_index_len = 3; + size_t init_expected_index_size = 3 * PICO_ENTRY_SIZE; + int expected_index_len = 0; + size_t expected_index_size = (size_t)0; + struct fo_flush_cache_test_spec spec[3] = + { + { + /* entry_num = */ 0, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 100, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 1, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 50, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 1, + /* pin_type = */ {PICO_ENTRY_TYPE, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {100, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, PICO_ENTRY_TYPE, 100, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 2, + /* entry_type = */ PICO_ENTRY_TYPE, + /* entry_index = */ 150, + /* insert_flag = */ TRUE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 1, + /* pin_type = */ {PICO_ENTRY_TYPE, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {100, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 1, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, PICO_ENTRY_TYPE, 100, FALSE, 0 }, + { FLUSH_OP__DIRTY, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ (size_t)0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + } + + if ( pass ) /* test #26 */ + { + /* This one is complex. + * + * In the following overvies table, VET stands for + * VARIABLE_ENTRY_TYPE. + * + * In trying to follow what happens when we flush the + * set of entries constructed below, recall that each + * flush operation is executed the first time the + * entry is flushed, and then not executed again. + * This may be a weakness in the tests, but that + * is the way it is for now. + * + * After thinking about it for a while, I'm not sure that + * the interaction between pins and flush operations needs + * all that much testing, as the two are essentially + * orthoginal. Thus this is a bit of a smoke check to + * verify that we get the expected results. + * + * (VET, 100) initially not resident in cache + * + * (VET, 200) initially clean and resident in cache + * + * (VET, 300) initially not resident in cache + * + * (VET, 2100) initially clean and resident in cache + * + * (VET, 2200) initially not resident in cache + * + * (VET, 2300) initially clean and resident in cache + * + * (VET, 1000) initially clean, and in cache + * dirties (VET, 100) + * resizes (VET, 200) + * dirty (VET, 300) -- dirty first to bring into cache. + * renames (VET, 300) + * + * (VET, 2000) initially clean, and in cache + * dirties (VET, 2100) + * resizes (VET, 2200) + * renames (VET, 2300) + * + * (VET, 350) initially clean, and in cache + * pins (VET, 1000) + * dirties (VET, 1000) + * resizes (VET, 350) + * pins (VET, 2000) + * dirties (VET, 2000) + * + * (VET, 450) initially dirty, and in cache + * pins (VET, 1000) + * dirties (VET, 1000) + * renames (VET, 450) + * pins (VET, 2000) + * dirties (VET, 2000) + * + * (VET, 650) initially clean, and in cache + * pins (VET, 1000) + * dirties (VET, 1000) + * resizes (VET, 650) + * pins (VET, 2000) + * dirties (VET, 2000) + * + * (VET, 750) initially dirty, and in cache + * pins (VET, 1000) + * dirties (VET, 1000) + * resizes (VET, 750) + * pins (VET, 2000) + * dirties (VET, 2000) + * + * (VET, 500) initially dirty, and in cache + * dirties (VET, 350) + * dirties (VET, 450) + * dirties (VET, 650) + * dirties (VET, 750) + */ + int test_num = 26; + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 10; + int init_expected_index_len = 10; + size_t init_expected_index_size = 10 * VARIABLE_ENTRY_SIZE; + int expected_index_len = 13; + size_t expected_index_size = 9 * VARIABLE_ENTRY_SIZE; + struct fo_flush_cache_test_spec spec[10] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 200, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2100, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 2, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2300, + /* insert_flag = */ TRUE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 3, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 1000, + /* insert_flag = */ TRUE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 4, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 100, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 200, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 300, FALSE, 0 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 300, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 4, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2000, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2100, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 2200, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 2300, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 5, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 350, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 2, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {1000, 2000, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 1000, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2000, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 350, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 6, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 450, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 2, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {1000, 2000, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 1000, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2000, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 450, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 7, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 650, + /* insert_flag = */ TRUE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 2, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {1000, 2000, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 1000, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2000, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 650, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 8, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 750, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 2, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {1000, 2000, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 1000, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2000, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 750, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 9, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 500, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 4, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 350, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 450, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 650, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 750, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 3; + struct fo_flush_entry_check checks[3] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 100, + /* expected_size = */ VARIABLE_ENTRY_SIZE, + /* in_cache = */ TRUE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 300, + /* expected_size = */ VARIABLE_ENTRY_SIZE, + /* in_cache = */ TRUE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 2, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2200, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ TRUE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + + reset_entries(); + } + + if ( pass ) /* test #27 */ + { + /* Repeat test #26 with the flush invalidate flag. + * + * In the following overview table, VET stands for + * VARIABLE_ENTRY_TYPE. + * + * In trying to follow what happens when we flush the + * set of entries constructed below, recall that each + * flush operation is executed the first time the + * entry is flushed, and then not executed again. + * This may be a weakness in the tests, but that + * is the way it is for now. + * + * After thinking about it for a while, I'm not sure that + * the interaction between pins and flush operations needs + * all that much testing, as the two are essentially + * orthoginal. The big thing is to verify that flushes of + * pinned entries with flush ops result in the expected + * updates of the cache. + * + * Thus this is a bit of a smoke check to * verify that we + * get the expected results. + * + * (VET, 100) initially not resident in cache + * + * (VET, 200) initially clean and resident in cache + * + * (VET, 300) initially not resident in cache + * + * (VET, 2100) initially clean and resident in cache + * + * (VET, 2200) initially not resident in cache + * + * (VET, 2300) initially clean and resident in cache + * + * (VET, 1000) initially clean, and in cache + * dirties (VET, 100) + * resizes (VET, 200) + * dirty (VET, 300) -- dirty first to bring into cache. + * renames (VET, 300) + * + * (VET, 2000) initially clean, and in cache + * dirties (VET, 2100) + * resizes (VET, 2200) + * renames (VET, 2300) + * + * (VET, 350) initially clean, and in cache + * pins (VET, 1000) + * dirties (VET, 1000) + * resizes (VET, 350) + * pins (VET, 2000) + * dirties (VET, 2000) + * + * (VET, 450) initially dirty, and in cache + * pins (VET, 1000) + * dirties (VET, 1000) + * renames (VET, 450) + * pins (VET, 2000) + * dirties (VET, 2000) + * + * (VET, 650) initially clean, and in cache + * pins (VET, 1000) + * dirties (VET, 1000) + * resizes (VET, 650) + * pins (VET, 2000) + * dirties (VET, 2000) + * + * (VET, 750) initially dirty, and in cache + * pins (VET, 1000) + * dirties (VET, 1000) + * resizes (VET, 750) + * pins (VET, 2000) + * dirties (VET, 2000) + * + * (VET, 500) initially dirty, and in cache + * dirties (VET, 350) + * dirties (VET, 450) + * dirties (VET, 650) + * dirties (VET, 750) + */ + int test_num = 27; + unsigned int flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + int spec_size = 10; + int init_expected_index_len = 10; + size_t init_expected_index_size = 10 * VARIABLE_ENTRY_SIZE; + int expected_index_len = 0; + size_t expected_index_size = (size_t)0; + struct fo_flush_cache_test_spec spec[10] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 200, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2100, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 2, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2300, + /* insert_flag = */ TRUE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 3, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 1000, + /* insert_flag = */ TRUE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 4, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 100, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 200, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 300, FALSE, 0 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 300, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 4, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2000, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2100, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 2200, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 2300, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 5, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 350, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 2, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {1000, 2000, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 1000, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2000, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 350, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 6, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 450, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 2, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {1000, 2000, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 1000, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2000, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 450, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 7, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 650, + /* insert_flag = */ TRUE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 2, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {1000, 2000, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 1000, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2000, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 650, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 8, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 750, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 2, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {1000, 2000, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 1000, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 2000, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 750, FALSE, VARIABLE_ENTRY_SIZE / 4 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 9, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 500, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 4, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 350, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 450, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 650, FALSE, 0 }, + { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 750, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + int check_size = 3; + struct fo_flush_entry_check checks[3] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 100, + /* expected_size = */ VARIABLE_ENTRY_SIZE, + /* in_cache = */ FALSE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 300, + /* expected_size = */ VARIABLE_ENTRY_SIZE, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 2, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 2200, + /* expected_size = */ VARIABLE_ENTRY_SIZE / 2, + /* in_cache = */ FALSE, + /* at_main_addr = */ TRUE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + + reset_entries(); + } + + if ( pass ) /* test #28 */ + { + /* Test the expected fheap case, in which an entry dirties + * and resizes itself, and dirties an entry which it has + * pinned. + */ + int test_num = 28; + unsigned int flush_flags = H5C__NO_FLAGS_SET; + int spec_size = 5; + int init_expected_index_len = 5; + size_t init_expected_index_size = 3 * VARIABLE_ENTRY_SIZE; + int expected_index_len = 5; + size_t expected_index_size = 4 * VARIABLE_ENTRY_SIZE; + struct fo_flush_cache_test_spec spec[5] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 100, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 200, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG | H5C__SIZE_CHANGED_FLAG, + /* new_size = */ VARIABLE_ENTRY_SIZE / 2, + /* num_pins = */ 1, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {100, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 100, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 200, FALSE, VARIABLE_ENTRY_SIZE }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 200, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 2, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 300, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG | H5C__SIZE_CHANGED_FLAG, + /* new_size = */ VARIABLE_ENTRY_SIZE / 4, + /* num_pins = */ 1, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {400, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 400, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 300, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 300, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 3, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 400, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + }, + { + /* entry_num = */ 4, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 500, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG | H5C__SIZE_CHANGED_FLAG, + /* new_size = */ VARIABLE_ENTRY_SIZE / 4, + /* num_pins = */ 1, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {100, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 100, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 500, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 500, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ FALSE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ 0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + + reset_entries(); + } + + if ( pass ) /* test #29 */ + { + /* Repeat test #28 with the flush invalidate flag. + * + * Test the expected fheap case, in which an entry dirties + * and resizes itself, and dirties an entry which it has + * pinned. + */ + int test_num = 29; + unsigned int flush_flags = H5C__FLUSH_INVALIDATE_FLAG; + int spec_size = 5; + int init_expected_index_len = 5; + size_t init_expected_index_size = 3 * VARIABLE_ENTRY_SIZE; + int expected_index_len = 0; + size_t expected_index_size = 0; + struct fo_flush_cache_test_spec spec[5] = + { + { + /* entry_num = */ 0, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 100, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 1, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 200, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG | H5C__SIZE_CHANGED_FLAG, + /* new_size = */ VARIABLE_ENTRY_SIZE / 2, + /* num_pins = */ 1, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {100, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 100, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 200, FALSE, VARIABLE_ENTRY_SIZE }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 200, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 2, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 300, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG | H5C__SIZE_CHANGED_FLAG, + /* new_size = */ VARIABLE_ENTRY_SIZE / 4, + /* num_pins = */ 1, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {400, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 400, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 300, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 300, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 3, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 400, + /* insert_flag = */ FALSE, + /* flags = */ H5C__NO_FLAGS_SET, + /* new_size = */ 0, + /* num_pins = */ 0, + /* pin_type = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 0, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + }, + { + /* entry_num = */ 4, + /* entry_type = */ VARIABLE_ENTRY_TYPE, + /* entry_index = */ 500, + /* insert_flag = */ FALSE, + /* flags = */ H5C__DIRTIED_FLAG | H5C__SIZE_CHANGED_FLAG, + /* new_size = */ VARIABLE_ENTRY_SIZE / 4, + /* num_pins = */ 1, + /* pin_type = */ {VARIABLE_ENTRY_TYPE, 0, 0, 0, 0, 0, 0, 0}, + /* pin_idx = */ {100, 0, 0, 0, 0, 0, 0, 0}, + /* num_flush_ops = */ 3, + /* flush_ops = */ + /* op_code: type: idx: flag: size: */ + { { FLUSH_OP__DIRTY, VARIABLE_ENTRY_TYPE, 100, FALSE, 0 }, + { FLUSH_OP__RESIZE, VARIABLE_ENTRY_TYPE, 500, FALSE, VARIABLE_ENTRY_SIZE / 2 }, + { FLUSH_OP__RENAME, VARIABLE_ENTRY_TYPE, 500, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 }, + { FLUSH_OP__NO_OP, 0, 0, FALSE, 0 } }, + /* expected_loaded = */ TRUE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ TRUE, + /* expected_destroyed = */ TRUE + } + }; + int check_size = 0; + struct fo_flush_entry_check checks[1] = + { + { + /* entry_num = */ 0, + /* entry_type = */ 0, + /* entry_index = */ 0, + /* expected_size = */ 0, + /* in_cache = */ FALSE, + /* at_main_addr = */ FALSE, + /* is_dirty = */ FALSE, + /* is_protected = */ FALSE, + /* is_pinned = */ FALSE, + /* expected_loaded = */ FALSE, + /* expected_cleared = */ FALSE, + /* expected_flushed = */ FALSE, + /* expected_destroyed = */ FALSE + } + }; + + check_flush_cache__flush_op_test(cache_ptr, + test_num, + flush_flags, + spec_size, + spec, + init_expected_index_len, + init_expected_index_size, + expected_index_len, + expected_index_size, + check_size, + checks); + + reset_entries(); + } + + /* finally finish up with the flush ops eviction test */ + check_flush_cache__flush_op_eviction_test(cache_ptr); + + return; + +} /* check_flush_cache__flush_ops() */ + + +/*------------------------------------------------------------------------- + * Function: check_flush_cache__flush_op_test() + * + * Purpose: Run a flush op flush cache test. Of the nature of + * flush operations, this is a multi-entry test. + * + * Return: void + * + * Programmer: John Mainzer + * 9/3/06 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +static void +check_flush_cache__flush_op_test(H5C_t * cache_ptr, + int test_num, + unsigned int flush_flags, + int spec_size, + struct fo_flush_cache_test_spec spec[], + int init_expected_index_len, + size_t init_expected_index_size, + int expected_index_len, + size_t expected_index_size, + int check_size, + struct fo_flush_entry_check check[]) +{ + /* const char * fcn_name = "check_flush_cache__flush_op_test"; */ + static char msg[128]; + herr_t result; + int i; + int j; + test_entry_t * base_addr; + test_entry_t * entry_ptr; + +#if 0 /* This is useful debugging code -- lets keep it around. */ + HDfprintf(stdout, "check_flush_cache__flush_op_test: test %d\n", + test_num); +#endif + + if ( cache_ptr == NULL ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "cache_ptr NULL on entry to flush op test #%d.", + test_num); + failure_mssg = msg; + } + else if ( ( cache_ptr->index_len != 0 ) || + ( cache_ptr->index_size != 0 ) ) { + + pass = FALSE; + + HDsnprintf(msg, (size_t)128, + "cache not empty at beginning of flush op test #%d.", + test_num); + failure_mssg = msg; + } + else if ( ( spec_size < 1 ) || ( spec == NULL ) ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "missing/bad test spec on entry to flush op test #%d.", + test_num); + failure_mssg = msg; + } + + i = 0; + while ( ( pass ) && ( i < spec_size ) ) + { + if ( ( spec[i].entry_num != i ) || + ( spec[i].entry_type < 0 ) || + ( spec[i].entry_type >= NUMBER_OF_ENTRY_TYPES ) || + ( spec[i].entry_index < 0 ) || + ( spec[i].entry_index > max_indices[spec[i].entry_type] ) || + ( spec[i].num_pins < 0 ) || + ( spec[i].num_pins > MAX_PINS ) || + ( spec[i].num_flush_ops < 0 ) || + ( spec[i].num_flush_ops > MAX_FLUSH_OPS ) ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "bad data in spec[%d] on entry to flush op test #%d.", + i, test_num); + failure_mssg = msg; + } + i++; + } + + i = 0; + while ( ( pass ) && ( i < check_size ) ) + { + if ( ( check[i].entry_num != i ) || + ( check[i].entry_type < 0 ) || + ( check[i].entry_type >= NUMBER_OF_ENTRY_TYPES ) || + ( check[i].entry_index < 0 ) || + ( check[i].entry_index > max_indices[check[i].entry_type] ) || + ( check[i].expected_size <= (size_t)0 ) || + ( ( check[i].in_cache != TRUE ) && + ( check[i].in_cache != FALSE ) ) || + ( ( check[i].at_main_addr != TRUE ) && + ( check[i].at_main_addr != FALSE ) ) || + ( ( check[i].is_dirty != TRUE ) && + ( check[i].is_dirty != FALSE ) ) || + ( ( check[i].is_protected != TRUE ) && + ( check[i].is_protected != FALSE ) ) || + ( ( check[i].is_pinned != TRUE ) && + ( check[i].is_pinned != FALSE ) ) || + ( ( check[i].expected_loaded != TRUE ) && + ( check[i].expected_loaded != FALSE ) ) || + ( ( check[i].expected_cleared != TRUE ) && + ( check[i].expected_cleared != FALSE ) ) || + ( ( check[i].expected_flushed != TRUE ) && + ( check[i].expected_flushed != FALSE ) ) || + ( ( check[i].expected_destroyed != TRUE ) && + ( check[i].expected_destroyed != FALSE ) ) ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "bad data in check[%d] on entry to flush op test #%d.", + i, test_num); + failure_mssg = msg; + } + i++; + } + + i = 0; + while ( ( pass ) && ( i < spec_size ) ) + { + if ( spec[i].insert_flag ) { + + insert_entry(cache_ptr, spec[i].entry_type, spec[i].entry_index, + TRUE, spec[i].flags); + + } else { + + protect_entry(cache_ptr, spec[i].entry_type, spec[i].entry_index); + + unprotect_entry_with_size_change(cache_ptr, spec[i].entry_type, + spec[i].entry_index, + spec[i].flags, spec[i].new_size); + } + + for ( j = 0; j < spec[i].num_pins; j++ ) + { + create_pinned_entry_dependency(cache_ptr, + spec[i].entry_type, + spec[i].entry_index, + spec[i].pin_type[j], + spec[i].pin_idx[j]); + } + + for ( j = 0; j < spec[i].num_flush_ops; j++ ) + { + add_flush_op(spec[i].entry_type, + spec[i].entry_index, + spec[i].flush_ops[j].op_code, + spec[i].flush_ops[j].type, + spec[i].flush_ops[j].idx, + spec[i].flush_ops[j].flag, + spec[i].flush_ops[j].size); + } + + i++; + } + + if ( pass ) { + + if ( ( cache_ptr->index_len != init_expected_index_len ) || + ( cache_ptr->index_size != init_expected_index_size ) ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Unexpected cache len/size before flush in flush op test #%d.", + test_num); + failure_mssg = msg; + } + } + + if ( pass ) { + + result = H5C_flush_cache(NULL, -1, -1, cache_ptr, flush_flags); + + if ( result < 0 ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "flush with flags 0x%x failed in flush op test #%d.", + flush_flags, test_num); + failure_mssg = msg; + } + } + + + i = 0; + while ( ( pass ) && ( i < spec_size ) ) + { + base_addr = entries[spec[i].entry_type]; + entry_ptr = &(base_addr[spec[i].entry_index]); + + if ( ( entry_ptr->loaded != spec[i].expected_loaded ) || + ( entry_ptr->cleared != spec[i].expected_cleared ) || + ( entry_ptr->flushed != spec[i].expected_flushed ) || + ( entry_ptr->destroyed != spec[i].expected_destroyed ) ) { + +#if 0 /* This is useful debugging code. Lets keep it around. */ + + HDfprintf(stdout, + "loaded = %d(%d), clrd = %d(%d), flshd = %d(%d), dest = %d(%d)\n", + (int)(entry_ptr->loaded), + (int)(spec[i].expected_loaded), + (int)(entry_ptr->cleared), + (int)(spec[i].expected_cleared), + (int)(entry_ptr->flushed), + (int)(spec[i].expected_flushed), + (int)(entry_ptr->destroyed), + (int)(spec[i].expected_destroyed)); + + HDfprintf(stdout, "entry_ptr->header.is_dirty = %d\n", + (int)(entry_ptr->header.is_dirty)); +#endif + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Bad status on entry %d after flush op test #%d.", + i, test_num); + failure_mssg = msg; + } + i++; + } + + if ( pass ) { + + i = 0; + while ( ( pass ) && ( i < check_size ) ) + { + if ( check[i].in_cache != entry_in_cache(cache_ptr, + check[i].entry_type, + check[i].entry_index) ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Check1 failed on entry %d after flush op test #%d.", + i, test_num); + failure_mssg = msg; + } + + base_addr = entries[check[i].entry_type]; + entry_ptr = &(base_addr[check[i].entry_index]); + + if ( ( entry_ptr->size != check[i].expected_size ) || + ( ( ! entry_ptr->header.destroy_in_progress ) && + ( check[i].in_cache ) && + ( entry_ptr->header.size != check[i].expected_size ) ) || + ( entry_ptr->at_main_addr != check[i].at_main_addr ) || + ( entry_ptr->is_dirty != check[i].is_dirty ) || + ( entry_ptr->header.is_dirty != check[i].is_dirty ) || + ( entry_ptr->is_protected != check[i].is_protected ) || + ( entry_ptr->header.is_protected != check[i].is_protected ) || + ( entry_ptr->is_pinned != check[i].is_pinned ) || + ( entry_ptr->header.is_pinned != check[i].is_pinned ) || + ( entry_ptr->loaded != check[i].expected_loaded ) || + ( entry_ptr->cleared != check[i].expected_cleared ) || + ( entry_ptr->flushed != check[i].expected_flushed ) || + ( entry_ptr->destroyed != check[i].expected_destroyed ) ) { + +#if 0 /* This is useful debugging code. Lets keep it around for a while. */ + + if ( entry_ptr->size != check[i].expected_size ) { + HDfprintf(stdout, "entry_ptr->size (expected) = %d (%d).\n", + (int)(entry_ptr->size), + (int)(check[i].expected_size)); + } + if ( ( ! entry_ptr->header.destroy_in_progress ) && + ( check[i].in_cache ) && + ( entry_ptr->header.size != check[i].expected_size ) ) { + HDfprintf(stdout, + "(!destroy in progress and in cache and size (expected) = %d (%d).\n", + (int)(entry_ptr->header.size), + (int)(check[i].expected_size)); + } + if ( entry_ptr->at_main_addr != check[i].at_main_addr ) { + HDfprintf(stdout, "(%d,%d) at main addr (expected) = %d (%d).\n", + (int)(check[i].entry_type), + (int)(check[i].entry_index), + (int)(entry_ptr->at_main_addr), + (int)(check[i].at_main_addr)); + } + if ( entry_ptr->is_dirty != check[i].is_dirty ) { + HDfprintf(stdout, "entry_ptr->is_dirty (expected) = %d (%d).\n", + (int)(entry_ptr->is_dirty), + (int)(check[i].is_dirty)); + } + if ( entry_ptr->header.is_dirty != check[i].is_dirty ) { + HDfprintf(stdout, "entry_ptr->header.is_dirty (expected) = %d (%d).\n", + (int)(entry_ptr->header.is_dirty), + (int)(check[i].is_dirty)); + } + if ( entry_ptr->is_protected != check[i].is_protected ) { + HDfprintf(stdout, "entry_ptr->is_protected (expected) = %d (%d).\n", + (int)(entry_ptr->is_protected), + (int)(check[i].is_protected)); + } + if ( entry_ptr->header.is_protected != check[i].is_protected ) { + HDfprintf(stdout, "entry_ptr->header.is_protected (expected) = %d (%d).\n", + (int)(entry_ptr->is_protected), + (int)(check[i].is_protected)); + } + if ( entry_ptr->is_pinned != check[i].is_pinned ) { + HDfprintf(stdout, "entry_ptr->is_pinned (expected) = %d (%d).\n", + (int)(entry_ptr->is_pinned), + (int)(check[i].is_pinned)); + } + if ( entry_ptr->header.is_pinned != check[i].is_pinned ) { + HDfprintf(stdout, "entry_ptr->header.is_pinned (expected) = %d (%d).\n", + (int)(entry_ptr->header.is_pinned), + (int)(check[i].is_pinned)); + } + if ( entry_ptr->loaded != check[i].expected_loaded ) { + HDfprintf(stdout, "entry_ptr->loaded (expected) = %d (%d).\n", + (int)(entry_ptr->loaded), + (int)(check[i].expected_loaded)); + } + if ( entry_ptr->cleared != check[i].expected_cleared ) { + HDfprintf(stdout, "entry_ptr->cleared (expected) = %d (%d).\n", + (int)(entry_ptr->cleared), + (int)(check[i].expected_cleared)); + } + if ( entry_ptr->flushed != check[i].expected_flushed ) { + HDfprintf(stdout, "entry_ptr->flushed (expected) = %d (%d).\n", + (int)(entry_ptr->flushed), + (int)(check[i].expected_flushed)); + } + if ( entry_ptr->destroyed != check[i].expected_destroyed ) { + HDfprintf(stdout, "entry_ptr->destroyed (expected) = %d (%d).\n", + (int)(entry_ptr->destroyed), + (int)(check[i].expected_destroyed)); + } +#endif + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Check2 failed on entry %d after flush op test #%d.", + i, test_num); + failure_mssg = msg; + } + i++; + } + } + + if ( pass ) { + + if ( ( ( (flush_flags & H5C__FLUSH_INVALIDATE_FLAG) == 0 ) + && + ( ( cache_ptr->index_len != expected_index_len ) + || + ( cache_ptr->index_size != expected_index_size ) + ) + ) + || + ( ( (flush_flags & H5C__FLUSH_INVALIDATE_FLAG) != 0 ) + && + ( ( cache_ptr->index_len != 0 ) + || + ( cache_ptr->index_size != 0 ) + ) + ) + ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Unexpected cache len/size after flush in flush op test #%d.", + test_num); + failure_mssg = msg; + } + } + + /* clean up the cache to prep for the next test */ + if ( pass ) { + + result = H5C_flush_cache(NULL, -1, -1, cache_ptr, + H5C__FLUSH_INVALIDATE_FLAG); + + if ( result < 0 ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Flush failed on cleanup in flush op test #%d.", + test_num); + failure_mssg = msg; + } + else if ( ( cache_ptr->index_len != 0 ) || + ( cache_ptr->index_size != 0 ) ) { + + pass = FALSE; + HDsnprintf(msg, (size_t)128, + "Unexpected cache len/size after cleanup in flush op test #%d.", + test_num); + failure_mssg = msg; + + } + } + + i = 0; + while ( ( pass ) && ( i < spec_size ) ) + { + base_addr = entries[spec[i].entry_type]; + entry_ptr = &(base_addr[spec[i].entry_index]); + + entry_ptr->size = entry_sizes[spec[i].entry_type]; + + entry_ptr->loaded = FALSE; + entry_ptr->cleared = FALSE; + entry_ptr->flushed = FALSE; + entry_ptr->destroyed = FALSE; + + i++; + } + + i = 0; + while ( ( pass ) && ( i < check_size ) ) + { + base_addr = entries[check[i].entry_type]; + entry_ptr = &(base_addr[check[i].entry_index]); + + entry_ptr->size = entry_sizes[check[i].entry_type]; + + entry_ptr->loaded = FALSE; + entry_ptr->cleared = FALSE; + entry_ptr->flushed = FALSE; + entry_ptr->destroyed = FALSE; + + i++; + } + + return; + +} /* check_flush_cache__flush_op_test() */ + + +/*------------------------------------------------------------------------- + * Function: check_flush_cache__flush_op_eviction_test() + * + * Purpose: Verify that flush operations work as expected when an + * entry is evicted. + * + * Do nothing if pass is FALSE on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 10/3/06 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +static void +check_flush_cache__flush_op_eviction_test(H5C_t * cache_ptr) +{ + /* const char * fcn_name = "check_flush_cache__flush_op_eviction_test"; */ + int i; + int num_variable_entries = 8; + int num_monster_entries = 31; + int num_large_entries = 0; + herr_t result; + test_entry_t * entry_ptr; + test_entry_t * base_addr; + struct expected_entry_status expected[8 + 31 + 14] = + { + /* the expected array is used to maintain a table of the expected status of every + * entry used in this test. Note that since the function that processes this + * array only processes as much of it as it is told to, we don't have to + * worry about maintaining the status of entries that we haven't used yet. + */ + /* entry entry in at main */ + /* type: index: size: cache: addr: dirty: prot: pinned: loaded: clrd: flshd: dest: */ + { VARIABLE_ENTRY_TYPE, 0, VARIABLE_ENTRY_SIZE/2, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE }, + { VARIABLE_ENTRY_TYPE, 1, VARIABLE_ENTRY_SIZE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { VARIABLE_ENTRY_TYPE, 2, VARIABLE_ENTRY_SIZE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { VARIABLE_ENTRY_TYPE, 3, VARIABLE_ENTRY_SIZE/2, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { VARIABLE_ENTRY_TYPE, 4, VARIABLE_ENTRY_SIZE/2, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { VARIABLE_ENTRY_TYPE, 5, VARIABLE_ENTRY_SIZE/2, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { VARIABLE_ENTRY_TYPE, 6, VARIABLE_ENTRY_SIZE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { VARIABLE_ENTRY_TYPE, 7, VARIABLE_ENTRY_SIZE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 0, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 1, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 2, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 3, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 4, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 5, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 6, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 7, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 8, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 9, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 10, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 11, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 12, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 13, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 14, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 15, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 16, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 17, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 18, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 19, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 20, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 21, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 22, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 23, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 24, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 25, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 26, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 27, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 28, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 29, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { MONSTER_ENTRY_TYPE, 30, MONSTER_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 0, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 1, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 2, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 3, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 4, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 5, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 6, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 7, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 8, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 9, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 10, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 11, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 12, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { LARGE_ENTRY_TYPE, 13, LARGE_ENTRY_SIZE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE } + }; + + if ( cache_ptr == NULL ) { + + pass = FALSE; + failure_mssg = "cache_ptr NULL on entry to flush ops test."; + } + else if ( ( cache_ptr->index_len != 0 ) || + ( cache_ptr->index_size != 0 ) ) { + + pass = FALSE; + failure_mssg = "cache not empty at start of flush ops eviction test."; + } + else if ( ( cache_ptr->max_cache_size != (2 * 1024 * 1024 ) ) || + ( cache_ptr->min_clean_size != (1 * 1024 * 1024 ) ) ) { + + pass = FALSE; + failure_mssg = "unexpected cache config at start of flush op eviction test."; + + } else { + + /* set min clean size to zero for this test as it simplifies + * computing the expected cache size after each operation. + */ + + cache_ptr->min_clean_size = 0; + } + + if ( pass ) { + + /* the basic idea in this test is to insert a bunch of entries + * with flush operations associated with them, and then load + * other entries into the cache until the cache is full. At + * that point, load yet more entries into the cache, and see + * if the flush operations are performed as expected. + * + * To make things a bit more interesting, we also include a + * couple of pins. + */ + + /* reset the stats before we start. If stats are enabled, we will + * check to see if they are as expected at the end. + */ + H5C_stats__reset(cache_ptr); + + + /* load a few entries with pin relationships and flush ops. + * Start by just loading the entries. + */ + + protect_entry(cache_ptr, VARIABLE_ENTRY_TYPE, 0); + unprotect_entry_with_size_change(cache_ptr, VARIABLE_ENTRY_TYPE, 0, + H5C__DIRTIED_FLAG | H5C__SIZE_CHANGED_FLAG, + (VARIABLE_ENTRY_SIZE / 2)); + + protect_entry(cache_ptr, VARIABLE_ENTRY_TYPE, 1); + unprotect_entry_with_size_change(cache_ptr, VARIABLE_ENTRY_TYPE, 1, + H5C__NO_FLAGS_SET, 0); + + protect_entry(cache_ptr, VARIABLE_ENTRY_TYPE, 2); + unprotect_entry_with_size_change(cache_ptr, VARIABLE_ENTRY_TYPE, 2, + H5C__NO_FLAGS_SET, 0); + + protect_entry(cache_ptr, VARIABLE_ENTRY_TYPE, 3); + unprotect_entry_with_size_change(cache_ptr, VARIABLE_ENTRY_TYPE, 3, + H5C__DIRTIED_FLAG | H5C__SIZE_CHANGED_FLAG, + (VARIABLE_ENTRY_SIZE / 2)); + + protect_entry(cache_ptr, VARIABLE_ENTRY_TYPE, 4); + unprotect_entry_with_size_change(cache_ptr, VARIABLE_ENTRY_TYPE, 4, + H5C__DIRTIED_FLAG | H5C__SIZE_CHANGED_FLAG, + (VARIABLE_ENTRY_SIZE / 2)); + + protect_entry(cache_ptr, VARIABLE_ENTRY_TYPE, 5); + unprotect_entry_with_size_change(cache_ptr, VARIABLE_ENTRY_TYPE, 5, + H5C__DIRTIED_FLAG | H5C__SIZE_CHANGED_FLAG, + (VARIABLE_ENTRY_SIZE / 2)); + + protect_entry(cache_ptr, VARIABLE_ENTRY_TYPE, 6); + unprotect_entry_with_size_change(cache_ptr, VARIABLE_ENTRY_TYPE, 6, + H5C__NO_FLAGS_SET, 0); + + protect_entry(cache_ptr, VARIABLE_ENTRY_TYPE, 7); + unprotect_entry_with_size_change(cache_ptr, VARIABLE_ENTRY_TYPE, 7, + H5C__NO_FLAGS_SET, 0); + + if ( ( cache_ptr->index_len != 8 ) || + ( cache_ptr->index_size != (4 * (VARIABLE_ENTRY_SIZE / 2)) + + (4 * VARIABLE_ENTRY_SIZE) ) ) { + + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 1."; + } + } + + if ( pass ) { + + /* Now set up the pinning relationships: + * + * Briefly, (VET, 0) is pinned by (VET, 1), (VET, 2), and (VET, 3) + * (VET, 7) is pinned by (VET, 3), and (VET, 5) + */ + create_pinned_entry_dependency(cache_ptr, VARIABLE_ENTRY_TYPE, 1, + VARIABLE_ENTRY_TYPE, 0); + create_pinned_entry_dependency(cache_ptr, VARIABLE_ENTRY_TYPE, 2, + VARIABLE_ENTRY_TYPE, 0); + create_pinned_entry_dependency(cache_ptr, VARIABLE_ENTRY_TYPE, 3, + VARIABLE_ENTRY_TYPE, 0); + create_pinned_entry_dependency(cache_ptr, VARIABLE_ENTRY_TYPE, 3, + VARIABLE_ENTRY_TYPE, 7); + create_pinned_entry_dependency(cache_ptr, VARIABLE_ENTRY_TYPE, 5, + VARIABLE_ENTRY_TYPE, 7); + + /* Next, set up the flush operations: + * + * Briefly, (VET, 1) dirties (VET, 0) + * resizes (VET, 0) to 3/4 VARIABLE_ENTRY_SIZE + * + * (VET, 2) dirties (VET, 0) + * resizes (VET, 0) to VARIABLE_ENTRY_SIZE + * renames (VET, 0) to its alternate address + * + * (VET, 3) dirties (VET, 0) + * resizes itself to VARIABLE_ENTRY_SIZE + * + * (VET, 7) dirties (VET, 6) + */ + add_flush_op(VARIABLE_ENTRY_TYPE, 1, FLUSH_OP__DIRTY, + VARIABLE_ENTRY_TYPE, 0, FALSE, 0); + add_flush_op(VARIABLE_ENTRY_TYPE, 1, FLUSH_OP__RESIZE, + VARIABLE_ENTRY_TYPE, 0, FALSE, + 3 * VARIABLE_ENTRY_SIZE / 4); + + add_flush_op(VARIABLE_ENTRY_TYPE, 2, FLUSH_OP__DIRTY, + VARIABLE_ENTRY_TYPE, 0, FALSE, 0); + add_flush_op(VARIABLE_ENTRY_TYPE, 2, FLUSH_OP__RESIZE, + VARIABLE_ENTRY_TYPE, 0, FALSE, VARIABLE_ENTRY_SIZE); + add_flush_op(VARIABLE_ENTRY_TYPE, 2, FLUSH_OP__RENAME, + VARIABLE_ENTRY_TYPE, 0, FALSE, 0); + + add_flush_op(VARIABLE_ENTRY_TYPE, 3, FLUSH_OP__DIRTY, + VARIABLE_ENTRY_TYPE, 0, FALSE, 0); + add_flush_op(VARIABLE_ENTRY_TYPE, 3, FLUSH_OP__RESIZE, + VARIABLE_ENTRY_TYPE, 3, FALSE, VARIABLE_ENTRY_SIZE); + + add_flush_op(VARIABLE_ENTRY_TYPE, 7, FLUSH_OP__DIRTY, + VARIABLE_ENTRY_TYPE, 6, FALSE, 0); + } + + if ( pass ) { + + /* to summarize, at present the following variable size entries + * are in cache with the following characteristics: + * + * in + * entry: cache? size: dirty? pinned? pins: flush operations: + * + * (VET, 0) Y 5 KB Y Y - - + * + * (VET, 1) Y 10 KB N N 0 dirty (VET, 0), + * resize (VET, 0) to 7.5 KB + * + * (VET, 2) Y 10 KB N N 0 dirty (VET, 0) + * resize (VET, 0) to 10 KB + * rename (VET, 0) to its alternate address + * + * (VET, 3) Y 5 KB Y N 0, 7 dirty (VET, 0) + * resize (VET, 3) to 10 KB + * + * (VET, 4) Y 5 KB Y N - - + * + * (VET, 5) Y 5 KB Y N 7 - + * + * (VET, 6) Y 10 KB N N - - + * + * (VET, 7) Y 10 KB N Y - dirty (VET, 6) + * + * Recall that in this test bed, flush operations are excuted the + * first time the associated entry is flushed, and are then + * deleted. + */ + + /* Now fill up the cache with other, unrelated entries */ + for ( i = 0; i < 31; i++ ) + { + protect_entry(cache_ptr, MONSTER_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, MONSTER_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } + + for ( i = 0; i < 1; i++ ) + { + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } + + /* The cache should now be exactly full */ + if ( ( cache_ptr->index_len != 40 ) || + ( cache_ptr->index_size != 2 * 1024 * 1024 ) || + ( cache_ptr->index_size != ((4 * VARIABLE_ENTRY_SIZE / 2) + + (4 * VARIABLE_ENTRY_SIZE) + + (31 * MONSTER_ENTRY_SIZE) + + (1 * LARGE_ENTRY_SIZE)) ) ) { + + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 2."; + + } else { + + /* verify the expected status of all entries we have loaded to date: */ + num_large_entries = 1; + verify_entry_status(cache_ptr, + 0, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); + } + } + + + if ( pass ) { + + /* Now load a large entry. This should result in the eviction + * of (VET,1), and the increase in the size of (VET, 0) from .5 + * VARIABLE_ENTRY_SIZE to .75 VARIABLE_ENTRY_SIZE. + * + * The following table illustrates the intended state of affairs + * after the eviction: + * + * in + * entry: cache? size: dirty? pinned? pins: flush operations: + * + * (VET, 0) Y 7.5 KB Y Y - - + * + * (VET, 1) N 10 KB N N - - + * + * (VET, 2) Y 10 KB N N 0 dirty (VET, 0) + * resize (VET, 0) to 10 KB + * rename (VET, 0) to its alternate address + * + * (VET, 3) Y 5 KB Y N 0, 7 dirty (VET, 0) + * resize (VET, 3) to 10 KB + * + * (VET, 4) Y 5 KB Y N - - + * + * (VET, 5) Y 5 KB Y N 7 - + * + * (VET, 6) Y 10 KB N N - - + * + * (VET, 7) Y 10 KB Y Y - dirty (VET, 6) + * + * Start by updating the expected table for the expected changes in entry status: + */ + expected[0].size = 3 * VARIABLE_ENTRY_SIZE / 4; + expected[1].in_cache = FALSE; + expected[1].flushed = TRUE; + expected[1].destroyed = TRUE; + + num_large_entries = 2; + + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, 1); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, 1, + H5C__DIRTIED_FLAG, 0); + + if ( ( cache_ptr->index_len != 40 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (VARIABLE_ENTRY_SIZE) + + (VARIABLE_ENTRY_SIZE / 4) + + (LARGE_ENTRY_SIZE) ) || + ( cache_ptr->index_size != ((1 * 3 * VARIABLE_ENTRY_SIZE / 4 ) + + (3 * VARIABLE_ENTRY_SIZE / 2 ) + + (3 * VARIABLE_ENTRY_SIZE) + + (31 * MONSTER_ENTRY_SIZE) + + (2 * LARGE_ENTRY_SIZE)) ) ) { + + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 3."; + } + + /* verify entry status */ + verify_entry_status(cache_ptr, + 1, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); + } + + if ( pass ) { + + /* Now load another large entry. This should result in the eviction + * of (VET, 2), the increase in the size of (VET, 0) from .75 + * VARIABLE_ENTRY_SIZE to 1.0 VARIABLE_ENTRY_SIZE, and the renaming + * of (VET, 0) to its alternate address. + * + * The following table shows the expected states of the variable + * size entries after the test. + * + * in + * entry: cache? size: dirty? pinned? pins: flush operations: + * + * (VET, 0) Y 10 KB Y Y - - + * + * (VET, 1) N 10 KB N N - - + * + * (VET, 2) N 10 KB N N - - + * + * (VET, 3) Y 5 KB Y N 0, 7 dirty (VET, 0) + * resize (VET, 3) to 10 KB + * + * (VET, 4) Y 5 KB Y N - - + * + * (VET, 5) Y 5 KB Y N 7 - + * + * (VET, 6) Y 10 KB N N - - + * + * (VET, 7) Y 10 KB Y Y - dirty (VET, 6) + * + * Start by updating the expected table for the expected changes in entry status: + */ + expected[0].size = VARIABLE_ENTRY_SIZE; + expected[0].at_main_addr = FALSE; + expected[2].in_cache = FALSE; + expected[2].flushed = TRUE; + expected[2].destroyed = TRUE; + + num_large_entries = 3; + + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, 2); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, 2, + H5C__DIRTIED_FLAG, 0); + + if ( ( cache_ptr->index_len != 40 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (2 * VARIABLE_ENTRY_SIZE) + + (VARIABLE_ENTRY_SIZE / 2) + + (2 * LARGE_ENTRY_SIZE) ) || + ( cache_ptr->index_size != ((3 * VARIABLE_ENTRY_SIZE / 2) + + (3 * VARIABLE_ENTRY_SIZE) + + (31 * MONSTER_ENTRY_SIZE) + + (3 * LARGE_ENTRY_SIZE)) ) ) { + + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 4."; + } + + /* verify entry status */ + verify_entry_status(cache_ptr, + 2, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); + } + + if ( pass ) { + + /* load two more large entries. This should result in (VET, 3) being + * flushed, and increasing its size from 1/2 VARIABLE_ENTRY_SIZE to + * VARIABLE_ENTRY_SIZE. + * + * As a result of this size increase, the cache will have to look + * for another entry to evict. After flushing (VET, 4) and (VET, 5), + * it should evict (VET, 6), yielding the needed memory. + * + * The following table shows the expected states of the variable + * size entries after the test. + * + * in + * entry: cache? size: dirty? pinned? pins: flush operations: + * + * (VET, 0) Y 10 KB Y Y - - + * + * (VET, 1) N 10 KB N N - - + * + * (VET, 2) N 10 KB N N - - + * + * (VET, 3) Y 10 KB N N 0, 7 - + * + * (VET, 4) Y 5 KB N N - - + * + * (VET, 5) Y 5 KB N N 7 - + * + * (VET, 6) N 10 KB N N - - + * + * (VET, 7) Y 10 KB Y Y - dirty (VET, 6) + * + * Start by updating the expected table for the expected changes in entry status: + */ + + expected[3].size = VARIABLE_ENTRY_SIZE; + expected[3].is_dirty = FALSE; + expected[3].flushed = TRUE; + expected[4].is_dirty = FALSE; + expected[4].flushed = TRUE; + expected[5].is_dirty = FALSE; + expected[5].flushed = TRUE; + expected[6].in_cache = FALSE; + expected[6].flushed = TRUE; + expected[6].destroyed = TRUE; + + num_large_entries = 5; + + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, 3); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, 3, + H5C__DIRTIED_FLAG, 0); + + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, 4); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, 4, + H5C__DIRTIED_FLAG, 0); + + /* verify cache size */ + if ( ( cache_ptr->index_len != 41 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (3 * VARIABLE_ENTRY_SIZE) + + (1 * VARIABLE_ENTRY_SIZE ) + /* size increases of (VET, 0) & (VET, 3) */ + (4 * LARGE_ENTRY_SIZE) ) || + ( cache_ptr->index_size != ((2 * VARIABLE_ENTRY_SIZE / 2) + + (3 * VARIABLE_ENTRY_SIZE) + + (31 * MONSTER_ENTRY_SIZE) + + (5 * LARGE_ENTRY_SIZE)) ) ) { + + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 5."; + } + + /* verify entry status */ + verify_entry_status(cache_ptr, + 3, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); + } + + if ( pass ) { + + /* now touch all the non VARIABLE_ENTRY_TYPE entries in the + * cache to bring all the VARIABLE_ENTRY_TYPE entries to the + * end of the LRU list. + * + * Note that we don't have to worry about (VET, 0) and (VET, 7) + * as they are pinned and thus not in the LRU list to begin with. + */ + for ( i = 0; i < 31; i++ ) + { + protect_entry(cache_ptr, MONSTER_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, MONSTER_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } + + for ( i = 0; i < 5; i++ ) + { + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } + + /* verify cache size */ + if ( ( cache_ptr->index_len != 41 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (2 * VARIABLE_ENTRY_SIZE) + + (4 * LARGE_ENTRY_SIZE) ) ) { + + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 6."; + } + + /* verify entry status */ + verify_entry_status(cache_ptr, + 4, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); + } + + if ( pass ) { + + /* Now load three more large entries. This should result + * in the eviction of (VET, 3), and the unpinning of (VET, 0) + * + * The following table shows the expected states of the variable + * size entries after the test. + * + * in + * entry: cache? size: dirty? pinned? pins: flush operations: + * + * (VET, 0) Y 10 KB Y N - - + * + * (VET, 1) N 10 KB N N - - + * + * (VET, 2) N 10 KB N N - - + * + * (VET, 3) N 10 KB N N - - + * + * (VET, 4) Y 5 KB N N - - + * + * (VET, 5) Y 5 KB N N 7 - + * + * (VET, 6) N 10 KB N N - - + * + * (VET, 7) Y 10 KB Y Y - dirty (VET, 6) + * + * Start by updating the expected table for the expected changes in entry status: + */ + + expected[0].is_pinned = FALSE; + expected[3].in_cache = FALSE; + expected[3].destroyed = TRUE; + + num_large_entries = 8; + + for ( i = 5; i < 8; i++ ) + { + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } + + /* verify cache size */ + if ( ( cache_ptr->index_len != 43 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (3 * VARIABLE_ENTRY_SIZE) + + (7 * LARGE_ENTRY_SIZE) ) || + ( cache_ptr->index_size != ((2 * VARIABLE_ENTRY_SIZE / 2) + + (2 * VARIABLE_ENTRY_SIZE) + + (31 * MONSTER_ENTRY_SIZE) + + (8 * LARGE_ENTRY_SIZE)) ) ) { + + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 7."; + } + + /* verify entry status */ + verify_entry_status(cache_ptr, + 5, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); + } + + if ( pass ) { + + /* load another large entry. (VET, 4) should be evicted. + * + * The following table shows the expected states of the variable + * size entries after the test. + * + * in + * entry: cache? size: dirty? pinned? pins: flush operations: + * + * (VET, 0) Y 10 KB Y N - - + * + * (VET, 1) N 10 KB N N - - + * + * (VET, 2) N 10 KB N N - - + * + * (VET, 3) N 10 KB N N - - + * + * (VET, 4) N 5 KB N N - - + * + * (VET, 5) Y 5 KB N N 7 - + * + * (VET, 6) N 10 KB N N - - + * + * (VET, 7) Y 10 KB Y Y - dirty (VET, 6) + * + * Start by updating the expected table for the expected changes in entry status: + */ + + expected[4].in_cache = FALSE; + expected[4].destroyed = TRUE; + + num_large_entries = 9; + + for ( i = 8; i < 9; i++ ) + { + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } + + /* verify cache size */ + if ( ( cache_ptr->index_len != 43 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (3 * VARIABLE_ENTRY_SIZE) - + (VARIABLE_ENTRY_SIZE / 2) + + (8 * LARGE_ENTRY_SIZE) ) || + ( cache_ptr->index_size != ((1 * VARIABLE_ENTRY_SIZE / 2) + + (2 * VARIABLE_ENTRY_SIZE) + + (31 * MONSTER_ENTRY_SIZE) + + (9 * LARGE_ENTRY_SIZE)) ) ) { + + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 8."; + } + + /* verify entry status */ + verify_entry_status(cache_ptr, + 6, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); + } + + if ( pass ) { + + /* Load another large entry. + * + * (VET, 5) should be evicted, and (VET, 7) should be unpinned. + * + * The following table shows the expected states of the variable + * size entries after the test. + * + * in + * entry: cache? size: dirty? pinned? pins: flush operations: + * + * (VET, 0) Y 10 KB Y N - - + * + * (VET, 1) N 10 KB N N - - + * + * (VET, 2) N 10 KB N N - - + * + * (VET, 3) N 10 KB N N - - + * + * (VET, 4) N 5 KB N N - - + * + * (VET, 5) N 5 KB N N - - + * + * (VET, 6) N 10 KB N N - - + * + * (VET, 7) Y 10 KB Y N - dirty (VET, 6) + * + * Start by updating the expected table for the expected changes in entry status: + */ + + expected[5].in_cache = FALSE; + expected[5].destroyed = TRUE; + expected[7].is_pinned = FALSE; + + num_large_entries = 10; + + for ( i = 9; i < 10; i++ ) + { + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } + + /* verify cache size */ + if ( ( cache_ptr->index_len != 43 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (4 * VARIABLE_ENTRY_SIZE) + + (9 * LARGE_ENTRY_SIZE) ) || + ( cache_ptr->index_size != ((2 * VARIABLE_ENTRY_SIZE) + + (31 * MONSTER_ENTRY_SIZE) + + (10 * LARGE_ENTRY_SIZE)) ) ) { pass = FALSE; - HDsnprintf(msg, (size_t)128, - "Unexpected cache len/size after cleanup in multi entry test #%d.", - test_num); - failure_mssg = msg; + failure_mssg = "unexpected size/len in flush op eviction test 9."; + } - } + /* verify entry status */ + verify_entry_status(cache_ptr, + 7, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); } - i = 0; - while ( ( pass ) && ( i < spec_size ) ) - { - base_addr = entries[spec[i].entry_type]; - entry_ptr = &(base_addr[spec[i].entry_index]); + if ( pass ) { - entry_ptr->loaded = FALSE; - entry_ptr->cleared = FALSE; - entry_ptr->flushed = FALSE; - entry_ptr->destroyed = FALSE; + /* Again, touch all the non VARIABLE_ENTRY_TYPE entries in the + * cache to bring all the VARIABLE_ENTRY_TYPE entries to the + * end of the LRU list. + * + * Both (VET, 0) and (VET, 7) have been unpinned, so they are + * now in the LRU list. + */ + for ( i = 0; i < 31; i++ ) + { + protect_entry(cache_ptr, MONSTER_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, MONSTER_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } - i++; - } + for ( i = 0; i < 10; i++ ) + { + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } - return; + /* verify cache size */ + if ( ( cache_ptr->index_len != 43 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (4 * VARIABLE_ENTRY_SIZE) + + (9 * LARGE_ENTRY_SIZE) ) || + ( cache_ptr->index_size != ((2 * VARIABLE_ENTRY_SIZE) + + (31 * MONSTER_ENTRY_SIZE) + + (10 * LARGE_ENTRY_SIZE)) ) ) { -} /* check_flush_cache__multi_entry_test() */ + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 10."; + } - -/*------------------------------------------------------------------------- - * Function: check_flush_cache__pe_multi_entry_test() - * - * Purpose: Run a multi entry flush cache test. - * - * Return: void - * - * Programmer: John Mainzer - * 4/5/06 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ + /* verify entry status */ + verify_entry_status(cache_ptr, + 8, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); + } + + if ( pass ) { + + /* load two more large entries. + * + * (VET, 0) should be flushed, but not evicted initially since it is dirty. + * + * (VET, 7) should be evicted, but (VET, 7) has an eviction operation that + * dirties (VET, 6). Since (VET, 6) is not in the cache, it will be loaded. + * Since this results in no net increase in free space, the cache will + * continue to attempt to create free space. + * + * The cache will then flush all the monster and large entries, but since they + * are all dirty, they will not be evicted. + * + * Finally, it will reach (VET, 0) again, and evict it on the second pass. + * This finally makes the necessary space. + * + * The following table shows the expected states of the variable + * size entries after the test. + * + * in + * entry: cache? size: dirty? pinned? pins: flush operations: + * + * (VET, 0) N 10 KB N N - - + * + * (VET, 1) N 10 KB N N - - + * + * (VET, 2) N 10 KB N N - - + * + * (VET, 3) N 10 KB N N - - + * + * (VET, 4) N 5 KB N N - - + * + * (VET, 5) N 5 KB N N - - + * + * (VET, 6) Y 10 KB Y N - - + * + * (VET, 7) N 10 KB N N - - + * + * Start by updating the expected table for the expected changes in entry status: + * + * Note that we reset the loaded, cleared, flushed, and destroyed fields of + * (VET,6) so we can track what is happening. + */ + base_addr = entries[VARIABLE_ENTRY_TYPE]; + entry_ptr = &(base_addr[6]); + entry_ptr->loaded = FALSE; + entry_ptr->cleared = FALSE; + entry_ptr->flushed = FALSE; + entry_ptr->destroyed = FALSE; + + expected[0].in_cache = FALSE; + expected[0].is_dirty = FALSE; + expected[0].flushed = TRUE; + expected[0].destroyed = TRUE; + expected[6].in_cache = TRUE; + expected[6].is_dirty = TRUE; + expected[6].loaded = TRUE; + expected[6].flushed = FALSE; + expected[6].destroyed = FALSE; + expected[7].in_cache = FALSE; + expected[7].flushed = TRUE; + expected[7].destroyed = TRUE; + + num_large_entries = 12; + + /* a newly loaded entry is not inserted in the cache until after space has been + * made for it. Thus (LET, 11) will not be flushed. + */ + for ( i = num_variable_entries; + i < num_variable_entries + num_monster_entries + num_large_entries - 1; + i++ ) + { + expected[i].is_dirty = FALSE; + expected[i].flushed = TRUE; + } -static void -check_flush_cache__pe_multi_entry_test(H5C_t * cache_ptr, - int test_num, - unsigned int flush_flags, - int spec_size, - struct pe_flush_cache_test_spec spec[]) -{ - /* const char * fcn_name = "check_flush_cache__pe_multi_entry_test"; */ - static char msg[128]; - herr_t result; - int i; - int j; - size_t total_entry_size = 0; - test_entry_t * base_addr; - test_entry_t * entry_ptr; + for ( i = 10; i < 12; i++ ) + { + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } - if ( cache_ptr == NULL ) { + /* verify cache size */ + if ( ( cache_ptr->index_len != 44 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (5 * VARIABLE_ENTRY_SIZE) + + (11 * LARGE_ENTRY_SIZE) ) || + ( cache_ptr->index_size != ((1 * VARIABLE_ENTRY_SIZE) + + (31 * MONSTER_ENTRY_SIZE) + + (12 * LARGE_ENTRY_SIZE)) ) ) { - pass = FALSE; - HDsnprintf(msg, (size_t)128, - "cache_ptr NULL on entry to pe multi entry test #%d.", - test_num); - failure_mssg = msg; + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 11."; + } + + /* verify entry status */ + verify_entry_status(cache_ptr, + 9, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); } - else if ( ( cache_ptr->index_len != 0 ) || - ( cache_ptr->index_size != 0 ) ) { - pass = FALSE; + if ( pass ) { - HDsnprintf(msg, (size_t)128, - "cache not empty at beginning of pe multi entry test #%d.", - test_num); - failure_mssg = msg; - } - else if ( ( spec_size < 1 ) || ( spec == NULL ) ) { + /* Again, touch all the non VARIABLE_ENTRY_TYPE entries in the + * cache to bring the last remaining VARIABLE_ENTRY_TYPE entry to the + * end of the LRU list. + */ + for ( i = 0; i < num_monster_entries; i++ ) + { + protect_entry(cache_ptr, MONSTER_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, MONSTER_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } - pass = FALSE; - HDsnprintf(msg, (size_t)128, - "missing/bad test spec on entry to pe multi entry test #%d.", - test_num); - failure_mssg = msg; - } + for ( i = 0; i < num_large_entries; i++ ) + { + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } - i = 0; - while ( ( pass ) && ( i < spec_size ) ) - { - if ( ( spec[i].entry_num != i ) || - ( spec[i].entry_type < 0 ) || - ( spec[i].entry_type >= NUMBER_OF_ENTRY_TYPES ) || - ( spec[i].entry_index < 0 ) || - ( spec[i].entry_index > max_indices[spec[i].entry_type] ) || - ( spec[i].num_pins < 0 ) || - ( spec[i].num_pins > MAX_PINS ) ) { + /* update the expected array to mark all these entries dirty again. */ + for ( i = num_variable_entries; + i < num_variable_entries + num_monster_entries + num_large_entries - 1; + i++ ) + { + expected[i].is_dirty = TRUE; + } + + /* verify cache size */ + if ( ( cache_ptr->index_len != 44 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (5 * VARIABLE_ENTRY_SIZE) + + (11 * LARGE_ENTRY_SIZE) ) || + ( cache_ptr->index_size != ((1 * VARIABLE_ENTRY_SIZE) + + (31 * MONSTER_ENTRY_SIZE) + + (12 * LARGE_ENTRY_SIZE)) ) ) { pass = FALSE; - HDsnprintf(msg, (size_t)128, - "bad data in spec[%d] on entry to pe multi entry test #%d.", - i, test_num); - failure_mssg = msg; - } - i++; - } + failure_mssg = "unexpected size/len in flush op eviction test 12."; + } - i = 0; - while ( ( pass ) && ( i < spec_size ) ) - { - if ( spec[i].insert_flag ) { + /* verify entry status */ + verify_entry_status(cache_ptr, + 10, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); + } + + if ( pass ) { + + /* Load two more large entries. + * + * Since (VET, 6) is dirty, at first this will just cause (VET, 6) to be flushed. + * + * But all other entries in the cache are dirty, so the cache will flush them all, + * and then evict (VET, 6) on the second pass. + * + * The following table shows the expected states of the variable + * size entries after the test. + * + * in + * entry: cache? size: dirty? pinned? pins: flush operations: + * + * (VET, 0) N 10 KB N N - - + * + * (VET, 1) N 10 KB N N - - + * + * (VET, 2) N 10 KB N N - - + * + * (VET, 3) N 10 KB N N - - + * + * (VET, 4) N 5 KB N N - - + * + * (VET, 5) N 5 KB N N - - + * + * (VET, 6) N 10 KB N N - - + * + * (VET, 7) N 10 KB N N - - + * + * Start by updating the expected table for the expected changes in entry status: + */ - insert_entry(cache_ptr, spec[i].entry_type, spec[i].entry_index, - spec[i].dirty_flag, spec[i].flags); + expected[6].in_cache = FALSE; + expected[6].is_dirty = FALSE; + expected[6].flushed = TRUE; + expected[6].destroyed = TRUE; - } else { + num_large_entries = 14; - protect_entry(cache_ptr, spec[i].entry_type, spec[i].entry_index); + /* a newly loaded entry is not inserted in the cache until after space has been + * made for it. Thus (LET, 13) will not be flushed. + */ + for ( i = num_variable_entries; + i < num_variable_entries + num_monster_entries + num_large_entries - 1; + i++ ) + { + expected[i].is_dirty = FALSE; + expected[i].flushed = TRUE; + } - unprotect_entry(cache_ptr, spec[i].entry_type, spec[i].entry_index, - (int)(spec[i].dirty_flag), spec[i].flags); - } + for ( i = 12; i < 14; i++ ) + { + protect_entry(cache_ptr, LARGE_ENTRY_TYPE, i); + unprotect_entry_with_size_change(cache_ptr, LARGE_ENTRY_TYPE, i, + H5C__DIRTIED_FLAG, 0); + } - total_entry_size += entry_sizes[spec[i].entry_type]; + /* verify cache size */ + if ( ( cache_ptr->index_len != 45 ) || + ( cache_ptr->index_size != (2 * 1024 * 1024) - + (6 * VARIABLE_ENTRY_SIZE) + + (13 * LARGE_ENTRY_SIZE) ) || + ( cache_ptr->index_size != ((31 * MONSTER_ENTRY_SIZE) + + (14 * LARGE_ENTRY_SIZE)) ) ) { - for ( j = 0; j < spec[i].num_pins; j++ ) - { - create_pinned_entry_dependency(cache_ptr, - spec[i].entry_type, - spec[i].entry_index, - spec[i].pin_type[j], - spec[i].pin_idx[j]); + pass = FALSE; + failure_mssg = "unexpected size/len in flush op eviction test 13."; } - i++; + /* verify entry status */ + verify_entry_status(cache_ptr, + 11, + (num_variable_entries + num_monster_entries + num_large_entries), + expected); } + /* at this point we have cycled all the variable size entries through the cache. + * + * flush the cache and end the test. + */ + if ( pass ) { - result = H5C_flush_cache(NULL, -1, -1, cache_ptr, flush_flags); + result = H5C_flush_cache(NULL, -1, -1, cache_ptr, + H5C__FLUSH_INVALIDATE_FLAG); if ( result < 0 ) { pass = FALSE; - HDsnprintf(msg, (size_t)128, - "flush with flags 0x%x failed in pe multi entry test #%d.", - flush_flags, test_num); - failure_mssg = msg; + failure_mssg = "Cache flush invalidate failed after flush op eviction test"; } - } - - i = 0; - while ( ( pass ) && ( i < spec_size ) ) - { - base_addr = entries[spec[i].entry_type]; - entry_ptr = &(base_addr[spec[i].entry_index]); + else if ( ( cache_ptr->index_len != 0 ) || + ( cache_ptr->index_size != 0 ) ) { - if ( ( entry_ptr->loaded != spec[i].expected_loaded ) || - ( entry_ptr->cleared != spec[i].expected_cleared ) || - ( entry_ptr->flushed != spec[i].expected_flushed ) || - ( entry_ptr->destroyed != spec[i].expected_destroyed ) ) { + pass = FALSE; + failure_mssg = "Unexpected cache len/size after cleanup of flush op eviction test"; -#if 0 /* This is useful debugging code. Lets keep it around. */ + } + } - HDfprintf(stdout, - "loaded = %d(%d), clrd = %d(%d), flshd = %d(%d), dest = %d(%d)\n", - (int)(entry_ptr->loaded), - (int)(spec[i].expected_loaded), - (int)(entry_ptr->cleared), - (int)(spec[i].expected_cleared), - (int)(entry_ptr->flushed), - (int)(spec[i].expected_flushed), - (int)(entry_ptr->destroyed), - (int)(spec[i].expected_destroyed)); +#if H5C_COLLECT_CACHE_STATS + /* If we are collecting stats, check to see if we get the expected + * values. + * + * Testing the stats code is fairly new, but given the extent + * to which I find myself depending on the stats, I've decided + * to start testing the stats whenever it is convenient to do + * so. + */ + if ( pass ) { -#endif + if ( ( cache_ptr->insertions[VARIABLE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pinned_insertions[VARIABLE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->clears[VARIABLE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->flushes[VARIABLE_ENTRY_TYPE] != 14 ) || + ( cache_ptr->evictions[VARIABLE_ENTRY_TYPE] != 9 ) || + ( cache_ptr->renames[VARIABLE_ENTRY_TYPE] != 1 ) || + ( cache_ptr->entry_flush_renames[VARIABLE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->cache_flush_renames[VARIABLE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pins[VARIABLE_ENTRY_TYPE] != 2 ) || + ( cache_ptr->unpins[VARIABLE_ENTRY_TYPE] != 2 ) || + ( cache_ptr->dirty_pins[VARIABLE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pinned_flushes[VARIABLE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pinned_clears[VARIABLE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->size_increases[VARIABLE_ENTRY_TYPE] != 3 ) || + ( cache_ptr->size_decreases[VARIABLE_ENTRY_TYPE] != 4 ) || + ( cache_ptr->entry_flush_size_changes[VARIABLE_ENTRY_TYPE] != 1 ) || + ( cache_ptr->cache_flush_size_changes[VARIABLE_ENTRY_TYPE] != 0 ) ) { pass = FALSE; - HDsnprintf(msg, (size_t)128, - "Bad status on entry %d after flush in pe multi entry test #%d.", - i, test_num); - failure_mssg = msg; + failure_mssg = "Unexpected variable size entry stats."; } - i++; } if ( pass ) { - if ( ( ( (flush_flags & H5C__FLUSH_INVALIDATE_FLAG) == 0 ) - && - ( ( cache_ptr->index_len != spec_size ) - || - ( cache_ptr->index_size != total_entry_size ) - ) - ) - || - ( ( (flush_flags & H5C__FLUSH_INVALIDATE_FLAG) != 0 ) - && - ( ( cache_ptr->index_len != 0 ) - || - ( cache_ptr->index_size != 0 ) - ) - ) - ) { + if ( ( cache_ptr->insertions[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pinned_insertions[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->clears[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->flushes[LARGE_ENTRY_TYPE] != 38 ) || + ( cache_ptr->evictions[LARGE_ENTRY_TYPE] != 14 ) || + ( cache_ptr->renames[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->entry_flush_renames[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->cache_flush_renames[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pins[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->unpins[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->dirty_pins[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pinned_flushes[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pinned_clears[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->size_increases[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->size_decreases[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->entry_flush_size_changes[LARGE_ENTRY_TYPE] != 0 ) || + ( cache_ptr->cache_flush_size_changes[LARGE_ENTRY_TYPE] != 0 ) ) { pass = FALSE; - HDsnprintf(msg, (size_t)128, - "Unexpected cache len/size after flush in pe multi entry test #%d.", - test_num); - failure_mssg = msg; + failure_mssg = "Unexpected monster entry stats."; } } - /* clean up the cache to prep for the next test */ if ( pass ) { - result = H5C_flush_cache(NULL, -1, -1, cache_ptr, - H5C__FLUSH_INVALIDATE_FLAG); - - if ( result < 0 ) { - - pass = FALSE; - HDsnprintf(msg, (size_t)128, - "Flush failed on cleanup in pe multi entry test #%d.", - test_num); - failure_mssg = msg; - } - else if ( ( cache_ptr->index_len != 0 ) || - ( cache_ptr->index_size != 0 ) ) { + if ( ( cache_ptr->insertions[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pinned_insertions[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->clears[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->flushes[MONSTER_ENTRY_TYPE] != 93 ) || + ( cache_ptr->evictions[MONSTER_ENTRY_TYPE] != 31 ) || + ( cache_ptr->renames[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->entry_flush_renames[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->cache_flush_renames[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pins[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->unpins[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->dirty_pins[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pinned_flushes[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->pinned_clears[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->size_increases[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->size_decreases[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->entry_flush_size_changes[MONSTER_ENTRY_TYPE] != 0 ) || + ( cache_ptr->cache_flush_size_changes[MONSTER_ENTRY_TYPE] != 0 ) ) { pass = FALSE; - HDsnprintf(msg, (size_t)128, - "Unexpected cache len/size after cleanup in pe multi entry test #%d.", - test_num); - failure_mssg = msg; - + failure_mssg = "Unexpected monster entry stats."; } } +#endif /* H5C_COLLECT_CACHE_STATS */ - i = 0; - while ( ( pass ) && ( i < spec_size ) ) - { - base_addr = entries[spec[i].entry_type]; - entry_ptr = &(base_addr[spec[i].entry_index]); - - entry_ptr->loaded = FALSE; - entry_ptr->cleared = FALSE; - entry_ptr->flushed = FALSE; - entry_ptr->destroyed = FALSE; + if ( pass ) { - i++; + reset_entries(); } return; -} /* check_flush_cache__pe_multi_entry_test() */ +} /* check_flush_cache__flush_op_eviction_test() */ /*------------------------------------------------------------------------- @@ -6462,6 +11880,8 @@ check_flush_cache__single_entry_test(H5C_t * cache_ptr, ( entry_ptr->flushed != expected_flushed ) || ( entry_ptr->destroyed != expected_destroyed ) ) { +#if 0 /* This is useful debugging code -- lets keep it for a while */ + HDfprintf(stdout, "loaded = %d(%d), clrd = %d(%d), flshd = %d(%d), dest = %d(%d)\n", (int)(entry_ptr->loaded), @@ -6472,7 +11892,7 @@ check_flush_cache__single_entry_test(H5C_t * cache_ptr, (int)expected_flushed, (int)(entry_ptr->destroyed), (int)expected_destroyed); - +#endif pass = FALSE; HDsnprintf(msg, (size_t)128, "Unexpected entry status after flush in single entry test #%d.", @@ -18740,6 +24160,10 @@ main(void) run_full_test = FALSE; #endif /* NDEBUG */ +#if 0 + run_full_test = TRUE; +#endif + #if 1 smoke_check_1(); smoke_check_2(); @@ -18750,7 +24174,7 @@ main(void) smoke_check_7(); smoke_check_8(); #endif -#if 1 + write_permitted_check(); check_insert_entry(); check_flush_cache(); @@ -18777,7 +24201,6 @@ main(void) check_auto_cache_resize_epoch_markers(); check_auto_cache_resize_input_errs(); check_auto_cache_resize_aux_fcns(); -#endif return(0); diff --git a/test/cache_common.c b/test/cache_common.c index 3e9b596..dc19ac2 100644 --- a/test/cache_common.c +++ b/test/cache_common.c @@ -41,6 +41,7 @@ test_entry_t medium_entries[NUM_MEDIUM_ENTRIES]; test_entry_t large_entries[NUM_LARGE_ENTRIES]; test_entry_t huge_entries[NUM_HUGE_ENTRIES]; test_entry_t monster_entries[NUM_MONSTER_ENTRIES]; +test_entry_t variable_entries[NUM_VARIABLE_ENTRIES]; test_entry_t * entries[NUMBER_OF_ENTRY_TYPES] = { @@ -52,7 +53,8 @@ test_entry_t * entries[NUMBER_OF_ENTRY_TYPES] = medium_entries, large_entries, huge_entries, - monster_entries + monster_entries, + variable_entries }; const int32_t max_indices[NUMBER_OF_ENTRY_TYPES] = @@ -65,7 +67,8 @@ const int32_t max_indices[NUMBER_OF_ENTRY_TYPES] = NUM_MEDIUM_ENTRIES - 1, NUM_LARGE_ENTRIES - 1, NUM_HUGE_ENTRIES - 1, - NUM_MONSTER_ENTRIES - 1 + NUM_MONSTER_ENTRIES - 1, + NUM_VARIABLE_ENTRIES - 1 }; const size_t entry_sizes[NUMBER_OF_ENTRY_TYPES] = @@ -78,7 +81,8 @@ const size_t entry_sizes[NUMBER_OF_ENTRY_TYPES] = MEDIUM_ENTRY_SIZE, LARGE_ENTRY_SIZE, HUGE_ENTRY_SIZE, - MONSTER_ENTRY_SIZE + MONSTER_ENTRY_SIZE, + VARIABLE_ENTRY_SIZE }; const haddr_t base_addrs[NUMBER_OF_ENTRY_TYPES] = @@ -91,7 +95,8 @@ const haddr_t base_addrs[NUMBER_OF_ENTRY_TYPES] = MEDIUM_BASE_ADDR, LARGE_BASE_ADDR, HUGE_BASE_ADDR, - MONSTER_BASE_ADDR + MONSTER_BASE_ADDR, + VARIABLE_BASE_ADDR }; const haddr_t alt_base_addrs[NUMBER_OF_ENTRY_TYPES] = @@ -104,7 +109,8 @@ const haddr_t alt_base_addrs[NUMBER_OF_ENTRY_TYPES] = MEDIUM_ALT_BASE_ADDR, LARGE_ALT_BASE_ADDR, HUGE_ALT_BASE_ADDR, - MONSTER_ALT_BASE_ADDR + MONSTER_ALT_BASE_ADDR, + VARIABLE_ALT_BASE_ADDR }; const char * entry_type_names[NUMBER_OF_ENTRY_TYPES] = @@ -117,7 +123,8 @@ const char * entry_type_names[NUMBER_OF_ENTRY_TYPES] = "medium entries -- 1 KB", "large entries -- 4 KB", "huge entries -- 16 KB", - "monster entries -- 64 KB" + "monster entries -- 64 KB", + "variable entries -- 1B - 10KB" }; @@ -196,13 +203,21 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = (H5C_dest_func_t)monster_dest, (H5C_clear_func_t)monster_clear, (H5C_size_func_t)monster_size + }, + { + VARIABLE_ENTRY_TYPE, + (H5C_load_func_t)variable_load, + (H5C_flush_func_t)variable_flush, + (H5C_dest_func_t)variable_dest, + (H5C_clear_func_t)variable_clear, + (H5C_size_func_t)variable_size } }; static herr_t clear(H5F_t * f, void * thing, hbool_t dest); static herr_t destroy(H5F_t * f, void * thing); static herr_t flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, unsigned UNUSED * flags_ptr); static void * load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata1, void *udata2); static herr_t size(H5F_t * f, void * thing, size_t * size_ptr); @@ -267,18 +282,18 @@ addr_to_type_and_index(haddr_t addr, if ( addr >= PICO_ALT_BASE_ADDR ) { idx = (addr - alt_base_addrs[type]) / entry_sizes[type]; + HDassert( ( idx >= 0 ) && ( idx <= max_indices[type] ) ); HDassert( !((entries[type])[idx].at_main_addr) ); HDassert( addr == (entries[type])[idx].alt_addr ); } else { idx = (addr - base_addrs[type]) / entry_sizes[type]; + HDassert( ( idx >= 0 ) && ( idx <= max_indices[type] ) ); HDassert( (entries[type])[idx].at_main_addr ); HDassert( addr == (entries[type])[idx].main_addr ); } - HDassert( ( idx >= 0 ) && ( idx <= max_indices[type] ) ); - HDassert( addr == (entries[type])[idx].addr ); *type_ptr = type; @@ -388,6 +403,8 @@ check_write_permitted(const H5F_t UNUSED * f, * * Modifications: * + * Added variable_clear. -- JRM 8/30/06 + * *------------------------------------------------------------------------- */ @@ -410,7 +427,8 @@ clear(H5F_t * f, HDassert( entry_ptr == entry_ptr->self ); HDassert( entry_ptr->header.addr == entry_ptr->addr ); HDassert( entry_ptr->header.size == entry_ptr->size ); - HDassert( entry_ptr->size == entry_sizes[entry_ptr->type] ); + HDassert( ( entry_ptr->type == VARIABLE_ENTRY_TYPE ) || + ( entry_ptr->size == entry_sizes[entry_ptr->type] ) ); entry_ptr->header.is_dirty = FALSE; entry_ptr->is_dirty = FALSE; @@ -490,6 +508,14 @@ monster_clear(H5F_t * f, void * thing, hbool_t dest) return(clear(f, thing, dest)); } +herr_t +variable_clear(H5F_t * f, void * thing, hbool_t dest) +{ + HDassert ( ((test_entry_t *)thing)->type == VARIABLE_ENTRY_TYPE ); + return(clear(f, thing, dest)); +} + + /*------------------------------------------------------------------------- * Function: dest & friends @@ -510,6 +536,9 @@ monster_clear(H5F_t * f, void * thing, hbool_t dest) * pinned by the target entry, and to unpin those entries * if the reference count drops to zero. * + * JRM -- 8/30/06 + * Added variable_destroy(). + * *------------------------------------------------------------------------- */ @@ -534,9 +563,11 @@ destroy(H5F_t UNUSED * f, HDassert( entry_ptr == entry_ptr->self ); HDassert( entry_ptr->cache_ptr != NULL ); HDassert( entry_ptr->cache_ptr->magic == H5C__H5C_T_MAGIC ); - HDassert( entry_ptr->header.addr == entry_ptr->addr ); + HDassert( ( entry_ptr->header.destroy_in_progress ) || + ( entry_ptr->header.addr == entry_ptr->addr ) ); HDassert( entry_ptr->header.size == entry_ptr->size ); - HDassert( entry_ptr->size == entry_sizes[entry_ptr->type] ); + HDassert( ( entry_ptr->type == VARIABLE_ENTRY_TYPE ) || + ( entry_ptr->size == entry_sizes[entry_ptr->type] ) ); HDassert( !(entry_ptr->is_dirty) ); HDassert( !(entry_ptr->header.is_dirty) ); @@ -645,6 +676,13 @@ monster_dest(H5F_t * f, void * thing) return(destroy(f, thing)); } +herr_t +variable_dest(H5F_t * f, void * thing) +{ + HDassert ( ((test_entry_t *)thing)->type == VARIABLE_ENTRY_TYPE ); + return(destroy(f, thing)); +} + /*------------------------------------------------------------------------- * Function: flush & friends @@ -660,6 +698,12 @@ monster_dest(H5F_t * f, void * thing) * * Modifications: * + * JRM -- 8/30/06 + * Added variable_flush() and flags_ptr parameter. + * + * JRM -- 9/1/06 + * Added support for flush operations. + * *------------------------------------------------------------------------- */ @@ -668,8 +712,10 @@ flush(H5F_t *f, hid_t UNUSED dxpl_id, hbool_t dest, haddr_t addr, - void *thing) + void *thing, + unsigned * flags_ptr) { + int i; test_entry_t * entry_ptr; test_entry_t * base_addr; @@ -685,8 +731,26 @@ flush(H5F_t *f, HDassert( entry_ptr->header.addr == entry_ptr->addr ); HDassert( entry_ptr->addr == addr ); HDassert( entry_ptr->header.size == entry_ptr->size ); - HDassert( entry_ptr->size == entry_sizes[entry_ptr->type] ); + HDassert( ( entry_ptr->type == VARIABLE_ENTRY_TYPE ) || + ( entry_ptr->size == entry_sizes[entry_ptr->type] ) ); HDassert( entry_ptr->header.is_dirty == entry_ptr->is_dirty ); + HDassert( entry_ptr->cache_ptr != NULL ); + HDassert( entry_ptr->cache_ptr->magic == H5C__H5C_T_MAGIC ); + HDassert( entry_ptr->num_flush_ops >= 0 ); + HDassert( entry_ptr->num_flush_ops < MAX_FLUSH_OPS ); + + if ( entry_ptr->num_flush_ops > 0 ) { + + for ( i = 0; i < entry_ptr->num_flush_ops; i++ ) + { + execute_flush_op(entry_ptr->cache_ptr, + entry_ptr, + &((entry_ptr->flush_ops)[i]), + flags_ptr); + } + entry_ptr->num_flush_ops = 0; + entry_ptr->flush_op_self_resize_in_progress = FALSE; + } entry_ptr->flushed = TRUE; @@ -713,69 +777,87 @@ flush(H5F_t *f, } /* flush() */ -herr_t -pico_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing) +herr_t +pico_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, + void *thing, unsigned * flags_ptr) { HDassert ( ((test_entry_t *)thing)->type == PICO_ENTRY_TYPE ); - return(flush(f, dxpl_id, dest, addr, thing)); + return(flush(f, dxpl_id, dest, addr, thing, flags_ptr)); } herr_t -nano_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing) +nano_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, + void *thing, unsigned * flags_ptr) { HDassert ( ((test_entry_t *)thing)->type == NANO_ENTRY_TYPE ); - return(flush(f, dxpl_id, dest, addr, thing)); + return(flush(f, dxpl_id, dest, addr, thing, flags_ptr)); } herr_t -micro_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing) +micro_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, + void *thing, unsigned * flags_ptr) { HDassert ( ((test_entry_t *)thing)->type == MICRO_ENTRY_TYPE ); - return(flush(f, dxpl_id, dest, addr, thing)); + return(flush(f, dxpl_id, dest, addr, thing, flags_ptr)); } herr_t -tiny_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing) +tiny_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, + void *thing, unsigned * flags_ptr) { HDassert ( ((test_entry_t *)thing)->type == TINY_ENTRY_TYPE ); - return(flush(f, dxpl_id, dest, addr, thing)); + return(flush(f, dxpl_id, dest, addr, thing, flags_ptr)); } herr_t -small_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing) +small_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, + void *thing, unsigned * flags_ptr) { HDassert ( ((test_entry_t *)thing)->type == SMALL_ENTRY_TYPE ); - return(flush(f, dxpl_id, dest, addr, thing)); + return(flush(f, dxpl_id, dest, addr, thing, flags_ptr)); } herr_t -medium_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing) +medium_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, + void *thing, unsigned * flags_ptr) { HDassert ( ((test_entry_t *)thing)->type == MEDIUM_ENTRY_TYPE ); - return(flush(f, dxpl_id, dest, addr, thing)); + return(flush(f, dxpl_id, dest, addr, thing, flags_ptr)); } herr_t -large_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing) +large_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, + void *thing, unsigned * flags_ptr) { HDassert ( ((test_entry_t *)thing)->type == LARGE_ENTRY_TYPE ); - return(flush(f, dxpl_id, dest, addr, thing)); + return(flush(f, dxpl_id, dest, addr, thing, flags_ptr)); } herr_t -huge_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing) +huge_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, + void *thing, unsigned * flags_ptr) { HDassert ( ((test_entry_t *)thing)->type == HUGE_ENTRY_TYPE ); - return(flush(f, dxpl_id, dest, addr, thing)); + return(flush(f, dxpl_id, dest, addr, thing, flags_ptr)); } herr_t -monster_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing) +monster_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, + void *thing, unsigned * flags_ptr) { HDassert ( ((test_entry_t *)thing)->type == MONSTER_ENTRY_TYPE ); - return(flush(f, dxpl_id, dest, addr, thing)); + return(flush(f, dxpl_id, dest, addr, thing, flags_ptr)); +} + +herr_t +variable_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, + void *thing, unsigned * flags_ptr) +{ + HDassert ( ((test_entry_t *)thing)->type == VARIABLE_ENTRY_TYPE ); + return(flush(f, dxpl_id, dest, addr, thing, flags_ptr)); } + /*------------------------------------------------------------------------- * Function: load & friends @@ -791,6 +873,9 @@ monster_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing) * * Modifications: * + * JRM -- 8/30/06 + * Added variable_load(). + * *------------------------------------------------------------------------- */ @@ -819,7 +904,18 @@ load(H5F_t UNUSED *f, HDassert( entry_ptr->index <= max_indices[type] ); HDassert( entry_ptr == entry_ptr->self ); HDassert( entry_ptr->addr == addr ); - HDassert( entry_ptr->size == entry_sizes[type] ); +#if 1 /* JRM */ + if ( ! ( ( entry_ptr->type == VARIABLE_ENTRY_TYPE ) || + ( entry_ptr->size == entry_sizes[type] ) ) ) { + + HDfprintf(stdout, "entry type/index/size = %d/%d/%ld\n", + (int)(entry_ptr->type), + (int)(entry_ptr->index), + (long)(entry_ptr->size)); + } +#endif /* JRM */ + HDassert( ( entry_ptr->type == VARIABLE_ENTRY_TYPE ) || + ( entry_ptr->size == entry_sizes[type] ) ); entry_ptr->loaded = TRUE; @@ -895,6 +991,13 @@ monster_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, return(load(f, dxpl_id, addr, udata1, udata2)); } +void * +variable_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, + const void *udata1, void *udata2) +{ + return(load(f, dxpl_id, addr, udata1, udata2)); +} + /*------------------------------------------------------------------------- * Function: size & friends @@ -910,6 +1013,9 @@ monster_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, * * Modifications: * + * JRM -- 8/30/06 + * Added variable_size(). + * *------------------------------------------------------------------------- */ @@ -932,7 +1038,8 @@ size(H5F_t UNUSED * f, HDassert( entry_ptr == &(base_addr[entry_ptr->index]) ); HDassert( entry_ptr == entry_ptr->self ); HDassert( entry_ptr->header.addr == entry_ptr->addr ); - HDassert( entry_ptr->size == entry_sizes[entry_ptr->type] ); + HDassert( ( entry_ptr->type == VARIABLE_ENTRY_TYPE ) || \ + ( entry_ptr->size == entry_sizes[entry_ptr->type] ) ); *size_ptr = entry_ptr->size; @@ -1003,6 +1110,14 @@ monster_size(H5F_t * f, void * thing, size_t * size_ptr) return(size(f, thing, size_ptr)); } +herr_t +variable_size(H5F_t * f, void * thing, size_t * size_ptr) +{ + HDassert ( ((test_entry_t *)thing)->type == VARIABLE_ENTRY_TYPE ); + return(size(f, thing, size_ptr)); +} + + /**************************************************************************/ /**************************************************************************/ @@ -1011,6 +1126,72 @@ monster_size(H5F_t * f, void * thing, size_t * size_ptr) /**************************************************************************/ /*------------------------------------------------------------------------- + * Function: add_flush_op + * + * Purpose: Do noting if pass is FALSE on entry. + * + * Otherwise, add the specified flush operation to the + * target instance of test_entry_t. + * + * Return: void + * + * Programmer: John Mainzer + * 9/1/06 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +void +add_flush_op(int target_type, + int target_idx, + int op_code, + int type, + int idx, + hbool_t flag, + size_t new_size) +{ + int i; + test_entry_t * target_base_addr; + test_entry_t * target_entry_ptr; + + HDassert( ( 0 <= target_type ) && ( target_type < NUMBER_OF_ENTRY_TYPES ) ); + HDassert( ( 0 <= target_idx ) && + ( target_idx <= max_indices[target_type] ) ); + HDassert( ( 0 <= op_code ) && ( op_code <= FLUSH_OP__MAX_OP ) ); + HDassert( ( op_code != FLUSH_OP__RESIZE ) || + ( type == VARIABLE_ENTRY_TYPE ) ); + HDassert( ( 0 <= type ) && ( type < NUMBER_OF_ENTRY_TYPES ) ); + HDassert( ( 0 <= idx ) && ( idx <= max_indices[type] ) ); + HDassert( ( flag == TRUE ) || ( flag == FALSE ) ); + HDassert( new_size <= VARIABLE_ENTRY_SIZE ); + + if ( pass ) { + + target_base_addr = entries[target_type]; + target_entry_ptr = &(target_base_addr[target_idx]); + + HDassert( target_entry_ptr->index == target_idx ); + HDassert( target_entry_ptr->type == target_type ); + HDassert( target_entry_ptr == target_entry_ptr->self ); + HDassert( target_entry_ptr->num_flush_ops < MAX_FLUSH_OPS ); + + i = (target_entry_ptr->num_flush_ops)++; + (target_entry_ptr->flush_ops)[i].op_code = op_code; + (target_entry_ptr->flush_ops)[i].type = type; + (target_entry_ptr->flush_ops)[i].idx = idx; + (target_entry_ptr->flush_ops)[i].flag = flag; + (target_entry_ptr->flush_ops)[i].size = new_size; + + } + + return; + +} /* add_flush_op() */ + + +/*------------------------------------------------------------------------- * Function: create_pinned_entry_dependency * * Purpose: Do noting if pass is FALSE on entry. @@ -1093,6 +1274,194 @@ create_pinned_entry_dependency(H5C_t * cache_ptr, /*------------------------------------------------------------------------- + * Function: dirty_entry + * + * Purpose: Given a pointer to a cache, an entry type, and an index, + * dirty the target entry. + * + * If the dirty_pin parameter is true, verify that the + * target entry is in the cache and is pinned. If it + * isn't, scream and die. If it is, use the + * H5C_mark_pinned_entry_dirty() call to dirty it. + * + * Do nothing if pass is false on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 6/10/04 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +void +dirty_entry(H5C_t * cache_ptr, + int32_t type, + int32_t idx, + hbool_t dirty_pin) +{ + test_entry_t * base_addr; + test_entry_t * entry_ptr; + + HDassert( cache_ptr ); + HDassert( ( 0 <= type ) && ( type < NUMBER_OF_ENTRY_TYPES ) ); + HDassert( ( 0 <= idx ) && ( idx <= max_indices[type] ) ); + + if ( pass ) { + + if ( dirty_pin ) { + + if ( ! entry_in_cache(cache_ptr, type, idx) ) { + + pass = FALSE; + failure_mssg = "entry to be dirty pinned is not in cache."; + + } else { + + base_addr = entries[type]; + entry_ptr = &(base_addr[idx]); + + HDassert( entry_ptr->index == idx ); + HDassert( entry_ptr->type == type ); + HDassert( entry_ptr == entry_ptr->self ); + + if ( ! ( (entry_ptr->header).is_pinned ) ) { + + pass = FALSE; + failure_mssg = "entry to be dirty pinned is not pinned."; + + } else { + + mark_pinned_entry_dirty(cache_ptr, type, idx, FALSE, 0); + + } + } + } else { + + protect_entry(cache_ptr, type, idx); + unprotect_entry(cache_ptr, type, idx, TRUE, H5C__NO_FLAGS_SET); + } + } + + return; + +} /* dirty_entry() */ + + +/*------------------------------------------------------------------------- + * Function: execute_flush_op + * + * Purpose: Given a pointer to an instance of struct flush_op, execute + * it. + * + * Do nothing if pass is false on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 9/1/06 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +void +execute_flush_op(H5C_t * cache_ptr, + struct test_entry_t * entry_ptr, + struct flush_op * op_ptr, + unsigned * flags_ptr) +{ + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); + HDassert( entry_ptr != NULL ); + HDassert( entry_ptr = entry_ptr->self ); + HDassert( entry_ptr->header.addr == entry_ptr->addr ); + HDassert( ( entry_ptr->flush_op_self_resize_in_progress ) || + ( entry_ptr->header.size == entry_ptr->size ) ); + HDassert( op_ptr != NULL ); + HDassert( ( 0 <= entry_ptr->type ) && + ( entry_ptr->type < NUMBER_OF_ENTRY_TYPES ) ); + HDassert( ( 0 <= entry_ptr->index ) && + ( entry_ptr->index <= max_indices[entry_ptr->type] ) ); + HDassert( ( 0 <= op_ptr->type ) && + ( op_ptr->type < NUMBER_OF_ENTRY_TYPES ) ); + HDassert( ( 0 <= op_ptr->idx ) && + ( op_ptr->idx <= max_indices[op_ptr->type] ) ); + HDassert( ( op_ptr->flag == FALSE ) || ( op_ptr->flag == TRUE ) ); + HDassert( flags_ptr != NULL ); + + if ( pass ) { + + switch ( op_ptr->op_code ) + { + case FLUSH_OP__NO_OP: + break; + + case FLUSH_OP__DIRTY: + HDassert( ( entry_ptr->type != op_ptr->type ) || + ( entry_ptr->index != op_ptr->idx ) ); + + dirty_entry(cache_ptr, op_ptr->type, op_ptr->idx, op_ptr->flag); + break; + + case FLUSH_OP__RESIZE: + if ( ( entry_ptr->type == op_ptr->type ) && + ( entry_ptr->index == op_ptr->idx ) ) { + + /* the flush operation is acting on the entry to + * which it is attached. Handle this here: + */ + HDassert( entry_ptr->type == VARIABLE_ENTRY_TYPE ); + HDassert( op_ptr->size > 0 ); + HDassert( op_ptr->size <= VARIABLE_ENTRY_SIZE ); + + entry_ptr->size = op_ptr->size; + (*flags_ptr) |= H5C_CALLBACK__SIZE_CHANGED_FLAG; + entry_ptr->flush_op_self_resize_in_progress = TRUE; + + /* if the entry is in the process of being destroyed, + * set the header size to match the entry size so as + * to avoid a spurious failure in the destroy callback. + */ + if ( entry_ptr->header.destroy_in_progress ) { + + entry_ptr->header.size = entry_ptr->size; + } + + } else { + + /* change the size of some other entry */ + + resize_entry(cache_ptr, op_ptr->type, op_ptr->idx, + op_ptr->size, op_ptr->flag); + } + break; + + case FLUSH_OP__RENAME: + rename_entry(cache_ptr, op_ptr->type, op_ptr->idx, + op_ptr->flag); + break; + + default: + pass = FALSE; + failure_mssg = "Undefined flush op code."; + break; + } + } + + return; + +} /* execute_flush_op() */ + + +/*------------------------------------------------------------------------- * Function: entry_in_cache * * Purpose: Given a pointer to a cache, an entry type, and an index, @@ -1228,6 +1597,17 @@ reset_entries(void) base_addr[j].pin_idx[k] = -1; } + base_addr[j].num_flush_ops = 0; + for ( k = 0; k < MAX_FLUSH_OPS; k++ ) + { + base_addr[j].flush_ops[k].op_code = FLUSH_OP__NO_OP; + base_addr[j].flush_ops[k].type = -1; + base_addr[j].flush_ops[k].idx = -1; + base_addr[j].flush_ops[k].flag = FALSE; + base_addr[j].flush_ops[k].size = 0; + } + base_addr[j].flush_op_self_resize_in_progress = FALSE; + base_addr[j].loaded = FALSE; base_addr[j].cleared = FALSE; base_addr[j].flushed = FALSE; @@ -1244,6 +1624,91 @@ reset_entries(void) /*------------------------------------------------------------------------- + * Function: resize_entry + * + * Purpose: Given a pointer to a cache, an entry type, an index, and + * a size, set the size of the target entry to the size. Note + * that at present, the type of the entry must be + * VARIABLE_ENTRY_TYPE. + * + * If the resize_pin parameter is true, verify that the + * target entry is in the cache and is pinned. If it + * isn't, scream and die. If it is, use the + * H5C_mark_pinned_entry_dirty() call to resize it. + * + * Do nothing if pass is false on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 6/10/04 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +void +resize_entry(H5C_t * cache_ptr, + int32_t type, + int32_t idx, + size_t new_size, + hbool_t resize_pin) +{ + test_entry_t * base_addr; + test_entry_t * entry_ptr; + + HDassert( cache_ptr ); + HDassert( ( 0 <= type ) && ( type < NUMBER_OF_ENTRY_TYPES ) ); + HDassert( type == VARIABLE_ENTRY_TYPE ); + HDassert( ( 0 <= idx ) && ( idx <= max_indices[type] ) ); + HDassert( ( 0 < new_size ) && ( new_size <= entry_sizes[type] ) ); + + if ( pass ) { + + base_addr = entries[type]; + entry_ptr = &(base_addr[idx]); + + HDassert( entry_ptr->index == idx ); + HDassert( entry_ptr->type == type ); + HDassert( entry_ptr == entry_ptr->self ); + + if ( resize_pin ) { + + if ( ! entry_in_cache(cache_ptr, type, idx) ) { + + pass = FALSE; + failure_mssg = "entry to be resized pinned is not in cache."; + + } else { + + if ( ! ( (entry_ptr->header).is_pinned ) ) { + + pass = FALSE; + failure_mssg = "entry to be resized pinned is not pinned."; + + } else { + + mark_pinned_entry_dirty(cache_ptr, type, idx, + TRUE, new_size); + } + } + } else { + + protect_entry(cache_ptr, type, idx); + unprotect_entry_with_size_change(cache_ptr, type, idx, + H5C__SIZE_CHANGED_FLAG, new_size); + } + } + + return; + +} /* resize_entry() */ + + +/*------------------------------------------------------------------------- * Function: verify_clean * * Purpose: Verify that all cache entries are marked as clean. If any @@ -1282,7 +1747,8 @@ verify_clean(void) for ( j = 0; j <= max_index; j++ ) { - if ( ( base_addr[j].header.is_dirty ) || ( base_addr[j].is_dirty ) ) { + if ( ( base_addr[j].header.is_dirty ) || + ( base_addr[j].is_dirty ) ) { dirty_count++; } @@ -1302,6 +1768,248 @@ verify_clean(void) /*------------------------------------------------------------------------- + * Function: verify_entry_status + * + * Purpose: Verify that a list of entries have the expected status. + * If any discrepencies are found, set the failure message + * and set pass to FALSE. + * + * Do nothing if pass is FALSE on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 10/8/04 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +void +verify_entry_status(H5C_t * cache_ptr, + int tag, + int num_entries, + struct expected_entry_status expected[]) +{ + static char msg[128]; + hbool_t in_cache; + int i; + test_entry_t * entry_ptr; + test_entry_t * base_addr; + + i = 0; + while ( ( pass ) && ( i < num_entries ) ) + { + base_addr = entries[expected[i].entry_type]; + entry_ptr = &(base_addr[expected[i].entry_index]); + + if ( ( ! expected[i].in_cache ) && + ( ( expected[i].is_dirty ) || + ( expected[i].is_protected ) || + ( expected[i].is_pinned ) ) ) { + + pass = FALSE; + sprintf(msg, "Contradictory data in expected[%d].\n", i); + failure_mssg = msg; + } + + if ( pass ) { + + in_cache = entry_in_cache(cache_ptr, expected[i].entry_type, + expected[i].entry_index); + + if ( in_cache != expected[i].in_cache ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d, %d) in cache actual/expected = %d/%d.\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (int)in_cache, + (int)expected[i].in_cache); + failure_mssg = msg; + } + } + + if ( pass ) { + + if ( entry_ptr->size != expected[i].size ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d, %d) size actualexpected = %ld/%ld.\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (long)(entry_ptr->size), + (long)expected[i].size); + failure_mssg = msg; + } + } + + if ( ( pass ) && ( in_cache ) ) { + + if ( entry_ptr->header.size != expected[i].size ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d, %d) header size actual/expected = %ld/%ld.\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (long)(entry_ptr->header.size), + (long)expected[i].size); + failure_mssg = msg; + } + } + + if ( pass ) { + + if ( entry_ptr->at_main_addr != expected[i].at_main_addr ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d, %d) at main addr actual/expected = %d/%d.\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (int)(entry_ptr->at_main_addr), + (int)expected[i].at_main_addr); + failure_mssg = msg; + } + } + + if ( pass ) { + + if ( entry_ptr->is_dirty != expected[i].is_dirty ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d, %d) is_dirty actual/expected = %d/%d.\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (int)(entry_ptr->is_dirty), + (int)expected[i].is_dirty); + failure_mssg = msg; + } + } + + if ( ( pass ) && ( in_cache ) ) { + + if ( entry_ptr->header.is_dirty != expected[i].is_dirty ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d, %d) header is_dirty actual/expected = %d/%d.\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (int)(entry_ptr->header.is_dirty), + (int)expected[i].is_dirty); + failure_mssg = msg; + } + } + + if ( pass ) { + + if ( entry_ptr->is_protected != expected[i].is_protected ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d, %d) is_protected actual/expected = %d/%d.\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (int)(entry_ptr->is_protected), + (int)expected[i].is_protected); + failure_mssg = msg; + } + } + + if ( ( pass ) && ( in_cache ) ) { + + if ( entry_ptr->header.is_protected != expected[i].is_protected ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d, %d) header is_protected actual/expected = %d/%d.\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (int)(entry_ptr->header.is_protected), + (int)expected[i].is_protected); + failure_mssg = msg; + } + } + + if ( pass ) { + + if ( entry_ptr->is_pinned != expected[i].is_pinned ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d, %d) is_pinned actual/expected = %d/%d.\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (int)(entry_ptr->is_pinned), + (int)expected[i].is_pinned); + failure_mssg = msg; + } + } + + if ( ( pass ) && ( in_cache ) ) { + + if ( entry_ptr->header.is_pinned != expected[i].is_pinned ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d, %d) header is_pinned actual/expected = %d/%d.\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (int)(entry_ptr->header.is_pinned), + (int)expected[i].is_pinned); + failure_mssg = msg; + } + } + + if ( pass ) { + + if ( ( entry_ptr->loaded != expected[i].loaded ) || + ( entry_ptr->cleared != expected[i].cleared ) || + ( entry_ptr->flushed != expected[i].flushed ) || + ( entry_ptr->destroyed != expected[i].destroyed ) ) { + + pass = FALSE; + sprintf(msg, + "%d entry (%d,%d) loaded = %d(%d), clrd = %d(%d), flshd = %d(%d), dest = %d(%d)\n", + tag, + (int)expected[i].entry_type, + (int)expected[i].entry_index, + (int)(entry_ptr->loaded), + (int)(expected[i].loaded), + (int)(entry_ptr->cleared), + (int)(expected[i].cleared), + (int)(entry_ptr->flushed), + (int)(expected[i].flushed), + (int)(entry_ptr->destroyed), + (int)(expected[i].destroyed)); + failure_mssg = msg; + } + } + i++; + } /* while */ + + return; + +} /* verify_entry_status() */ + + +/*------------------------------------------------------------------------- * Function: verify_unprotected * * Purpose: Verify that no cache entries are marked as protected. If @@ -1649,8 +2357,7 @@ insert_entry(H5C_t * cache_ptr, pass = FALSE; failure_mssg = "error in H5C_insert()."; -#if 0 - /* This is useful debugging code. Lets keep it around. */ +#if 0 /* This is useful debugging code. Lets keep it around. */ HDfprintf(stdout, "result = %d\n", (int)result); HDfprintf(stdout, "entry_ptr->header.is_protected = %d\n", @@ -1934,7 +2641,9 @@ rename_entry(H5C_t * cache_ptr, if ( ! done ) { - if ( ( result < 0 ) || ( entry_ptr->header.addr != new_addr ) ) { + if ( ( result < 0 ) || + ( ( ! ( entry_ptr->header.destroy_in_progress ) ) && + ( entry_ptr->header.addr != new_addr ) ) ) { pass = FALSE; failure_mssg = "error in H5C_rename_entry()."; @@ -2241,6 +2950,130 @@ unprotect_entry(H5C_t * cache_ptr, /*------------------------------------------------------------------------- + * Function: unprotect_entry_with_size_change() + * + * Purpose: Version of unprotect_entry() that allow access to the new + * size change parameters in H5C_unprotect_entry() + * + * At present, only the sizes of VARIABLE_ENTRY_TYPE entries + * can be changed. Thus this function will scream and die + * if the H5C__SIZE_CHANGED_FLAG is set and the type is not + * VARIABLE_ENTRY_TYPE. + * + * Do nothing if pass is FALSE on entry. + * + * Return: void + * + * Programmer: John Mainzer + * 8/31/06 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +void +unprotect_entry_with_size_change(H5C_t * cache_ptr, + int32_t type, + int32_t idx, + unsigned int flags, + size_t new_size) +{ + /* const char * fcn_name = "unprotect_entry_with_size_change()"; */ + herr_t result; + hbool_t dirty_flag_set; + hbool_t pin_flag_set; + hbool_t unpin_flag_set; + hbool_t size_changed_flag_set; + test_entry_t * base_addr; + test_entry_t * entry_ptr; + + if ( pass ) { + + HDassert( cache_ptr ); + HDassert( ( 0 <= type ) && ( type < NUMBER_OF_ENTRY_TYPES ) ); + HDassert( ( 0 <= idx ) && ( idx <= max_indices[type] ) ); + HDassert( new_size <= entry_sizes[type] ); + + base_addr = entries[type]; + entry_ptr = &(base_addr[idx]); + + HDassert( entry_ptr->index == idx ); + HDassert( entry_ptr->type == type ); + HDassert( entry_ptr == entry_ptr->self ); + HDassert( entry_ptr->cache_ptr == cache_ptr ); + HDassert( entry_ptr->header.is_protected ); + HDassert( entry_ptr->is_protected ); + + dirty_flag_set = ((flags & H5C__DIRTIED_FLAG) != 0 ); + pin_flag_set = ((flags & H5C__PIN_ENTRY_FLAG) != 0 ); + unpin_flag_set = ((flags & H5C__UNPIN_ENTRY_FLAG) != 0 ); + size_changed_flag_set = ((flags & H5C__SIZE_CHANGED_FLAG) != 0 ); + + HDassert ( ! ( pin_flag_set && unpin_flag_set ) ); + HDassert ( ( ! pin_flag_set ) || ( ! (entry_ptr->is_pinned) ) ); + HDassert ( ( ! unpin_flag_set ) || ( entry_ptr->is_pinned ) ); + HDassert ( ( ! size_changed_flag_set ) || ( new_size > 0 ) ); + HDassert ( ( ! size_changed_flag_set ) || + ( type == VARIABLE_ENTRY_TYPE ) ); + + entry_ptr->is_dirty = (entry_ptr->is_dirty || dirty_flag_set); + + if ( size_changed_flag_set ) { + + entry_ptr->is_dirty = TRUE; + entry_ptr->size = new_size; + } + + result = H5C_unprotect(NULL, -1, -1, cache_ptr, &(types[type]), + entry_ptr->addr, (void *)entry_ptr, + flags, new_size); + + if ( ( result < 0 ) || + ( entry_ptr->header.is_protected ) || + ( entry_ptr->header.type != &(types[type]) ) || + ( entry_ptr->size != entry_ptr->header.size ) || + ( entry_ptr->addr != entry_ptr->header.addr ) ) { + + pass = FALSE; + failure_mssg = "error in H5C_unprotect()."; + + } + else + { + entry_ptr->is_protected = FALSE; + + if ( pin_flag_set ) { + + HDassert ( entry_ptr->header.is_pinned ); + entry_ptr->is_pinned = TRUE; + + } else if ( unpin_flag_set ) { + + HDassert ( ! ( entry_ptr->header.is_pinned ) ); + entry_ptr->is_pinned = FALSE; + + } + } + + HDassert( ((entry_ptr->header).type)->id == type ); + + if ( ( flags & H5C__DIRTIED_FLAG ) != 0 + && ( (flags & H5C__DELETED_FLAG) == 0 ) ) { + + HDassert( entry_ptr->header.is_dirty ); + HDassert( entry_ptr->is_dirty ); + } + } + + return; + +} /* unprotect_entry_with_size_change() */ + + +/*------------------------------------------------------------------------- * Function: row_major_scan_forward() * * Purpose: Do a sequence of inserts, protects, unprotects, renames, diff --git a/test/cache_common.h b/test/cache_common.h index c6c2a32..460661a 100644 --- a/test/cache_common.h +++ b/test/cache_common.h @@ -43,8 +43,9 @@ #define LARGE_ENTRY_TYPE 6 #define HUGE_ENTRY_TYPE 7 #define MONSTER_ENTRY_TYPE 8 +#define VARIABLE_ENTRY_TYPE 9 -#define NUMBER_OF_ENTRY_TYPES 9 +#define NUMBER_OF_ENTRY_TYPES 10 #define PICO_ENTRY_SIZE (size_t)1 #define NANO_ENTRY_SIZE (size_t)4 @@ -55,6 +56,7 @@ #define LARGE_ENTRY_SIZE (size_t)(4 * 1024) #define HUGE_ENTRY_SIZE (size_t)(16 * 1024) #define MONSTER_ENTRY_SIZE (size_t)(64 * 1024) +#define VARIABLE_ENTRY_SIZE (size_t)(10 * 1024) #define NUM_PICO_ENTRIES (10 * 1024) #define NUM_NANO_ENTRIES (10 * 1024) @@ -65,6 +67,7 @@ #define NUM_LARGE_ENTRIES (10 * 1024) #define NUM_HUGE_ENTRIES (10 * 1024) #define NUM_MONSTER_ENTRIES (10 * 1024) +#define NUM_VARIABLE_ENTRIES (10 * 1024) #define MAX_ENTRIES (10 * 1024) @@ -85,9 +88,11 @@ (LARGE_ENTRY_SIZE * NUM_LARGE_ENTRIES)) #define MONSTER_BASE_ADDR (haddr_t)(HUGE_BASE_ADDR + \ (HUGE_ENTRY_SIZE * NUM_HUGE_ENTRIES)) - -#define PICO_ALT_BASE_ADDR (haddr_t)(MONSTER_BASE_ADDR + \ +#define VARIABLE_BASE_ADDR (haddr_t)(MONSTER_BASE_ADDR + \ (MONSTER_ENTRY_SIZE * NUM_MONSTER_ENTRIES)) + +#define PICO_ALT_BASE_ADDR (haddr_t)(VARIABLE_BASE_ADDR + \ + (VARIABLE_ENTRY_SIZE * NUM_VARIABLE_ENTRIES)) #define NANO_ALT_BASE_ADDR (haddr_t)(PICO_ALT_BASE_ADDR + \ (PICO_ENTRY_SIZE * NUM_PICO_ENTRIES)) #define MICRO_ALT_BASE_ADDR (haddr_t)(NANO_ALT_BASE_ADDR + \ @@ -104,10 +109,75 @@ (LARGE_ENTRY_SIZE * NUM_LARGE_ENTRIES)) #define MONSTER_ALT_BASE_ADDR (haddr_t)(HUGE_ALT_BASE_ADDR + \ (HUGE_ENTRY_SIZE * NUM_HUGE_ENTRIES)) +#define VARIABLE_ALT_BASE_ADDR (haddr_t)(MONSTER_ALT_BASE_ADDR + \ + (MONSTER_ENTRY_SIZE * NUM_MONSTER_ENTRIES)) #define MAX_PINS 8 /* Maximum number of entries that can be * directly pinned by a single entry. */ + +#define FLUSH_OP__NO_OP 0 +#define FLUSH_OP__DIRTY 1 +#define FLUSH_OP__RESIZE 2 +#define FLUSH_OP__RENAME 3 +#define FLUSH_OP__MAX_OP 3 + +#define MAX_FLUSH_OPS 10 /* Maximum number of flush operations + * that can be associated with a + * cache entry. + */ + +typedef struct flush_op +{ + int op_code; /* integer op code indicating the + * operation to be performed. At + * present it must be one of: + * + * FLUSH_OP__NO_OP + * FLUSH_OP__DIRTY + * FLUSH_OP__RESIZE + * FLUSH_OP__RENAME + */ + int type; /* type code of the cache entry that + * is the target of the operation. + * This value is passed into the + * function implementing the flush + * operation. + */ + int idx; /* index of the cache entry that + * is the target of the operation. + * This value is passed into the + * function implementing the flush + * operation. + */ + hbool_t flag; /* boolean flag passed into the + * function implementing the flush + * operation. The meaning of the + * flag is dependant upon the flush + * operation: + * + * FLUSH_OP__DIRTY: TRUE iff the + * target is pinned, and is to + * be dirtied via the + * H5C_mark_pinned_entry_dirty() + * call. + * + * FLUSH_OP__RESIZE: TRUE iff the + * target is pinned, and is to + * be resized via the + * H5C_mark_pinned_entry_dirty() + * call. + * + * FLUSH_OP__RENAME: TRUE iff the + * target is to be renamed to + * its main address. + */ + size_t size; /* New target size in the + * FLUSH_OP__RENAME operation. + * Unused elsewhere. + */ +} flush_op; + typedef struct test_entry_t { H5C_cache_entry_t header; /* entry data used by the cache @@ -172,6 +242,32 @@ typedef struct test_entry_t int pin_idx[MAX_PINS]; /* array of the indicies of * entries pinned by this entry. */ + int num_flush_ops; /* integer field containing the + * number of flush operations to + * be executed when the entry is + * flushed. This value must lie in + * the closed interval + * [0, MAX_FLUSH_OPS]. + */ + struct flush_op flush_ops[MAX_FLUSH_OPS]; /* Array of instances + * of struct flush_op detailing the + * flush operations (if any) that + * are to be executed when the entry + * is flushed from the cache. + * + * num_flush_ops contains the number + * of valid entries in this array. + */ + hbool_t flush_op_self_resize_in_progress; /* Boolean flag + * that is set to TRUE iff this + * entry is being flushed, it has + * been resized by a resize flush + * op, and the flush function has + * not yet returned, This field is + * used to turn off overactive santity + * checking code that would otherwise + * cause a false test failure. + */ hbool_t loaded; /* entry has been loaded since the * last time it was reset. */ @@ -290,6 +386,42 @@ struct pe_flush_cache_test_spec hbool_t expected_destroyed; }; +struct fo_flush_entry_check +{ + int entry_num; + int entry_type; + int entry_index; + size_t expected_size; + hbool_t in_cache; + hbool_t at_main_addr; + hbool_t is_dirty; + hbool_t is_protected; + hbool_t is_pinned; + hbool_t expected_loaded; + hbool_t expected_cleared; + hbool_t expected_flushed; + hbool_t expected_destroyed; +}; + +struct fo_flush_cache_test_spec +{ + int entry_num; + int entry_type; + int entry_index; + hbool_t insert_flag; + unsigned int flags; + size_t new_size; + int num_pins; + int pin_type[MAX_PINS]; + int pin_idx[MAX_PINS]; + int num_flush_ops; + struct flush_op flush_ops[MAX_FLUSH_OPS]; + hbool_t expected_loaded; + hbool_t expected_cleared; + hbool_t expected_flushed; + hbool_t expected_destroyed; +}; + struct rename_entry_test_spec { int entry_type; @@ -298,6 +430,22 @@ struct rename_entry_test_spec hbool_t is_pinned; }; +struct expected_entry_status +{ + int entry_type; + int entry_index; + size_t size; + hbool_t in_cache; + hbool_t at_main_addr; + hbool_t is_dirty; + hbool_t is_protected; + hbool_t is_pinned; + hbool_t loaded; + hbool_t cleared; + hbool_t flushed; + hbool_t destroyed; +}; + @@ -344,6 +492,7 @@ herr_t medium_clear(H5F_t * f, void * thing, hbool_t dest); herr_t large_clear(H5F_t * f, void * thing, hbool_t dest); herr_t huge_clear(H5F_t * f, void * thing, hbool_t dest); herr_t monster_clear(H5F_t * f, void * thing, hbool_t dest); +herr_t variable_clear(H5F_t * f, void * thing, hbool_t dest); herr_t pico_dest(H5F_t * f, void * thing); @@ -355,26 +504,29 @@ herr_t medium_dest(H5F_t * f, void * thing); herr_t large_dest(H5F_t * f, void * thing); herr_t huge_dest(H5F_t * f, void * thing); herr_t monster_dest(H5F_t * f, void * thing); +herr_t variable_dest(H5F_t * f, void * thing); herr_t pico_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, unsigned * flags_ptr); herr_t nano_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, unsigned * flags_ptr); herr_t micro_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, unsigned * flags_ptr); herr_t tiny_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, unsigned * flags_ptr); herr_t small_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, unsigned * flags_ptr); herr_t medium_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, unsigned * flags_ptr); herr_t large_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, unsigned * flags_ptr); herr_t huge_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, unsigned * flags_ptr); herr_t monster_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing); + haddr_t addr, void *thing, unsigned * flags_ptr); +herr_t variable_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, + haddr_t addr, void *thing, unsigned * flags_ptr); void * pico_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, @@ -395,6 +547,8 @@ void * huge_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata1, void *udata2); void * monster_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata1, void *udata2); +void * variable_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, + const void *udata1, void *udata2); herr_t pico_size(H5F_t * f, void * thing, size_t * size_ptr); @@ -406,6 +560,7 @@ herr_t medium_size(H5F_t * f, void * thing, size_t * size_ptr); herr_t large_size(H5F_t * f, void * thing, size_t * size_ptr); herr_t huge_size(H5F_t * f, void * thing, size_t * size_ptr); herr_t monster_size(H5F_t * f, void * thing, size_t * size_ptr); +herr_t variable_size(H5F_t * f, void * thing, size_t * size_ptr); /* callback table extern */ @@ -414,6 +569,15 @@ extern const H5C_class_t types[NUMBER_OF_ENTRY_TYPES]; /* function declarations: */ +void add_flush_op(int target_type, + int target_idx, + int op_code, + int type, + int idx, + hbool_t flag, + size_t size); + + void addr_to_type_and_index(haddr_t addr, int32_t * type_ptr, int32_t * index_ptr); @@ -423,6 +587,11 @@ haddr_t type_and_index_to_addr(int32_t type, int32_t idx); #endif +void dirty_entry(H5C_t * cache_ptr, + int32_t type, + int32_t idx, + hbool_t dirty_pin); + void expunge_entry(H5C_t * cache_ptr, int32_t type, int32_t idx); @@ -462,8 +631,19 @@ void create_pinned_entry_dependency(H5C_t * cache_ptr, int pinned_type, int pinned_idx); +void execute_flush_op(H5C_t * cache_ptr, + struct test_entry_t * entry_ptr, + struct flush_op * op_ptr, + unsigned * flags_ptr); + void reset_entries(void); +void resize_entry(H5C_t * cache_ptr, + int32_t type, + int32_t idx, + size_t new_size, + hbool_t resize_pin); + H5C_t * setup_cache(size_t max_cache_size, size_t min_clean_size); void row_major_scan_forward(H5C_t * cache_ptr, @@ -571,7 +751,18 @@ void unprotect_entry(H5C_t * cache_ptr, int dirty, unsigned int flags); +void unprotect_entry_with_size_change(H5C_t * cache_ptr, + int32_t type, + int32_t idx, + unsigned int flags, + size_t new_size); + void verify_clean(void); +void verify_entry_status(H5C_t * cache_ptr, + int tag, + int num_entries, + struct expected_entry_status expected[]); + void verify_unprotected(void); -- cgit v0.12