summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Mainzer <mainzer@hdfgroup.org>2006-10-18 10:51:26 (GMT)
committerJohn Mainzer <mainzer@hdfgroup.org>2006-10-18 10:51:26 (GMT)
commit2d6bb5932951242d23ccef420a328a033f3b4efa (patch)
tree3650df339b604f381873f55dcb24af501a83bd0b
parentce30ee9b28e9b68de817845aa5bc965d35ca8967 (diff)
downloadhdf5-2d6bb5932951242d23ccef420a328a033f3b4efa.zip
hdf5-2d6bb5932951242d23ccef420a328a033f3b4efa.tar.gz
hdf5-2d6bb5932951242d23ccef420a328a033f3b4efa.tar.bz2
[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.
-rw-r--r--src/H5ACprivate.h4
-rw-r--r--src/H5B2cache.c29
-rw-r--r--src/H5Bcache.c10
-rw-r--r--src/H5C.c961
-rw-r--r--src/H5Cpkg.h61
-rw-r--r--src/H5Cprivate.h18
-rw-r--r--src/H5FScache.c20
-rw-r--r--src/H5Gnode.c10
-rw-r--r--src/H5HFcache.c29
-rw-r--r--src/H5HG.c11
-rw-r--r--src/H5HL.c10
-rw-r--r--src/H5Ocache.c10
-rw-r--r--test/cache.c5429
-rw-r--r--test/cache_common.c911
-rw-r--r--test/cache_common.h215
15 files changed, 7496 insertions, 232 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, <pvn@ncsa.uiuc.edu> 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;
@@ -4498,6 +4523,13 @@ check_flush_cache__pe_multi_entry_test(H5C_t * cache_ptr,
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;
@@ -4697,6 +4729,5392 @@ check_flush_cache__pe_multi_entry_test(H5C_t * cache_ptr,
/*-------------------------------------------------------------------------
+ * 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;
+ 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);
+ }
+
+ if ( pass ) {
+
+ /* 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);
+ }
+
+ 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);
+ }
+
+ /* 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;
+ failure_mssg = "unexpected size/len in flush op eviction test 10.";
+ }
+
+ /* 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;
+ }
+
+ 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);
+ }
+
+ /* 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;
+ 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);
+ }
+
+ if ( pass ) {
+
+ /* 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);
+ }
+
+ 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);
+ }
+
+ /* 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;
+ failure_mssg = "unexpected size/len in flush op eviction test 12.";
+ }
+
+ /* 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:
+ */
+
+ expected[6].in_cache = FALSE;
+ expected[6].is_dirty = FALSE;
+ expected[6].flushed = TRUE;
+ expected[6].destroyed = TRUE;
+
+ num_large_entries = 14;
+
+ /* 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;
+ }
+
+ 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);
+ }
+
+ /* 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)) ) ) {
+
+ pass = FALSE;
+ failure_mssg = "unexpected size/len in flush op eviction test 13.";
+ }
+
+ /* 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,
+ H5C__FLUSH_INVALIDATE_FLAG);
+
+ if ( result < 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "Cache flush invalidate failed after flush op eviction test";
+ }
+ else if ( ( cache_ptr->index_len != 0 ) ||
+ ( cache_ptr->index_size != 0 ) ) {
+
+ pass = FALSE;
+ failure_mssg = "Unexpected cache len/size after cleanup of flush op eviction test";
+
+ }
+ }
+
+#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 ) {
+
+ 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;
+ failure_mssg = "Unexpected variable size entry stats.";
+ }
+ }
+
+ if ( pass ) {
+
+ 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;
+ failure_mssg = "Unexpected monster entry stats.";
+ }
+ }
+
+ if ( pass ) {
+
+ 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;
+ failure_mssg = "Unexpected monster entry stats.";
+ }
+ }
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ if ( pass ) {
+
+ reset_entries();
+ }
+
+ return;
+
+} /* check_flush_cache__flush_op_eviction_test() */
+
+
+/*-------------------------------------------------------------------------
* Function: check_flush_cache__single_entry()
*
* Purpose: Verify that flush_cache behaves as expected when the cache
@@ -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);