summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcvs2svn <no_author@cvs2svn>2004-10-01 23:00:55 (GMT)
committercvs2svn <no_author@cvs2svn>2004-10-01 23:00:55 (GMT)
commitd5d34def1ca98fdacc9b31d992a865f07104d379 (patch)
tree2b96c01730364fa3fb82ad7168dc46c3fc5bf77e
parent709ffbd151ddf363b5c3ea59aa222c3b67075ce0 (diff)
downloadhdf5-d5d34def1ca98fdacc9b31d992a865f07104d379.zip
hdf5-d5d34def1ca98fdacc9b31d992a865f07104d379.tar.gz
hdf5-d5d34def1ca98fdacc9b31d992a865f07104d379.tar.bz2
[svn-r9355] This commit was manufactured by cvs2svn to create branch 'hdf5_1_6'.
-rw-r--r--src/H5C.c4183
-rw-r--r--src/H5Cprivate.h421
-rw-r--r--src/H5Defl.c371
-rw-r--r--src/H5Dselect.c691
-rw-r--r--test/cache.c4160
-rw-r--r--tools/h5jam/Dependencies83
-rw-r--r--tools/h5jam/Makefile.in96
-rw-r--r--tools/h5jam/getub.c170
-rw-r--r--tools/h5jam/h5jam.c538
-rw-r--r--tools/h5jam/h5jamgentest.c639
-rw-r--r--tools/h5jam/h5unjam.c317
-rw-r--r--tools/h5jam/tellub.c189
-rw-r--r--tools/h5jam/testh5jam.sh.in527
-rw-r--r--tools/testfiles/twithub.h5bin0 -> 10820 bytes
-rw-r--r--tools/testfiles/twithub513.h5bin0 -> 12560 bytes
-rwxr-xr-xtools/testfiles/u10.txt1
-rwxr-xr-xtools/testfiles/u511.txt1
-rwxr-xr-xtools/testfiles/u512.txt1
-rwxr-xr-xtools/testfiles/u513.txt1
19 files changed, 12389 insertions, 0 deletions
diff --git a/src/H5C.c b/src/H5C.c
new file mode 100644
index 0000000..8c9c74b
--- /dev/null
+++ b/src/H5C.c
@@ -0,0 +1,4183 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5C.c
+ * June 1 2004
+ * John Mainzer
+ *
+ * Purpose: Functions in this file implement a generic cache for
+ * things which exist on disk, and which may be
+ * unambiguously referenced by their disk addresses.
+ *
+ * The code in this module was initially written in
+ * support of a complete re-write of the metadata cache
+ * in H5AC.c However, other uses for the cache code
+ * suggested themselves, and thus this file was created
+ * in an attempt to support re-use.
+ *
+ * For a detailed overview of the cache, please see the
+ * header comment for H5C_t in this file.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/**************************************************************************
+ *
+ * To Do:
+ *
+ * Code Changes:
+ *
+ * - Remove extra functionality in H5C_flush_single_entry()?
+ *
+ * - Change protect/unprotect to lock/unlock.
+ *
+ * - Change the way the dirty flag is set. Probably pass it in
+ * as a parameter in unprotect & insert.
+ *
+ * - Size should also be passed in as a parameter in insert and
+ * unprotect -- or some other way should be found to advise the
+ * cache of changes in entry size.
+ *
+ * - Flush entries in increasing address order in
+ * H5C_make_space_in_cache().
+ *
+ * - Also in H5C_make_space_in_cache(), use high and low water marks
+ * to reduce the number of I/O calls.
+ *
+ * - When flushing, attempt to combine contiguous entries to reduce
+ * I/O overhead. Can't do this just yet as some entries are not
+ * contiguous. Do this in parallel only or in serial as well?
+ *
+ * - Create MPI type for dirty objects when flushing in parallel.
+ *
+ * - Fix TBBT routines so deletions don't move nodes in memory and
+ * point directly to the TBBT node from the LRU list, eliminating
+ * binary tree lookups when evicting objects from the cache.
+ *
+ * Tests:
+ *
+ * - Trim execution time.
+ *
+ * - Add random tests.
+ *
+ **************************************************************************/
+
+#define H5F_PACKAGE /*suppress error about including H5Fpkg */
+
+/* Pablo information */
+/* (Put before include files to avoid problems with inline functions) */
+#define PABLO_MASK H5C_mask
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Cprivate.h" /* Cache */
+#include "H5Dprivate.h" /* Dataset functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fpkg.h" /* Files */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+#include "H5TBprivate.h" /* Threaded, Balanced, Binary Trees */
+
+
+/****************************************************************************
+ *
+ * We maintain doubly linked lists of instances of H5C_cache_entry_t for a
+ * variety of reasons -- protected list, LRU list, and the clean and dirty
+ * LRU lists at present. The following macros support linking and unlinking
+ * of instances of H5C_cache_entry_t by both their regular and auxilary next
+ * and previous pointers.
+ *
+ * The size and length fields are also maintained.
+ *
+ * Note that the relevant pair of prev and next pointers are presumed to be
+ * NULL on entry in the insertion macros.
+ *
+ * Finally, observe that the sanity checking macros evaluate to the empty
+ * string when H5C_DO_SANITY_CHECKS is FALSE. They also contain calls
+ * to the HGOTO_ERROR macro, which may not be appropriate in all cases.
+ * If so, we will need versions of the insertion and deletion macros which
+ * do not reference the sanity checking macros.
+ * JRM - 5/5/04
+ *
+ ****************************************************************************/
+
+#if H5C_DO_SANITY_CHECKS
+
+#define H5C__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+if ( ( (head_ptr) == NULL ) || \
+ ( (tail_ptr) == NULL ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (len) <= 0 ) || \
+ ( (Size) < (entry_ptr)->size ) || \
+ ( ( (Size) == (entry_ptr)->size ) && ( (len) != 1 ) ) || \
+ ( ( (entry_ptr)->prev == NULL ) && ( (head_ptr) != (entry_ptr) ) ) || \
+ ( ( (entry_ptr)->next == NULL ) && ( (tail_ptr) != (entry_ptr) ) ) || \
+ ( ( (len) == 1 ) && \
+ ( ! ( ( (head_ptr) == (entry_ptr) ) && \
+ ( (tail_ptr) == (entry_ptr) ) && \
+ ( (entry_ptr)->next == NULL ) && \
+ ( (entry_ptr)->prev == NULL ) && \
+ ( (Size) == (entry_ptr)->size ) \
+ ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "DLL pre remove SC failed") \
+}
+
+#define H5C__DLL_SC(head_ptr, tail_ptr, len, Size, fv) \
+if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (head_ptr) != (tail_ptr) ) \
+ ) || \
+ ( (len) < 0 ) || \
+ ( (Size) < 0 ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (head_ptr) != (tail_ptr) ) || ( (cache_ptr)->size <= 0 ) || \
+ ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (head_ptr) == NULL ) || ( (head_ptr)->prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "DLL sanity check failed") \
+}
+
+#define H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+if ( ( (entry_ptr) == NULL ) || \
+ ( (entry_ptr)->next != NULL ) || \
+ ( (entry_ptr)->prev != NULL ) || \
+ ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (head_ptr) != (tail_ptr) ) \
+ ) || \
+ ( (len) < 0 ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (head_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) || \
+ ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (head_ptr) == NULL ) || ( (head_ptr)->prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "DLL pre insert SC failed") \
+}
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv)
+#define H5C__DLL_SC(head_ptr, tail_ptr, len, Size, fv)
+#define H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv)
+
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+#define H5C__DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \
+ H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fail_val) \
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (tail_ptr)->next = (entry_ptr); \
+ (entry_ptr)->prev = (tail_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += (entry_ptr)->size;
+
+#define H5C__DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \
+ H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fail_val) \
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (head_ptr)->prev = (entry_ptr); \
+ (entry_ptr)->next = (head_ptr); \
+ (head_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += entry_ptr->size;
+
+#define H5C__DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \
+ H5C__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fail_val) \
+ { \
+ if ( (head_ptr) == (entry_ptr) ) \
+ { \
+ (head_ptr) = (entry_ptr)->next; \
+ if ( (head_ptr) != NULL ) \
+ { \
+ (head_ptr)->prev = NULL; \
+ } \
+ } \
+ else \
+ { \
+ (entry_ptr)->prev->next = (entry_ptr)->next; \
+ } \
+ if ( (tail_ptr) == (entry_ptr) ) \
+ { \
+ (tail_ptr) = (entry_ptr)->prev; \
+ if ( (tail_ptr) != NULL ) \
+ { \
+ (tail_ptr)->next = NULL; \
+ } \
+ } \
+ else \
+ { \
+ (entry_ptr)->next->prev = (entry_ptr)->prev; \
+ } \
+ entry_ptr->next = NULL; \
+ entry_ptr->prev = NULL; \
+ (len)--; \
+ (Size) -= entry_ptr->size; \
+ }
+
+
+#if H5C_DO_SANITY_CHECKS
+
+#define H5C__AUX_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) \
+if ( ( (hd_ptr) == NULL ) || \
+ ( (tail_ptr) == NULL ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (len) <= 0 ) || \
+ ( (Size) < (entry_ptr)->size ) || \
+ ( ( (Size) == (entry_ptr)->size ) && ( ! ( (len) == 1 ) ) ) || \
+ ( ( (entry_ptr)->aux_prev == NULL ) && ( (hd_ptr) != (entry_ptr) ) ) || \
+ ( ( (entry_ptr)->aux_next == NULL ) && ( (tail_ptr) != (entry_ptr) ) ) || \
+ ( ( (len) == 1 ) && \
+ ( ! ( ( (hd_ptr) == (entry_ptr) ) && ( (tail_ptr) == (entry_ptr) ) && \
+ ( (entry_ptr)->aux_next == NULL ) && \
+ ( (entry_ptr)->aux_prev == NULL ) && \
+ ( (Size) == (entry_ptr)->size ) \
+ ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "aux DLL pre remove SC failed") \
+}
+
+#define H5C__AUX_DLL_SC(head_ptr, tail_ptr, len, Size, fv) \
+if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (head_ptr) != (tail_ptr) ) \
+ ) || \
+ ( (len) < 0 ) || \
+ ( (Size) < 0 ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (head_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) || \
+ ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (head_ptr) == NULL ) || ( (head_ptr)->aux_prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->aux_next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "AUX DLL sanity check failed") \
+}
+
+#define H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) \
+if ( ( (entry_ptr) == NULL ) || \
+ ( (entry_ptr)->aux_next != NULL ) || \
+ ( (entry_ptr)->aux_prev != NULL ) || \
+ ( ( ( (hd_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
+ ( (hd_ptr) != (tail_ptr) ) \
+ ) || \
+ ( (len) < 0 ) || \
+ ( ( (len) == 1 ) && \
+ ( ( (hd_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) || \
+ ( (hd_ptr) == NULL ) || ( (hd_ptr)->size != (Size) ) \
+ ) \
+ ) || \
+ ( ( (len) >= 1 ) && \
+ ( ( (hd_ptr) == NULL ) || ( (hd_ptr)->aux_prev != NULL ) || \
+ ( (tail_ptr) == NULL ) || ( (tail_ptr)->aux_next != NULL ) \
+ ) \
+ ) \
+ ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "AUX DLL pre insert SC failed") \
+}
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__AUX_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv)
+#define H5C__AUX_DLL_SC(head_ptr, tail_ptr, len, Size, fv)
+#define H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv)
+
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+#define H5C__AUX_DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val)\
+ H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fail_val) \
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (tail_ptr)->aux_next = (entry_ptr); \
+ (entry_ptr)->aux_prev = (tail_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += entry_ptr->size;
+
+#define H5C__AUX_DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+ H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fv) \
+ if ( (head_ptr) == NULL ) \
+ { \
+ (head_ptr) = (entry_ptr); \
+ (tail_ptr) = (entry_ptr); \
+ } \
+ else \
+ { \
+ (head_ptr)->aux_prev = (entry_ptr); \
+ (entry_ptr)->aux_next = (head_ptr); \
+ (head_ptr) = (entry_ptr); \
+ } \
+ (len)++; \
+ (Size) += entry_ptr->size;
+
+#define H5C__AUX_DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
+ H5C__AUX_DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
+ fv) \
+ { \
+ if ( (head_ptr) == (entry_ptr) ) \
+ { \
+ (head_ptr) = (entry_ptr)->aux_next; \
+ if ( (head_ptr) != NULL ) \
+ { \
+ (head_ptr)->aux_prev = NULL; \
+ } \
+ } \
+ else \
+ { \
+ (entry_ptr)->aux_prev->aux_next = (entry_ptr)->aux_next; \
+ } \
+ if ( (tail_ptr) == (entry_ptr) ) \
+ { \
+ (tail_ptr) = (entry_ptr)->aux_prev; \
+ if ( (tail_ptr) != NULL ) \
+ { \
+ (tail_ptr)->aux_next = NULL; \
+ } \
+ } \
+ else \
+ { \
+ (entry_ptr)->aux_next->aux_prev = (entry_ptr)->aux_prev; \
+ } \
+ entry_ptr->aux_next = NULL; \
+ entry_ptr->aux_prev = NULL; \
+ (len)--; \
+ (Size) -= entry_ptr->size; \
+ }
+
+
+/***********************************************************************
+ *
+ * Stats collection macros
+ *
+ * The following macros must handle stats collection when this collection
+ * is enabled, and evaluate to the empty string when it is not.
+ *
+ ***********************************************************************/
+
+#if H5C_COLLECT_CACHE_STATS
+
+#define H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) \
+ (((cache_ptr)->insertions)[(entry_ptr)->type->id])++; \
+ if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len ) \
+ (cache_ptr)->max_index_len = (cache_ptr)->index_len; \
+ if ( (cache_ptr)->index_size > (cache_ptr)->max_index_size ) \
+ (cache_ptr)->max_index_size = (cache_ptr)->index_size; \
+ if ( (cache_ptr)->tree_len > (cache_ptr)->max_tree_len ) \
+ (cache_ptr)->max_tree_len = (cache_ptr)->tree_len; \
+ if ( (cache_ptr)->tree_size > (cache_ptr)->max_tree_size ) \
+ (cache_ptr)->max_tree_size = (cache_ptr)->tree_size; \
+ if ( (entry_ptr)->size > \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] ) { \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] \
+ = (entry_ptr)->size; \
+ }
+
+#define H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr) \
+ if ( (cache_ptr)->tree_len > (cache_ptr)->max_tree_len ) \
+ (cache_ptr)->max_tree_len = (cache_ptr)->tree_len; \
+ if ( (cache_ptr)->tree_size > (cache_ptr)->max_tree_size ) \
+ (cache_ptr)->max_tree_size = (cache_ptr)->tree_size;
+
+#define H5C__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr) \
+ (((cache_ptr)->renames)[(entry_ptr)->type->id])++;
+
+#define H5C__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) \
+ (cache_ptr)->total_ht_insertions++;
+
+#define H5C__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) \
+ (cache_ptr)->total_ht_deletions++;
+
+#define H5C__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, success, depth) \
+ if ( success ) { \
+ (cache_ptr)->successful_ht_searches++; \
+ (cache_ptr)->total_successful_ht_search_depth += depth; \
+ } else { \
+ (cache_ptr)->failed_ht_searches++; \
+ (cache_ptr)->total_failed_ht_search_depth += depth; \
+ }
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+
+#define H5C__RESET_CACHE_ENTRY_STATS(entry_ptr) \
+ (entry_ptr)->accesses = 0; \
+ (entry_ptr)->clears = 0; \
+ (entry_ptr)->flushes = 0;
+
+#define H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) \
+ (((cache_ptr)->clears)[(entry_ptr)->type->id])++; \
+ ((entry_ptr)->clears)++;
+
+#define H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) \
+ (((cache_ptr)->flushes)[(entry_ptr)->type->id])++; \
+ ((entry_ptr)->flushes)++;
+
+#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) \
+ (((cache_ptr)->evictions)[(entry_ptr)->type->id])++; \
+ if ( (entry_ptr)->accesses > \
+ ((cache_ptr)->max_accesses)[(entry_ptr)->type->id] ) { \
+ ((cache_ptr)->max_accesses)[(entry_ptr)->type->id] \
+ = (entry_ptr)->accesses; \
+ } \
+ if ( (entry_ptr)->accesses < \
+ ((cache_ptr)->min_accesses)[(entry_ptr)->type->id] ) { \
+ ((cache_ptr)->min_accesses)[(entry_ptr)->type->id] \
+ = (entry_ptr)->accesses; \
+ } \
+ if ( (entry_ptr)->clears > \
+ ((cache_ptr)->max_clears)[(entry_ptr)->type->id] ) { \
+ ((cache_ptr)->max_clears)[(entry_ptr)->type->id] \
+ = (entry_ptr)->clears; \
+ } \
+ if ( (entry_ptr)->flushes > \
+ ((cache_ptr)->max_flushes)[(entry_ptr)->type->id] ) { \
+ ((cache_ptr)->max_flushes)[(entry_ptr)->type->id] \
+ = (entry_ptr)->flushes; \
+ } \
+ if ( (entry_ptr)->size > \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] ) { \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] \
+ = (entry_ptr)->size; \
+ } \
+
+#define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit) \
+ if ( hit ) \
+ ((cache_ptr)->hits)[(entry_ptr)->type->id]++; \
+ else \
+ ((cache_ptr)->misses)[(entry_ptr)->type->id]++; \
+ if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len ) \
+ (cache_ptr)->max_index_len = (cache_ptr)->index_len; \
+ if ( (cache_ptr)->index_size > (cache_ptr)->max_index_size ) \
+ (cache_ptr)->max_index_size = (cache_ptr)->index_size; \
+ if ( (cache_ptr)->pl_len > (cache_ptr)->max_pl_len ) \
+ (cache_ptr)->max_pl_len = (cache_ptr)->pl_len; \
+ if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size ) \
+ (cache_ptr)->max_pl_size = (cache_ptr)->pl_size; \
+ if ( (entry_ptr)->size > \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] ) { \
+ ((cache_ptr)->max_size)[(entry_ptr)->type->id] \
+ = (entry_ptr)->size; \
+ } \
+ ((entry_ptr)->accesses)++;
+
+#else /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+#define H5C__RESET_CACHE_ENTRY_STATS(entry_ptr)
+
+#define H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) \
+ (((cache_ptr)->clears)[(entry_ptr)->type->id])++;
+
+#define H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) \
+ (((cache_ptr)->flushes)[(entry_ptr)->type->id])++;
+
+#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) \
+ (((cache_ptr)->evictions)[(entry_ptr)->type->id])++;
+
+#define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit) \
+ if ( hit ) \
+ ((cache_ptr)->hits)[(entry_ptr)->type->id]++; \
+ else \
+ ((cache_ptr)->misses)[(entry_ptr)->type->id]++; \
+ if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len ) \
+ (cache_ptr)->max_index_len = (cache_ptr)->index_len; \
+ if ( (cache_ptr)->index_size > (cache_ptr)->max_index_size ) \
+ (cache_ptr)->max_index_size = (cache_ptr)->index_size; \
+ if ( (cache_ptr)->pl_len > (cache_ptr)->max_pl_len ) \
+ (cache_ptr)->max_pl_len = (cache_ptr)->pl_len; \
+ if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size ) \
+ (cache_ptr)->max_pl_size = (cache_ptr)->pl_size;
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+#else /* H5C_COLLECT_CACHE_STATS */
+
+#define H5C__RESET_CACHE_ENTRY_STATS(entry_ptr)
+#define H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_HT_DELETION(cache_ptr)
+#define H5C__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, success, depth)
+#define H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr)
+#define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit)
+
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+
+/***********************************************************************
+ *
+ * Hash table access and manipulation macros:
+ *
+ * The following macros handle searches, insertions, and deletion in
+ * the hash table.
+ *
+ * When modifying these macros, remember to modify the similar macros
+ * in tst/cache.c
+ *
+ ***********************************************************************/
+
+#define H5C__HASH_TABLE_LEN (32 * 1024) /* must be a power of 2 */
+
+#define H5C__HASH_MASK ((size_t)(H5C__HASH_TABLE_LEN - 1) << 3)
+
+#define H5C__HASH_FCN(x) (int)(((x) & H5C__HASH_MASK) >> 3)
+
+#if H5C_DO_SANITY_CHECKS
+
+#define H5C__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( ! H5F_addr_defined((entry_ptr)->addr) ) || \
+ ( (entry_ptr)->ht_next != NULL ) || \
+ ( (entry_ptr)->ht_prev != NULL ) || \
+ ( (entry_ptr)->size <= 0 ) || \
+ ( (k = H5C__HASH_FCN((entry_ptr)->addr)) < 0 ) || \
+ ( k >= H5C__HASH_TABLE_LEN ) ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, \
+ "Pre HT insert SC failed") \
+}
+
+#define H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (cache_ptr)->index_len < 1 ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (cache_ptr)->index_size < (entry_ptr)->size ) || \
+ ( ! H5F_addr_defined((entry_ptr)->addr) ) || \
+ ( (entry_ptr)->size <= 0 ) || \
+ ( H5C__HASH_FCN((entry_ptr)->addr) < 0 ) || \
+ ( H5C__HASH_FCN((entry_ptr)->addr) >= H5C__HASH_TABLE_LEN ) || \
+ ( ((cache_ptr)->index)[(H5C__HASH_FCN((entry_ptr)->addr))] \
+ == NULL ) || \
+ ( ( ((cache_ptr)->index)[(H5C__HASH_FCN((entry_ptr)->addr))] \
+ != (entry_ptr) ) && \
+ ( (entry_ptr)->ht_prev == NULL ) ) || \
+ ( ( ((cache_ptr)->index)[(H5C__HASH_FCN((entry_ptr)->addr))] == \
+ (entry_ptr) ) && \
+ ( (entry_ptr)->ht_prev != NULL ) ) ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Pre HT remove SC failed") \
+}
+
+#define H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( ! H5F_addr_defined(Addr) ) || \
+ ( H5C__HASH_FCN(Addr) < 0 ) || \
+ ( H5C__HASH_FCN(Addr) >= H5C__HASH_TABLE_LEN ) ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, "Pre HT search SC failed") \
+}
+
+#define H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (cache_ptr)->index_len < 1 ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (cache_ptr)->index_size < (entry_ptr)->size ) || \
+ ( H5F_addr_ne((entry_ptr)->addr, (Addr)) ) || \
+ ( (entry_ptr)->size <= 0 ) || \
+ ( ((cache_ptr)->index)[k] == NULL ) || \
+ ( ( ((cache_ptr)->index)[k] != (entry_ptr) ) && \
+ ( (entry_ptr)->ht_prev == NULL ) ) || \
+ ( ( ((cache_ptr)->index)[k] == (entry_ptr) ) && \
+ ( (entry_ptr)->ht_prev != NULL ) ) || \
+ ( ( (entry_ptr)->ht_prev != NULL ) && \
+ ( (entry_ptr)->ht_prev->ht_next != (entry_ptr) ) ) || \
+ ( ( (entry_ptr)->ht_next != NULL ) && \
+ ( (entry_ptr)->ht_next->ht_prev != (entry_ptr) ) ) ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, \
+ "Post successful HT search SC failed") \
+}
+
+#define H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( ((cache_ptr)->index)[k] != (entry_ptr) ) || \
+ ( (entry_ptr)->ht_prev != NULL ) ) { \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, \
+ "Post HT shift to front SC failed") \
+}
+
+
+#else /* H5C_DO_SANITY_CHECKS */
+
+#define H5C__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val)
+#define H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr)
+#define H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val)
+#define H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val)
+#define H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val)
+
+#endif /* H5C_DO_SANITY_CHECKS */
+
+
+#define H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, fail_val) \
+{ \
+ int k; \
+ H5C__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \
+ k = H5C__HASH_FCN((entry_ptr)->addr); \
+ if ( ((cache_ptr)->index)[k] == NULL ) \
+ { \
+ ((cache_ptr)->index)[k] = (entry_ptr); \
+ } \
+ else \
+ { \
+ (entry_ptr)->ht_next = ((cache_ptr)->index)[k]; \
+ (entry_ptr)->ht_next->ht_prev = (entry_ptr); \
+ ((cache_ptr)->index)[k] = (entry_ptr); \
+ } \
+ (cache_ptr)->index_len++; \
+ (cache_ptr)->index_size += (entry_ptr)->size; \
+ H5C__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) \
+}
+
+#define H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr) \
+{ \
+ int k; \
+ H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) \
+ k = H5C__HASH_FCN((entry_ptr)->addr); \
+ if ( (entry_ptr)->ht_next ) \
+ { \
+ (entry_ptr)->ht_next->ht_prev = (entry_ptr)->ht_prev; \
+ } \
+ if ( (entry_ptr)->ht_prev ) \
+ { \
+ (entry_ptr)->ht_prev->ht_next = (entry_ptr)->ht_next; \
+ } \
+ if ( ((cache_ptr)->index)[k] == (entry_ptr) ) \
+ { \
+ ((cache_ptr)->index)[k] = (entry_ptr)->ht_next; \
+ } \
+ (entry_ptr)->ht_next = NULL; \
+ (entry_ptr)->ht_prev = NULL; \
+ (cache_ptr)->index_len--; \
+ (cache_ptr)->index_size -= (entry_ptr)->size; \
+ H5C__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) \
+}
+
+#define H5C__SEARCH_INDEX(cache_ptr, Addr, entry_ptr, fail_val) \
+{ \
+ int k; \
+ int depth = 0; \
+ H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \
+ k = H5C__HASH_FCN(Addr); \
+ entry_ptr = ((cache_ptr)->index)[k]; \
+ while ( ( entry_ptr ) && ( H5F_addr_ne(Addr, (entry_ptr)->addr) ) ) \
+ { \
+ (entry_ptr) = (entry_ptr)->ht_next; \
+ (depth)++; \
+ } \
+ if ( entry_ptr ) \
+ { \
+ H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val) \
+ if ( entry_ptr != ((cache_ptr)->index)[k] ) \
+ { \
+ if ( (entry_ptr)->ht_next ) \
+ { \
+ (entry_ptr)->ht_next->ht_prev = (entry_ptr)->ht_prev; \
+ } \
+ HDassert( (entry_ptr)->ht_prev != NULL ); \
+ (entry_ptr)->ht_prev->ht_next = (entry_ptr)->ht_next; \
+ ((cache_ptr)->index)[k]->ht_prev = (entry_ptr); \
+ (entry_ptr)->ht_next = ((cache_ptr)->index)[k]; \
+ (entry_ptr)->ht_prev = NULL; \
+ ((cache_ptr)->index)[k] = (entry_ptr); \
+ H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) \
+ } \
+ } \
+ H5C__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, (entry_ptr != NULL), depth) \
+}
+
+
+/**************************************************************************
+ *
+ * Tree insertion and deletion macros:
+ *
+ * These used to be functions, but I converted them to macros to avoid some
+ * function call overhead.
+ *
+ **************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__INSERT_ENTRY_IN_TREE
+ *
+ * Purpose: Insert the specified instance of H5C_cache_entry_t into
+ * the tree in the specified instance of H5C_t. Update
+ * the associated length and size fields.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 5/10/04
+ *
+ * Modifications:
+ *
+ * JRM -- 7/21/04
+ * Updated function to set the in_tree flag when inserting
+ * an entry into the tree. Also modified the function to
+ * update the tree size and len fields instead of the similar
+ * index fields.
+ *
+ * All of this is part of the modifications to support the
+ * hash table.
+ *
+ * JRM -- 7/27/04
+ * Converted the function H5C_insert_entry_in_tree() into
+ * the macro H5C__INSERT_ENTRY_IN_TREE in the hopes of
+ * wringing a little more speed out of the cache.
+ *
+ * Note that we don't bother to check if the entry is already
+ * in the tree -- if it is, H5TB_dins() will fail.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5C__INSERT_ENTRY_IN_TREE(cache_ptr, entry_ptr) \
+{ \
+ H5TB_NODE * loc_node_ptr = NULL; \
+ \
+ 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_tree) ); \
+ \
+ loc_node_ptr = H5TB_dins((cache_ptr)->tree_ptr, (void *)(entry_ptr), NULL);\
+ \
+ if ( loc_node_ptr == NULL ) { \
+ \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't insert entry in tree") \
+ } \
+ \
+ (entry_ptr)->in_tree = TRUE; \
+ (cache_ptr)->tree_len++; \
+ (cache_ptr)->tree_size += (entry_ptr)->size; \
+ \
+ HDassert( (cache_ptr)->tree_len > 0 ); \
+ HDassert( (cache_ptr)->tree_size > 0 ); \
+ \
+} /* H5C__INSERT_ENTRY_IN_TREE */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C__REMOVE_ENTRY_FROM_TREE
+ *
+ * Purpose: Remove the specified instance of H5C_cache_entry_t from the
+ * index tree in the specified instance of H5C_t. Update
+ * the associated length and size fields.
+ *
+ * Return: N/A
+ *
+ * Programmer: John Mainzer, 5/10/04
+ *
+ * Modifications:
+ *
+ * JRM -- 7/21/04
+ * Updated function for the addition of the hash table.
+ *
+ * JRM - 7/27/04
+ * Converted from the function H5C_remove_entry_from_tree()
+ * to the macro H5C__REMOVE_ENTRY_FROM_TREE in the hopes of
+ * wringing a little more performance out of the cache.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5C__REMOVE_ENTRY_FROM_TREE(cache_ptr, entry_ptr, node_ptr) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (node_ptr) ); \
+ HDassert( (node_ptr)->data == (entry_ptr) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ HDassert( (entry_ptr)->in_tree ); \
+ HDassert( (cache_ptr)->tree_ptr ); \
+ HDassert( (cache_ptr)->tree_ptr->root ); \
+ \
+ if ( H5TB_rem(&((cache_ptr)->tree_ptr->root), (node_ptr), NULL) \
+ != (entry_ptr) ) { \
+ \
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "Can't delete entry from tree.") \
+ \
+ } else { \
+ \
+ HDassert( (cache_ptr)->tree_len > 0 ); \
+ (cache_ptr)->tree_len--; \
+ HDassert( (cache_ptr)->tree_size >= (entry_ptr)->size ); \
+ (cache_ptr)->tree_size -= (entry_ptr)->size; \
+ (entry_ptr)->in_tree = FALSE; \
+ } \
+} /* H5C__REMOVE_ENTRY_FROM_TREE */
+
+
+/**************************************************************************
+ *
+ * Replacement policy update macros:
+ *
+ * These used to be functions, but I converted them to macros to avoid some
+ * function call overhead.
+ *
+ **************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_EVICTION
+ *
+ * Purpose: Update the replacement policy data structures for an
+ * eviction of the specified cache entry.
+ *
+ * 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: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 5/10/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_eviction() to the
+ * macro H5C__UPDATE_RP_FOR_EVICTION in an effort to squeeze
+ * a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * the pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two version, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* If the entry is clean when it is evicted, it should be on the \
+ * clean LRU list, if it was dirty, it should be on the dirty LRU list. \
+ * Remove it from the appropriate list according to the value of the \
+ * dirty flag. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ } else { \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+} /* H5C__UPDATE_RP_FOR_EVICTION */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+} /* H5C__UPDATE_RP_FOR_EVICTION */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_FLUSH
+ *
+ * Purpose: Update the replacement policy data structures for a flush
+ * of the specified cache entry.
+ *
+ * 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, 5/6/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_flush() to the
+ * macro H5C__UPDATE_RP_FOR_FLUSH in an effort to squeeze
+ * a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two version, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list, and re-insert it at the head. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* since the entry is being flushed or cleared, one would think that it \
+ * must be dirty -- but that need not be the case. Use the dirty flag \
+ * to infer whether the entry is on the clean or dirty LRU list, and \
+ * remove it. Then insert it at the head of the clean LRU list. \
+ * \
+ * The function presumes that a dirty entry will be either cleared or \
+ * flushed shortly, so it is OK if we put a dirty entry on the clean \
+ * LRU list. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ } else { \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ \
+} /* H5C__UPDATE_RP_FOR_FLUSH */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list, and re-insert it at the head. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ \
+} /* H5C__UPDATE_RP_FOR_FLUSH */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_INSERTION
+ *
+ * Purpose: Update the replacement policy data structures for an
+ * insertion of the specified cache entry.
+ *
+ * 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, 5/17/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_insertion() to the
+ * macro H5C__UPDATE_RP_FOR_INSERTION in an effort to squeeze
+ * a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two version, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the head of the LRU list. */ \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* insert the entry at the head of the clean or dirty LRU list as \
+ * appropriate. \
+ */ \
+ \
+ if ( entry_ptr->is_dirty ) { \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ } else { \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ \
+}
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the head of the LRU list. */ \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ \
+}
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_PROTECT
+ *
+ * Purpose: Update the replacement policy data structures for a
+ * protect of the specified cache entry.
+ *
+ * To do this, unlink the specified entry from any data
+ * structures used by the replacement policy, and add the
+ * entry to the protected list.
+ *
+ * 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, 5/17/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_protect() to the
+ * macro H5C__UPDATE_RP_FOR_PROTECT in an effort to squeeze
+ * a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two version, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* Similarly, remove the entry from the clean or dirty LRU list \
+ * as appropriate. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ \
+ } else { \
+ \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ \
+ /* Regardless of the replacement policy, now add the entry to the \
+ * protected list. \
+ */ \
+ \
+ H5C__DLL_APPEND((entry_ptr), (cache_ptr)->pl_head_ptr, \
+ (cache_ptr)->pl_tail_ptr, \
+ (cache_ptr)->pl_len, \
+ (cache_ptr)->pl_size, (fail_val)) \
+} /* H5C__UPDATE_RP_FOR_PROTECT */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ \
+ /* Regardless of the replacement policy, now add the entry to the \
+ * protected list. \
+ */ \
+ \
+ H5C__DLL_APPEND((entry_ptr), (cache_ptr)->pl_head_ptr, \
+ (cache_ptr)->pl_tail_ptr, \
+ (cache_ptr)->pl_len, \
+ (cache_ptr)->pl_size, (fail_val)) \
+} /* H5C__UPDATE_RP_FOR_PROTECT */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_RENAME
+ *
+ * Purpose: Update the replacement policy data structures for a
+ * rename of the specified cache entry.
+ *
+ * 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, 5/17/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_rename() to the
+ * macro H5C__UPDATE_RP_FOR_RENAME in an effort to squeeze
+ * a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two version, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list, and re-insert it at the head. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* move the entry to the head of either the clean or dirty LRU list \
+ * as appropriate. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ \
+ } else { \
+ \
+ H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ \
+} /* H5C__UPDATE_RP_FOR_RENAME */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( !((entry_ptr)->is_protected) ); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* remove the entry from the LRU list, and re-insert it at the head. */ \
+ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ \
+} /* H5C__UPDATE_RP_FOR_RENAME */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Macro: H5C__UPDATE_RP_FOR_UNPROTECT
+ *
+ * Purpose: Update the replacement policy data structures for an
+ * unprotect of the specified cache entry.
+ *
+ * To do this, unlink the specified entry from the protected
+ * list, and re-insert it in the data structures used by the
+ * current replacement policy.
+ *
+ * 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, 5/19/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/27/04
+ * Converted the function H5C_update_rp_for_unprotect() to
+ * the macro H5C__UPDATE_RP_FOR_UNPROTECT in an effort to
+ * squeeze a bit more performance out of the cache.
+ *
+ * At least for the first cut, I am leaving the comments and
+ * white space in the macro. If they cause dificulties with
+ * pre-processor, I'll have to remove them.
+ *
+ * JRM - 7/28/04
+ * Split macro into two version, one supporting the clean and
+ * dirty LRU lists, and the other not. Yet another attempt
+ * at optimization.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+#define H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( (entry_ptr)->is_protected); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* Regardless of the replacement policy, remove the entry from the \
+ * protected list. \
+ */ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pl_head_ptr, \
+ (cache_ptr)->pl_tail_ptr, (cache_ptr)->pl_len, \
+ (cache_ptr)->pl_size, (fail_val)) \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the head of the LRU list. */ \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* Similarly, insert the entry at the head of either the clean or \
+ * dirty LRU list as appropriate. \
+ */ \
+ \
+ if ( (entry_ptr)->is_dirty ) { \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr, \
+ (cache_ptr)->dLRU_tail_ptr, \
+ (cache_ptr)->dLRU_list_len, \
+ (cache_ptr)->dLRU_list_size, (fail_val)) \
+ \
+ } else { \
+ \
+ H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \
+ (cache_ptr)->cLRU_tail_ptr, \
+ (cache_ptr)->cLRU_list_len, \
+ (cache_ptr)->cLRU_list_size, (fail_val)) \
+ } \
+ \
+ /* End modified LRU specific code. */ \
+ \
+} /* H5C__UPDATE_RP_FOR_UNPROTECT */
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+#define H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, fail_val) \
+{ \
+ HDassert( (cache_ptr) ); \
+ HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
+ HDassert( (entry_ptr) ); \
+ HDassert( (entry_ptr)->is_protected); \
+ HDassert( (entry_ptr)->size > 0 ); \
+ \
+ /* Regardless of the replacement policy, remove the entry from the \
+ * protected list. \
+ */ \
+ H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pl_head_ptr, \
+ (cache_ptr)->pl_tail_ptr, (cache_ptr)->pl_len, \
+ (cache_ptr)->pl_size, (fail_val)) \
+ \
+ /* modified LRU specific code */ \
+ \
+ /* insert the entry at the head of the LRU list. */ \
+ \
+ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \
+ (cache_ptr)->LRU_tail_ptr, \
+ (cache_ptr)->LRU_list_len, \
+ (cache_ptr)->LRU_list_size, (fail_val)) \
+ \
+ /* End modified LRU specific code. */ \
+ \
+} /* H5C__UPDATE_RP_FOR_UNPROTECT */
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+
+/****************************************************************************
+ *
+ * structure H5C_t
+ *
+ * Catchall structure for all variables specific to an instance of the cache.
+ *
+ * While the individual fields of the structure are discussed below, the
+ * following overview may be helpful.
+ *
+ * Entries in the cache are stored in an instance of H5TB_TREE, indexed on
+ * the entry's disk address. While the H5TB_TREE is less efficient than
+ * hash table, it keeps the entries in address sorted order. As flushes
+ * in parallel mode are more efficient if they are issued in increasing
+ * address order, this is a significant benefit. Also the H5TB_TREE code
+ * was readily available, which reduced development time.
+ *
+ * While the cache was designed with multiple replacement policies in mind,
+ * at present only a modified form of LRU is supported.
+ *
+ * JRM - 4/26/04
+ *
+ * Profiling has indicated that searches in the instance of H5TB_TREE are
+ * too expensive. To deal with this issue, I have augmented the cache
+ * with a hash table in which all entries will be stored. Given the
+ * advantages of flushing entries in increasing address order, the TBBT
+ * is retained, but only dirty entries are stored in it. At least for
+ * now, we will leave entries in the TBBT after they are flushed.
+ *
+ * Note that index_size and index_len now refer to the total size of
+ * and number of entries in the hash table.
+ *
+ * JRM - 7/19/04
+ *
+ * *********************************************
+ *
+ * WARNING: A copy of H5C_t is in tst/cache.c (under the name "local_H5C_t"
+ * to allow the test code to access the internal fields of the
+ * cache. If you modify H5C_t, be sure to update local_H5C_t
+ * in cache.c as well.
+ *
+ * *********************************************
+ *
+ * magic: Unsigned 32 bit integer always set to H5C__H5C_T_MAGIC. This
+ * field is used to validate pointers to instances of H5C_t.
+ *
+ * max_type_id: Integer field containing the maximum type id number assigned
+ * to a type of entry in the cache. All type ids from 0 to
+ * max_type_id inclusive must be defined. The names of the
+ * types are stored in the type_name_table discussed below, and
+ * indexed by the ids.
+ *
+ * type_name_table_ptr: Pointer to an array of pointer to char of length
+ * max_type_id + 1. The strings pointed to by the entries
+ * in the array are the names of the entry types associated
+ * with the indexing type IDs.
+ *
+ * max_cache_size: Nominal maximum number of bytes that may be stored in the
+ * cache. This value should be viewed as a soft limit, as the
+ * cache can exceed this value under the following circumstances:
+ *
+ * a) All entries in the cache are protected, and the cache is
+ * asked to insert a new entry. In this case the new entry
+ * will be created. If this causes the cache to exceed
+ * max_cache_size, it will do so. The cache will attempt
+ * to reduce its size as entries are unprotected.
+ *
+ * b) When running in parallel mode, the cache may not be
+ * permitted to flush a dirty entry in response to a read.
+ * If there are no clean entries available to evict, the
+ * cache will exceed its maximum size. Again the cache
+ * will attempt to reduce its size to the max_cache_size
+ * limit on the next cache write.
+ *
+ * min_clean_size: Nominal minimum number of clean bytes in the cache.
+ * The cache attempts to maintain this number of bytes of
+ * clean data so as to avoid case b) above. Again, this is
+ * a soft limit.
+ *
+ *
+ * In addition to the call back functions required for each entry, the
+ * cache requires the following call back functions for this instance of
+ * the cache as a whole:
+ *
+ * check_write_permitted: In certain applications, the cache may not
+ * be allowed to write to disk at certain time. If specified,
+ * the check_write_permitted function is used to determine if
+ * a write is permissible at any given point in time.
+ *
+ * If no such function is specified (i.e. this field is NULL),
+ * the cache will presume that writes are always permissable.
+ *
+ *
+ * The cache requires an index to facilitate searching for entries. The
+ * following fields support that index.
+ *
+ * index_len: Number of entries currently in the hash table used to index
+ * the cache.
+ *
+ * index_size: Number of bytes of cache entries currently stored in the
+ * hash table used to index the cache.
+ *
+ * This value should not be mistaken for footprint of the
+ * cache in memory. The average cache entry is small, and
+ * the cache has a considerable overhead. Multiplying the
+ * index_size by two should yield a conservative estimate
+ * of the cache's memory footprint.
+ *
+ * index: Array of pointer to H5C_cache_entry_t of size
+ * H5C__HASH_TABLE_LEN. At present, this value is a power
+ * of two, not the usual prime number.
+ *
+ * I hope that the variable size of cache elements, the large
+ * hash table size, and the way in which HDF5 allocates space
+ * will combine to avoid problems with periodicity. If so, we
+ * can use a trivial hash function (a bit-and and a 3 bit left
+ * shift) with some small savings.
+ *
+ * If not, it will become evident in the statistics. Changing
+ * to the usual prime number length hash table will require
+ * changing the H5C__HASH_FCN macro and the deletion of the
+ * H5C__HASH_MASK #define. No other changes should be required.
+ *
+ *
+ * When we flush the cache, we need to write entries out in increasing
+ * address order. An instance of TBBT is used to store dirty entries in
+ * sorted order. Whether it is cheaper to sort the dirty entries as needed,
+ * or to maintain the tree is an open question. At a guess, it depends
+ * on how frequently the cache is flushed. We will see how it goes.
+ *
+ * For now at least, I will not remove dirty entries from the tree as they
+ * are flushed.
+ *
+ * tree_len: Number of entries currently in the threaded binary B-tree
+ * used to maintain a sorted list of dirty entries in the
+ * cache.
+ *
+ * tree_size: Number of bytes of cache entries currently stored in the
+ * threaded binary B-tree used to maintain a sorted list of
+ * dirty entries in the cache.
+ *
+ * tree_ptr: pointer to the instance of H5TB_TREE used maintain a sorted
+ * list of dirty entries in the cache. This sorted list has
+ * two uses:
+ *
+ * a) It allows us to flush dirty entries in increasing address
+ * order, which results in significant savings.
+ *
+ * b) It facilitates checking for adjacent dirty entries when
+ * attempting to evict entries from the cache. While we
+ * don't use this at present, I hope that this will allow
+ * some optimizations when I get to it.
+ *
+ *
+ * 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.
+ * The following fields are used to implement the protected list (pl).
+ *
+ * pl_len: Number of entries currently residing on the protected list.
+ *
+ * pl_size: Number of bytes of cache entries currently residing on the
+ * protected list.
+ *
+ * pl_head_ptr: Pointer to the head of the doubly linked list of protected
+ * entries. Note that cache entries on this list are linked
+ * by their next and prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * pl_tail_ptr: Pointer to the tail of the doubly linked list of protected
+ * entries. Note that cache entries on this list are linked
+ * by their next and prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ *
+ * The cache must have a replacement policy, and the fields supporting this
+ * policy must be accessible from this structure.
+ *
+ * While there has been interest in several replacement policies for
+ * this cache, the initial development schedule is tight. Thus I have
+ * elected to support only a modified LRU policy for the first cut.
+ *
+ * To further simplify matters, I have simply included the fields needed
+ * by the modified LRU in this structure. When and if we add support for
+ * other policies, it will probably be easiest to just add the necessary
+ * fields to this structure as well -- we only create one instance of this
+ * structure per file, so the overhead is not excessive.
+ *
+ *
+ * Fields supporting the modified LRU policy:
+ *
+ * See most any OS text for a discussion of the LRU replacement policy.
+ *
+ * When operating in parallel mode, we must ensure that a read does not
+ * cause a write. If it does, the process will hang, as the write will
+ * be collective and the other processes will not know to participate.
+ *
+ * To deal with this issue, I have modified the usual LRU policy by adding
+ * clean and dirty LRU lists to the usual LRU list.
+ *
+ * The clean LRU list is simply the regular LRU list with all dirty cache
+ * entries removed.
+ *
+ * Similarly, the dirty LRU list is the regular LRU list with all the clean
+ * cache entries removed.
+ *
+ * When reading in parallel mode, we evict from the clean LRU list only.
+ * This implies that we must try to ensure that the clean LRU list is
+ * reasonably well stocked at all times.
+ *
+ * We attempt to do this by trying to flush enough entries on each write
+ * to keep the cLRU_list_size >= min_clean_size.
+ *
+ * Even if we start with a completely clean cache, a sequence of protects
+ * without unprotects can empty the clean LRU list. In this case, the
+ * cache must grow temporarily. At the next write, we will attempt to
+ * evict enough entries to reduce index_size to less than max_cache_size.
+ * While this will usually be possible, all bets are off if enough entries
+ * are protected.
+ *
+ * Discussions of the individual fields used by the modified LRU replacement
+ * policy follow:
+ *
+ * LRU_list_len: Number of cache entries currently on the LRU list.
+ *
+ * Observe that LRU_list_len + pl_len must always equal
+ * index_len.
+ *
+ * LRU_list_size: Number of bytes of cache entries currently residing on the
+ * LRU list.
+ *
+ * Observe that LRU_list_size + pl_size must always equal
+ * index_size.
+ *
+ * LRU_head_ptr: Pointer to the head of the doubly linked LRU list. Cache
+ * entries on this list are linked by their next and prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * LRU_tail_ptr: Pointer to the tail of the doubly linked LRU list. Cache
+ * entries on this list are linked by their next and prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * cLRU_list_len: Number of cache entries currently on the clean LRU list.
+ *
+ * Observe that cLRU_list_len + dLRU_list_len must always
+ * equal LRU_list_len.
+ *
+ * cLRU_list_size: Number of bytes of cache entries currently residing on
+ * the clean LRU list.
+ *
+ * Observe that cLRU_list_size + dLRU_list_size must always
+ * equal LRU_list_size.
+ *
+ * cLRU_head_ptr: Pointer to the head of the doubly linked clean LRU list.
+ * Cache entries on this list are linked by their aux_next and
+ * aux_prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * cLRU_tail_ptr: Pointer to the tail of the doubly linked clean LRU list.
+ * Cache entries on this list are linked by their aux_next and
+ * aux_prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * dLRU_list_len: Number of cache entries currently on the dirty LRU list.
+ *
+ * Observe that cLRU_list_len + dLRU_list_len must always
+ * equal LRU_list_len.
+ *
+ * dLRU_list_size: Number of cache entries currently on the dirty LRU list.
+ *
+ * Observe that cLRU_list_len + dLRU_list_len must always
+ * equal LRU_list_len.
+ *
+ * dLRU_head_ptr: Pointer to the head of the doubly linked dirty LRU list.
+ * Cache entries on this list are linked by their aux_next and
+ * aux_prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ * dLRU_tail_ptr: Pointer to the tail of the doubly linked dirty LRU list.
+ * Cache entries on this list are linked by their aux_next and
+ * aux_prev fields.
+ *
+ * This field is NULL if the list is empty.
+ *
+ *
+ * Statistics collection fields:
+ *
+ * When enabled, these fields are used to collect statistics as described
+ * below. The first set are collected only when H5C_COLLECT_CACHE_STATS
+ * is true.
+ *
+ * hits: Array of int64 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the number of times an entry with type id
+ * equal to the array index has been in cache when requested in
+ * the current epoch.
+ *
+ * misses: Array of int64 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the number of times an entry with type id
+ * equal to the array index has not been in cache when
+ * requested in the current epoch.
+ *
+ * insertions: Array of int64 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the number of times an entry with type
+ * id equal to the array index has been inserted into the
+ * cache in the current epoch.
+ *
+ * clears: Array of int64 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the number of times an entry with type
+ * id equal to the array index has been cleared in the current
+ * epoch.
+ *
+ * flushes: Array of int64 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the number of times an entry with type id
+ * equal to the array index has been written to disk in the
+ * current epoch.
+ *
+ * evictions: Array of int64 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the number of times an entry with type id
+ * equal to the array index has been evicted from the cache in
+ * the current epoch.
+ *
+ * renames: Array of int64 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the number of times an entry with type
+ * id equal to the array index has been renamed in the current
+ * epoch.
+ *
+ * total_ht_insertions: Number of times entries have been inserted into the
+ * hash table in the current epoch.
+ *
+ * total_ht_deletions: Number of times entries have been deleted from the
+ * hash table in the current epoch.
+ *
+ * successful_ht_searches: int64 containing the total number of successful
+ * searches of the hash table in the current epoch.
+ *
+ * total_successful_ht_search_depth: int64 containing the total number of
+ * entries other than the targets examined in successful
+ * searches of the hash table in the current epoch.
+ *
+ * failed_ht_searches: int64 containing the total number of unsuccessful
+ * searches of the hash table in the current epoch.
+ *
+ * total_failed_ht_search_depth: int64 containing the total number of
+ * entries examined in unsuccessful searches of the hash
+ * table in the current epoch.
+ *
+ * max_index_len: Largest value attained by the index_len field in the
+ * current epoch.
+ *
+ * max_index_size: Largest value attained by the index_size field in the
+ * current epoch.
+ *
+ * max_tree_len: Largest value attained by the tree_len field in the
+ * current epoch.
+ *
+ * max_tree_size: Largest value attained by the tree_size field in the
+ * current epoch.
+ *
+ * max_pl_len: Largest value attained by the pl_len field in the
+ * current epoch.
+ *
+ * max_pl_size: Largest value attained by the pl_size field in the
+ * current epoch.
+ *
+ * The remaining stats are collected only when both H5C_COLLECT_CACHE_STATS
+ * and H5C_COLLECT_CACHE_ENTRY_STATS are true.
+ *
+ * max_accesses: Array of int32 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the maximum number of times any single
+ * entry with type id equal to the array index has been
+ * accessed in the current epoch.
+ *
+ * min_accesses: Array of int32 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the minimum number of times any single
+ * entry with type id equal to the array index has been
+ * accessed in the current epoch.
+ *
+ * max_clears: Array of int32 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the maximum number of times any single
+ * entry with type id equal to the array index has been cleared
+ * in the current epoch.
+ *
+ * max_flushes: Array of int32 of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the maximum number of times any single
+ * entry with type id equal to the array index has been
+ * flushed in the current epoch.
+ *
+ * max_size: Array of size_t of length H5C__MAX_NUM_TYPE_IDS. The cells
+ * are used to record the maximum size of any single entry
+ * with type id equal to the array index that has resided in
+ * the cache in the current epoch.
+ *
+ *
+ * Fields supporting testing:
+ *
+ * For test purposes, it is useful to turn off some asserts and sanity
+ * checks. The following flags support this.
+ *
+ * skip_file_checks: Boolean flag used to skip sanity checks on file
+ * parameters passed to the cache. In the test bed, there
+ * is no reason to have a file open, as the cache proper
+ * just passes these parameters through without using them.
+ *
+ * When this flag is set, all sanity checks on the file
+ * parameters are skipped. The field defaults to FALSE.
+ *
+ * skip_dxpl_id_checks: Boolean flag used to skip sanity checks on the
+ * dxpl_id parameters passed to the cache. These are not
+ * used directly by the cache, so skipping the checks
+ * simplifies the test bed.
+ *
+ * When this flag is set, all sanity checks on the dxpl_id
+ * parameters are skipped. The field defaults to FALSE.
+ *
+ ****************************************************************************/
+
+#define H5C__H5C_T_MAGIC 0x005CAC0E
+#define H5C__MAX_NUM_TYPE_IDS 9
+
+struct H5C_t
+{
+ uint32_t magic;
+
+ int32_t max_type_id;
+ const char * (* type_name_table_ptr);
+
+ size_t max_cache_size;
+ size_t min_clean_size;
+
+ H5C_write_permitted_func_t check_write_permitted;
+
+ int32_t index_len;
+ size_t index_size;
+ H5C_cache_entry_t * (index[H5C__HASH_TABLE_LEN]);
+
+
+ int32_t tree_len;
+ size_t tree_size;
+ H5TB_TREE * tree_ptr;
+
+ int32_t pl_len;
+ size_t pl_size;
+ H5C_cache_entry_t * pl_head_ptr;
+ H5C_cache_entry_t * pl_tail_ptr;
+
+ int32_t LRU_list_len;
+ size_t LRU_list_size;
+ H5C_cache_entry_t * LRU_head_ptr;
+ H5C_cache_entry_t * LRU_tail_ptr;
+
+ int32_t cLRU_list_len;
+ size_t cLRU_list_size;
+ H5C_cache_entry_t * cLRU_head_ptr;
+ H5C_cache_entry_t * cLRU_tail_ptr;
+
+ int32_t dLRU_list_len;
+ size_t dLRU_list_size;
+ H5C_cache_entry_t * dLRU_head_ptr;
+ H5C_cache_entry_t * dLRU_tail_ptr;
+
+#if H5C_COLLECT_CACHE_STATS
+
+ /* stats fields */
+ int64_t hits[H5C__MAX_NUM_TYPE_IDS];
+ int64_t misses[H5C__MAX_NUM_TYPE_IDS];
+ int64_t insertions[H5C__MAX_NUM_TYPE_IDS];
+ int64_t clears[H5C__MAX_NUM_TYPE_IDS];
+ int64_t flushes[H5C__MAX_NUM_TYPE_IDS];
+ int64_t evictions[H5C__MAX_NUM_TYPE_IDS];
+ int64_t renames[H5C__MAX_NUM_TYPE_IDS];
+
+ int64_t total_ht_insertions;
+ int64_t total_ht_deletions;
+ int64_t successful_ht_searches;
+ int64_t total_successful_ht_search_depth;
+ int64_t failed_ht_searches;
+ int64_t total_failed_ht_search_depth;
+
+ int32_t max_index_len;
+ size_t max_index_size;
+
+ int32_t max_tree_len;
+ size_t max_tree_size;
+
+ int32_t max_pl_len;
+ size_t max_pl_size;
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+
+ int32_t max_accesses[H5C__MAX_NUM_TYPE_IDS];
+ int32_t min_accesses[H5C__MAX_NUM_TYPE_IDS];
+ int32_t max_clears[H5C__MAX_NUM_TYPE_IDS];
+ int32_t max_flushes[H5C__MAX_NUM_TYPE_IDS];
+ size_t max_size[H5C__MAX_NUM_TYPE_IDS];
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ hbool_t skip_file_checks;
+ hbool_t skip_dxpl_id_checks;
+
+};
+
+
+/*
+ * Private file-scope variables.
+ */
+
+/* Declare a free list to manage the H5C_t struct */
+H5FL_DEFINE_STATIC(H5C_t);
+
+/*
+ * Private file-scope function declarations:
+ */
+
+static herr_t H5C_flush_single_entry(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ const H5C_class_t * type_ptr,
+ haddr_t addr,
+ unsigned flags,
+ H5TB_NODE * tgt_node_ptr,
+ hbool_t * first_flush_ptr,
+ hbool_t del_entry_from_tree_on_destroy);
+
+static void * H5C_load_entry(H5F_t * f,
+ hid_t dxpl_id,
+ const H5C_class_t * type,
+ haddr_t addr,
+ const void * udata1,
+ void * udata2,
+ hbool_t skip_file_checks);
+
+static herr_t H5C_make_space_in_cache(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ size_t space_needed,
+ hbool_t write_permitted);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_create
+ *
+ * Purpose: Allocate, initialize, and return the address of a new
+ * instance of H5C_t.
+ *
+ * In general, the max_cache_size parameter must be positive,
+ * and the min_clean_size parameter must lie in the closed
+ * interval [0, max_cache_size].
+ *
+ * The check_write_permitted parameter must either be NULL,
+ * or point to a function of type H5C_write_permitted_func_t.
+ * If it is NULL, the cache will presume that writes are
+ * always permitted.
+ *
+ * Return: Success: Pointer to the new instance.
+ *
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ * Modifications:
+ *
+ * JRM -- 7/20/04
+ * Updated for the addition of the hash table.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+H5C_t *
+H5C_create(size_t max_cache_size,
+ size_t min_clean_size,
+ int max_type_id,
+ const char * (* type_name_table_ptr),
+ H5C_write_permitted_func_t check_write_permitted)
+{
+ int i;
+ H5C_t * cache_ptr = NULL;
+ H5C_t * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5C_create, NULL)
+
+ HDassert( max_cache_size > 0 );
+ HDassert( min_clean_size <= max_cache_size );
+
+ HDassert( max_type_id >= 0 );
+ HDassert( max_type_id < H5C__MAX_NUM_TYPE_IDS );
+ HDassert( type_name_table_ptr );
+
+ for ( i = 0; i <= max_type_id; i++ ) {
+
+ HDassert( (type_name_table_ptr)[i] );
+ HDassert( HDstrlen(( type_name_table_ptr)[i]) > 0 );
+ }
+
+
+ if ( NULL == (cache_ptr = H5FL_CALLOC(H5C_t)) ) {
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, \
+ "memory allocation failed")
+ }
+
+ if ( (cache_ptr->tree_ptr = H5TB_fast_dmake(H5TB_FAST_HADDR_COMPARE))
+ == NULL ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, NULL, "can't create TBBT.")
+ }
+
+ /* If we get this far, we should succeed. Go ahead and initialize all
+ * the fields.
+ */
+
+ cache_ptr->magic = H5C__H5C_T_MAGIC;
+
+ cache_ptr->max_type_id = max_type_id;
+ cache_ptr->type_name_table_ptr = type_name_table_ptr;
+
+ cache_ptr->max_cache_size = max_cache_size;
+ cache_ptr->min_clean_size = min_clean_size;
+
+ cache_ptr->check_write_permitted = check_write_permitted;
+
+ cache_ptr->index_len = 0;
+ cache_ptr->index_size = (size_t)0;
+
+ cache_ptr->tree_len = 0;
+ cache_ptr->tree_size = (size_t)0;
+
+ for ( i = 0; i < H5C__HASH_TABLE_LEN; i++ )
+ {
+ (cache_ptr->index)[i] = NULL;
+ }
+
+ cache_ptr->pl_len = 0;
+ cache_ptr->pl_size = (size_t)0;
+ cache_ptr->pl_head_ptr = NULL;
+ cache_ptr->pl_tail_ptr = NULL;
+
+ cache_ptr->LRU_list_len = 0;
+ cache_ptr->LRU_list_size = (size_t)0;
+ cache_ptr->LRU_head_ptr = NULL;
+ cache_ptr->LRU_tail_ptr = NULL;
+
+ cache_ptr->cLRU_list_len = 0;
+ cache_ptr->cLRU_list_size = (size_t)0;
+ cache_ptr->cLRU_head_ptr = NULL;
+ cache_ptr->cLRU_tail_ptr = NULL;
+
+ cache_ptr->dLRU_list_len = 0;
+ cache_ptr->dLRU_list_size = (size_t)0;
+ cache_ptr->dLRU_head_ptr = NULL;
+ cache_ptr->dLRU_tail_ptr = NULL;
+
+ H5C_stats__reset(cache_ptr);
+
+ cache_ptr->skip_file_checks = FALSE;
+ cache_ptr->skip_dxpl_id_checks = FALSE;
+
+ /* Set return value */
+ ret_value = cache_ptr;
+
+done:
+
+ if ( ret_value == 0 ) {
+
+ if ( cache_ptr != NULL ) {
+
+ if ( cache_ptr->tree_ptr != NULL ) {
+
+ /* the index tree should be empty, so we can pass in
+ * NULL for the fd & fk parameters.
+ */
+ H5TB_dfree(cache_ptr->tree_ptr, NULL, NULL);
+ }
+
+ cache_ptr->magic = 0;
+ H5FL_FREE(H5C_t, cache_ptr);
+ cache_ptr = NULL;
+
+ } /* end if */
+
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_create() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_dest
+ *
+ * Purpose: Flush all data to disk and destroy the cache.
+ *
+ * This function fails if any object are protected since the
+ * resulting file might not be consistent.
+ *
+ * The primary_dxpl_id and secondary_dxpl_id parameters
+ * specify the dxpl_ids used on the first write occasioned
+ * by the destroy (primary_dxpl_id), and on all subsequent
+ * writes (secondary_dxpl_id). This is useful in the metadata
+ * cache, but may not be needed elsewhere. If so, just use the
+ * same dxpl_id for both parameters.
+ *
+ * Note that *cache_ptr has been freed upon successful return.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_dest(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5C_dest, FAIL)
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( cache_ptr->skip_file_checks || f );
+
+ if ( H5C_flush_cache(f, primary_dxpl_id, secondary_dxpl_id,
+ cache_ptr, H5F_FLUSH_INVALIDATE) < 0 ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache")
+ }
+
+ if ( cache_ptr->tree_ptr != NULL ) {
+
+ /* the index tree should be empty, so we can pass in
+ * NULL for the fd & fk parameters.
+ */
+ H5TB_dfree(cache_ptr->tree_ptr, NULL, NULL);
+ cache_ptr->tree_ptr = NULL;
+ }
+
+ cache_ptr->magic = 0;
+
+ H5FL_FREE(H5C_t, cache_ptr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_dest_empty
+ *
+ * Purpose: Destroy an empty cache.
+ *
+ * This function fails if the cache is not empty on entry.
+ *
+ * Note that *cache_ptr has been freed upon successful return.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_dest_empty(H5C_t * cache_ptr)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5C_dest_empty, FAIL)
+
+ /* This would normally be an assert, but we need to use an HGOTO_ERROR
+ * call to shut up the compiler.
+ */
+ if ( ( ! cache_ptr ) ||
+ ( cache_ptr->magic != H5C__H5C_T_MAGIC ) ||
+ ( cache_ptr->index_len != 0 ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "Bad cache_ptr or non-empty cache on entry.")
+ }
+
+
+ if ( cache_ptr->tree_ptr != NULL ) {
+
+ /* the tree should be empty, so we can pass in
+ * NULL for the fd & fk parameters.
+ */
+ H5TB_dfree(cache_ptr->tree_ptr, NULL, NULL);
+ cache_ptr->tree_ptr = NULL;
+ }
+
+ cache_ptr->magic = 0;
+
+ H5FL_FREE(H5C_t, cache_ptr);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_dest_empty() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_flush_cache
+ *
+ * Purpose: Flush (and possibly destroy) the entries contained in the
+ * specified cache.
+ *
+ * If the cache contains protected entries, the function will
+ * fail, as protected entries cannot be flushed. However
+ * all unprotected entries should be flushed before the
+ * function returns failure.
+ *
+ * The primary_dxpl_id and secondary_dxpl_id parameters
+ * specify the dxpl_ids used on the first write occasioned
+ * by the flush (primary_dxpl_id), and on all subsequent
+ * writes (secondary_dxpl_id). This is useful in the metadata
+ * cache, but may not be needed elsewhere. If so, just use the
+ * same dxpl_id for both parameters.
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * a request to flush all items and something was protected.
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ * Modifications:
+ *
+ * JRM -- 7/20/04
+ * Modified the function for the addition of the hash table.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_flush_cache(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ unsigned flags)
+{
+ herr_t status;
+ herr_t ret_value = SUCCEED;
+ hbool_t destroy = ( (flags & H5F_FLUSH_INVALIDATE) != 0 );
+ hbool_t first_flush = TRUE;
+ int32_t protected_entries = 0;
+ int32_t i;
+ H5TB_NODE * node_ptr;
+ H5C_cache_entry_t * entry_ptr;
+#if H5C_DO_SANITY_CHECKS
+ int32_t actual_tree_len = 0;
+ size_t actual_tree_size = 0;
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ FUNC_ENTER_NOAPI(H5C_flush_cache, FAIL)
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( cache_ptr->skip_file_checks || f );
+ HDassert( cache_ptr->tree_ptr );
+
+ if ( cache_ptr->tree_ptr->root == NULL ) {
+
+ node_ptr = NULL;
+ HDassert( cache_ptr->tree_len == 0 );
+ HDassert( cache_ptr->tree_size == 0 );
+
+ } else {
+
+ node_ptr = H5TB_first(cache_ptr->tree_ptr->root);
+ }
+
+ while ( node_ptr != NULL )
+ {
+ entry_ptr = (H5C_cache_entry_t *)(node_ptr->data);
+
+ HDassert( entry_ptr != NULL );
+ HDassert( entry_ptr->in_tree );
+
+#if H5C_DO_SANITY_CHECKS
+ actual_tree_len++;
+ actual_tree_size += entry_ptr->size;
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ if ( entry_ptr->is_protected ) {
+
+ /* we have major problems -- but lets flush everything
+ * we can before we flag an error.
+ */
+ protected_entries++;
+
+ } else {
+
+ status = H5C_flush_single_entry(f,
+ primary_dxpl_id,
+ secondary_dxpl_id,
+ cache_ptr,
+ NULL,
+ entry_ptr->addr,
+ flags,
+ node_ptr,
+ &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.")
+ }
+ }
+
+ node_ptr = H5TB_next(node_ptr);
+
+ } /* while */
+
+#if H5C_DO_SANITY_CHECKS
+ HDassert( actual_tree_len == cache_ptr->tree_len );
+ HDassert( actual_tree_size == cache_ptr->tree_size );
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ if ( destroy ) {
+
+ /* don't pass in any key or data free functions, as all
+ * unprotected entries should have already been destroyed.
+ */
+ H5TB_free(&(cache_ptr->tree_ptr->root), NULL, NULL);
+ cache_ptr->tree_len = 0;
+ cache_ptr->tree_size = 0;
+
+ /* Since we are doing a destroy, we must make a pass through
+ * the hash table and flush all entries that remain. Note that
+ * all remaining entries entries must be clean, so this will
+ * not result in any writes to disk.
+ */
+ for ( i = 0; i < H5C__HASH_TABLE_LEN; i++ )
+ {
+ while ( cache_ptr->index[i] )
+ {
+ entry_ptr = cache_ptr->index[i];
+
+ if ( entry_ptr->is_protected ) {
+
+ /* we have major problems -- but lets flush and destroy
+ * everything we can before we flag an error.
+ */
+
+ H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr)
+
+ if ( !entry_ptr->in_tree ) {
+
+ protected_entries++;
+ HDassert( !(entry_ptr->is_dirty) );
+ }
+ } else {
+
+ HDassert( !(entry_ptr->is_dirty) );
+ HDassert( !(entry_ptr->in_tree) );
+
+ status = H5C_flush_single_entry(f,
+ primary_dxpl_id,
+ secondary_dxpl_id,
+ cache_ptr,
+ NULL,
+ entry_ptr->addr,
+ flags,
+ NULL,
+ &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.")
+ }
+ }
+ }
+ }
+
+ HDassert( protected_entries == cache_ptr->pl_len );
+
+ if ( protected_entries > 0 )
+ {
+ /* the caller asked us to flush and destroy a cache that
+ * contains one or more protected entries. Since we can't
+ * flush protected entries, we haven't destroyed them either.
+ * Since they are all on the protected list, just re-insert
+ * them into the cache before we flag an error.
+ */
+ entry_ptr = cache_ptr->pl_head_ptr;
+
+ while ( entry_ptr != NULL )
+ {
+ entry_ptr->in_tree = FALSE;
+
+ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL)
+
+ if ( entry_ptr->is_dirty ) {
+
+ H5C__INSERT_ENTRY_IN_TREE(cache_ptr, entry_ptr)
+ }
+ entry_ptr = entry_ptr->next;
+ }
+ }
+ }
+
+ HDassert( protected_entries <= cache_ptr->pl_len );
+
+ if ( cache_ptr->pl_len > 0 ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_PROTECT, FAIL, "cache has protected items")
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_flush_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_insert_entry
+ *
+ * Purpose: Adds the specified thing to the cache. The thing need not
+ * exist on disk yet, but it must have an address and disk
+ * space reserved.
+ *
+ * The primary_dxpl_id and secondary_dxpl_id parameters
+ * specify the dxpl_ids used on the first write occasioned
+ * by the insertion (primary_dxpl_id), and on all subsequent
+ * writes (secondary_dxpl_id). This is useful in the
+ * metadata cache, but may not be needed elsewhere. If so,
+ * just use the same dxpl_id for both parameters.
+ *
+ * The primary_dxpl_id is the dxpl_id passed to the
+ * check_write_permitted function if such a function has been
+ * provided.
+ *
+ * Observe that this function cannot occasion a read.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ * Modifications:
+ *
+ * JRM -- 7/21/04
+ * Updated function for the addition of the hash table.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+herr_t
+H5C_insert_entry(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ const H5C_class_t * type,
+ haddr_t addr,
+ void * thing)
+{
+ herr_t result;
+ herr_t ret_value = SUCCEED; /* Return value */
+ hbool_t write_permitted = TRUE;
+ H5C_cache_entry_t * entry_ptr;
+ H5C_cache_entry_t * test_entry_ptr;
+
+ FUNC_ENTER_NOAPI(H5C_insert_entry, FAIL)
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( cache_ptr->skip_file_checks || f );
+ HDassert( type );
+ HDassert( type->flush );
+ HDassert( type->size );
+ HDassert( H5F_addr_defined(addr) );
+ HDassert( thing );
+
+ entry_ptr = (H5C_cache_entry_t *)thing;
+
+ entry_ptr->addr = addr;
+ entry_ptr->type = type;
+
+ if ( (type->size)(f, thing, &(entry_ptr->size)) < 0 ) {
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGETSIZE, FAIL, \
+ "Can't get size of thing")
+ }
+
+ HDassert( entry_ptr->size < H5C_MAX_ENTRY_SIZE );
+
+ entry_ptr->in_tree = FALSE;
+
+ entry_ptr->ht_next = NULL;
+ entry_ptr->ht_prev = NULL;
+
+ entry_ptr->next = NULL;
+ entry_ptr->prev = NULL;
+
+ entry_ptr->aux_next = NULL;
+ entry_ptr->aux_prev = NULL;
+
+ H5C__RESET_CACHE_ENTRY_STATS(entry_ptr)
+
+ if ((cache_ptr->index_size + entry_ptr->size) > cache_ptr->max_cache_size) {
+
+ size_t space_needed;
+
+ if ( cache_ptr->check_write_permitted != NULL ) {
+
+ result = (cache_ptr->check_write_permitted)(f,
+ primary_dxpl_id,
+ &write_permitted);
+
+ if ( result < 0 ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, \
+ "Can't get write_permitted")
+ }
+ }
+
+ HDassert( entry_ptr->size <= H5C_MAX_ENTRY_SIZE );
+
+ space_needed = (cache_ptr->index_size + entry_ptr->size) -
+ cache_ptr->max_cache_size;
+
+ /* It would be nice to be able to do a tight sanity check on
+ * space_needed here, but it is hard to assign an upper bound on
+ * its value other than then value assigned to it.
+ *
+ * This fact springs from several features of the cache:
+ *
+ * First, it is possible for the cache to grow without
+ * bound as long as entries are protected and not unprotected.
+ *
+ * Second, when writes are not permitted it is also possible
+ * for the cache to grow without bound.
+ *
+ * Finally, we don't check to see if the cache is oversized
+ * at the end of an unprotect. As a result, it is possible
+ * to have a vastly oversized cache with no protected entries
+ * as long as all the protects preceed the unprotects.
+ *
+ * Since items 1 and 2 are not changing any time soon, I see
+ * no point in worrying about the third.
+ *
+ * In any case, I hope this explains why there is no sanity
+ * check on space_needed here.
+ */
+
+ result = H5C_make_space_in_cache(f,
+ primary_dxpl_id,
+ secondary_dxpl_id,
+ cache_ptr,
+ space_needed,
+ write_permitted);
+
+ if ( result < 0 ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, \
+ "H5C_make_space_in_cache failed.")
+ }
+ }
+
+ /* verify that the new entry isn't already in the hash table -- scream
+ * and die if it is.
+ */
+
+ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL)
+
+ if ( test_entry_ptr != NULL ) {
+
+ if ( test_entry_ptr == entry_ptr ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, \
+ "entry already in cache.")
+
+ } else {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, \
+ "duplicate entry in cache.")
+ }
+ }
+
+ /* we don't initialize the protected field until here as it is
+ * possible that the entry is already in the cache, and already
+ * protected. If it is, we don't want to make things worse by
+ * marking it unprotected.
+ */
+
+ entry_ptr->is_protected = FALSE;
+
+ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL)
+
+ if ( entry_ptr->is_dirty ) {
+
+ H5C__INSERT_ENTRY_IN_TREE(cache_ptr, entry_ptr)
+ }
+
+ H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, FAIL)
+
+ H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr)
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_insert_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_rename_entry
+ *
+ * Purpose: Use this function to notify the cache that an entry's
+ * file address changed.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ * Modifications:
+ *
+ * JRM -- 7/21/04
+ * Updated function for the addition of the hash table.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+herr_t
+H5C_rename_entry(H5F_t * f,
+ H5C_t * cache_ptr,
+ const H5C_class_t * type,
+ haddr_t old_addr,
+ haddr_t new_addr)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ H5TB_NODE * old_node_ptr = NULL;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ H5C_cache_entry_t * test_entry_ptr = NULL;
+ H5C_cache_entry_t search_target;
+
+ FUNC_ENTER_NOAPI(H5C_rename_entry, FAIL)
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( cache_ptr->skip_file_checks || f );
+ HDassert( type );
+ HDassert( H5F_addr_defined(old_addr) );
+ HDassert( H5F_addr_defined(new_addr) );
+ HDassert( H5F_addr_ne(old_addr, new_addr) );
+
+ H5C__SEARCH_INDEX(cache_ptr, old_addr, entry_ptr, FAIL)
+
+ if ( ( entry_ptr == NULL ) || ( entry_ptr->type != type ) ) {
+
+ /* the old item doesn't exist in the cache, so we are done. */
+ HGOTO_DONE(SUCCEED)
+
+ } else {
+
+ HDassert( entry_ptr->addr == old_addr );
+ HDassert( entry_ptr->type == type );
+ HDassert( !(entry_ptr->is_protected) );
+
+ if ( entry_ptr->in_tree ) {
+
+ HDassert( cache_ptr->tree_ptr );
+ search_target.addr = old_addr;
+
+ old_node_ptr = H5TB_dfind(cache_ptr->tree_ptr,
+ (void *)(&search_target),
+ NULL);
+
+ HDassert( old_node_ptr != NULL );
+ HDassert( old_node_ptr->key == (void *)entry_ptr );
+ }
+ }
+
+ H5C__SEARCH_INDEX(cache_ptr, new_addr, test_entry_ptr, FAIL)
+
+ if ( test_entry_ptr != NULL ) { /* we are hosed */
+
+ if ( test_entry_ptr->type == type ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTRENAME, FAIL, \
+ "Target already renamed & reinserted???.")
+
+ } else {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTRENAME, FAIL, \
+ "New address already in use?.")
+ }
+ }
+
+ /* If we get this far, we have work to do. Remove *entry_ptr from
+ * the hash table (and tree if necessary), change its address to the
+ * new address, and then re-insert.
+ *
+ * Update the replacement policy for a hit to avoid an eviction before
+ * the renamed entry is touched. Update stats for a rename.
+ *
+ * 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.
+ */
+ H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr)
+
+ if ( old_node_ptr ) {
+
+ H5C__REMOVE_ENTRY_FROM_TREE(cache_ptr, entry_ptr, old_node_ptr)
+ }
+
+ entry_ptr->addr = new_addr;
+
+ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL)
+
+ if ( entry_ptr->is_dirty ) {
+
+ H5C__INSERT_ENTRY_IN_TREE(cache_ptr, entry_ptr)
+ }
+
+ H5C__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, FAIL)
+
+ H5C__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr)
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_rename_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_protect
+ *
+ * Purpose: If the target entry is not in the cache, load it. If
+ * necessary, attempt to evict one or more entries to keep
+ * the cache within its maximum size.
+ *
+ * Mark the target entry as protected, and return its address
+ * to the caller. The caller must call H5C_unprotect() when
+ * finished with the entry.
+ *
+ * While it is protected, the entry may not be either evicted
+ * or flushed -- nor may it be accessed by another call to
+ * H5C_protect. Any attempt to do so will result in a failure.
+ *
+ * The primary_dxpl_id and secondary_dxpl_id parameters
+ * specify the dxpl_ids used on the first write occasioned
+ * by the insertion (primary_dxpl_id), and on all subsequent
+ * writes (secondary_dxpl_id). This is useful in the
+ * metadata cache, but may not be needed elsewhere. If so,
+ * just use the same dxpl_id for both parameters.
+ *
+ * All reads are performed with the primary_dxpl_id.
+ *
+ * Similarly, the primary_dxpl_id is passed to the
+ * check_write_permitted function if it is called.
+ *
+ * Return: Success: Ptr to the desired entry
+ *
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer - 6/2/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/21/04
+ * Updated for the addition of the hash table.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+void *
+H5C_protect(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ const H5C_class_t * type,
+ haddr_t addr,
+ const void * udata1,
+ void * udata2)
+{
+ hbool_t hit = FALSE;
+ void * thing = NULL;
+ H5C_cache_entry_t * entry_ptr;
+ void * ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5C_protect, NULL)
+
+ /* check args */
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( cache_ptr->skip_file_checks || f );
+ HDassert( type );
+ HDassert( type->flush );
+ HDassert( type->load );
+ HDassert( H5F_addr_defined(addr) );
+
+ /* first check to see if the target is in cache */
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, NULL)
+
+ if ( entry_ptr != NULL ) {
+
+ hit = TRUE;
+ thing = (void *)entry_ptr;
+
+ } else { /* must try to load the entry from disk. */
+
+ hit = FALSE;
+ thing = H5C_load_entry(f, primary_dxpl_id, type, addr, udata1, udata2,
+ cache_ptr->skip_file_checks);
+
+ if ( thing == NULL ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "can't load entry")
+ }
+
+ entry_ptr = (H5C_cache_entry_t *)thing;
+
+ /* try to free up some space if necessay */
+ if ( (cache_ptr->index_size + entry_ptr->size) >
+ cache_ptr->max_cache_size ) {
+
+ hbool_t write_permitted = TRUE;
+ herr_t result;
+ size_t space_needed;
+
+ if ( cache_ptr->check_write_permitted != NULL ) {
+
+ result = (cache_ptr->check_write_permitted)(f,
+ primary_dxpl_id,
+ &write_permitted);
+
+ if ( result < 0 ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, \
+ "Can't get write_permitted")
+ }
+ }
+
+ HDassert( entry_ptr->size <= H5C_MAX_ENTRY_SIZE );
+
+ space_needed = (cache_ptr->index_size + entry_ptr->size) -
+ cache_ptr->max_cache_size;
+
+ /* It would be nice to be able to do a tight sanity check on
+ * space_needed here, but it is hard to assign an upper bound on
+ * its value other than then value assigned to it.
+ *
+ * This fact springs from several features of the cache:
+ *
+ * First, it is possible for the cache to grow without
+ * bound as long as entries are protected and not unprotected.
+ *
+ * Second, when writes are not permitted it is also possible
+ * for the cache to grow without bound.
+ *
+ * Finally, we don't check to see if the cache is oversized
+ * at the end of an unprotect. As a result, it is possible
+ * to have a vastly oversized cache with no protected entries
+ * as long as all the protects preceed the unprotects.
+ *
+ * Since items 1 and 2 are not changing any time soon, I see
+ * no point in worrying about the third.
+ *
+ * In any case, I hope this explains why there is no sanity
+ * check on space_needed here.
+ */
+
+ result = H5C_make_space_in_cache(f, primary_dxpl_id,
+ secondary_dxpl_id, cache_ptr,
+ space_needed, write_permitted);
+
+ if ( result < 0 ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, \
+ "H5C_make_space_in_cache failed.")
+ }
+ }
+
+ /* Insert the entry in the hash table. It can't be dirty yet, so
+ * we don't even check to see if it should go in the tree.
+ */
+ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, NULL)
+
+ /* insert the entry in the data structures used by the replacement
+ * policy. We are just going to take it out again when we update
+ * the replacement policy for a protect, but this simplifies the
+ * code. If we do this often enough, we may want to optimize this.
+ */
+ H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, NULL)
+ }
+
+ HDassert( entry_ptr->addr == addr );
+ HDassert( entry_ptr->type == type );
+
+ if ( entry_ptr->is_protected ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, \
+ "Target already protected?!?.")
+ }
+
+ H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, NULL)
+
+ entry_ptr->is_protected = TRUE;
+
+ ret_value = thing;
+
+ H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit)
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_protect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_unprotect
+ *
+ * Purpose: Undo an H5C_protect() call -- specifically, mark the
+ * entry as unprotected, remove it from the protected list,
+ * and give it back to the replacement policy.
+ *
+ * The TYPE and ADDR arguments must be the same as those in
+ * the corresponding call to H5C_protect() and the THING
+ * argument must be the value returned by that call to
+ * H5C_protect().
+ *
+ * The primary_dxpl_id and secondary_dxpl_id parameters
+ * specify the dxpl_ids used on the first write occasioned
+ * by the unprotect (primary_dxpl_id), and on all subsequent
+ * writes (secondary_dxpl_id). Since an uprotect cannot
+ * occasion a write at present, all this is moot for now.
+ * However, things change, and in any case,
+ * H5C_flush_single_entry() needs primary_dxpl_id and
+ * secondary_dxpl_id in its parameter list.
+ *
+ * The function can't cause a read either, so the dxpl_id
+ * parameters are moot in this case as well.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * If the deleted flag is TRUE, simply remove the target entry
+ * from the cache, clear it, and free it without writing it to
+ * disk.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/21/04
+ * Updated the function for the addition of the hash table.
+ * In particular, we now add dirty entries to the tree if
+ * they aren't in the tree already.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5C_unprotect(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ const H5C_class_t * type,
+ haddr_t addr,
+ void * thing,
+ hbool_t deleted)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+ H5C_cache_entry_t * entry_ptr;
+ H5C_cache_entry_t * test_entry_ptr;
+
+ FUNC_ENTER_NOAPI(H5C_unprotect, FAIL)
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+ HDassert( cache_ptr->skip_file_checks || f );
+ HDassert( type );
+ HDassert( type->clear );
+ HDassert( type->flush );
+ HDassert( H5F_addr_defined(addr) );
+ HDassert( thing );
+
+ entry_ptr = (H5C_cache_entry_t *)thing;
+
+ HDassert( entry_ptr->addr == addr );
+ HDassert( entry_ptr->type == type );
+
+ if ( ! (entry_ptr->is_protected) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \
+ "Entry already unprotected??")
+ }
+
+ H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, FAIL)
+
+ entry_ptr->is_protected = FALSE;
+
+ /* add the entry to the tree if it is dirty, and it isn't already in
+ * the tree.
+ */
+
+ if ( ( entry_ptr->is_dirty ) && ( ! (entry_ptr->in_tree) ) ) {
+
+ H5C__INSERT_ENTRY_IN_TREE(cache_ptr, entry_ptr)
+ }
+
+ /* this implementation of the "deleted" option is a bit inefficient, as
+ * we re-insert the entry to be deleted into the replacement policy
+ * data structures, only to remove them again. Depending on how often
+ * we do this, we may want to optimize a bit.
+ *
+ * On the other hand, this implementation is reasonably clean, and
+ * makes good use of existing code.
+ * JRM - 5/19/04
+ */
+ if ( deleted ) {
+
+ /* the following first flush flag will never be used as we are
+ * calling H5C_flush_single_entry with both the H5F_FLUSH_CLEAR_ONLY
+ * and H5F_FLUSH_INVALIDATE flags. However, it is needed for the
+ * function call.
+ */
+ hbool_t dummy_first_flush = TRUE;
+
+ /* verify that the target entry is in the cache. */
+
+ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL)
+
+ if ( test_entry_ptr == NULL ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \
+ "entry not in hash table?!?.")
+ }
+ else if ( test_entry_ptr != entry_ptr ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \
+ "hash table contains multiple entries for addr?!?.")
+ }
+
+ if ( H5C_flush_single_entry(f,
+ primary_dxpl_id,
+ secondary_dxpl_id,
+ cache_ptr,
+ type,
+ addr,
+ (H5F_FLUSH_CLEAR_ONLY|H5F_FLUSH_INVALIDATE),
+ NULL,
+ &dummy_first_flush,
+ TRUE) < 0 ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Can't flush.")
+ }
+ }
+
+ H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr)
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_unprotect() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_stats
+ *
+ * Purpose: Prints statistics about the cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/2/04
+ *
+ * Modifications:
+ *
+ * JRM -- 7/21/04
+ * Updated function for the addition of the hash table.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+herr_t
+H5C_stats(H5C_t * cache_ptr,
+ const char * cache_name,
+ hbool_t
+#if !H5C_COLLECT_CACHE_STATS
+ UNUSED
+#endif /* H5C_COLLECT_CACHE_STATS */
+ display_detailed_stats)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+#if H5C_COLLECT_CACHE_STATS
+ int i;
+ int64_t total_hits = 0;
+ int64_t total_misses = 0;
+ int64_t total_insertions = 0;
+ int64_t total_clears = 0;
+ int64_t total_flushes = 0;
+ int64_t total_evictions = 0;
+ int64_t total_renames = 0;
+ int32_t aggregate_max_accesses = 0;
+ int32_t aggregate_min_accesses = 1000000;
+ int32_t aggregate_max_clears = 0;
+ int32_t aggregate_max_flushes = 0;
+ size_t aggregate_max_size = 0;
+ double hit_rate;
+ double average_successful_search_depth = 0.0;
+ double average_failed_search_depth = 0.0;
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ FUNC_ENTER_NOAPI(H5C_stats, FAIL)
+
+ /* This would normally be an assert, but we need to use an HGOTO_ERROR
+ * call to shut up the compiler.
+ */
+ if ( ( ! cache_ptr ) ||
+ ( cache_ptr->magic != H5C__H5C_T_MAGIC ) ||
+ ( !cache_name ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr or cache_name")
+ }
+
+#if H5C_COLLECT_CACHE_STATS
+
+ for ( i = 0; i <= cache_ptr->max_type_id; i++ ) {
+
+ total_hits += cache_ptr->hits[i];
+ total_misses += cache_ptr->misses[i];
+ total_insertions += cache_ptr->insertions[i];
+ total_clears += cache_ptr->clears[i];
+ total_flushes += cache_ptr->flushes[i];
+ total_evictions += cache_ptr->evictions[i];
+ total_renames += cache_ptr->renames[i];
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+ if ( aggregate_max_accesses < cache_ptr->max_accesses[i] )
+ aggregate_max_accesses = cache_ptr->max_accesses[i];
+ if ( aggregate_min_accesses > aggregate_max_accesses )
+ aggregate_min_accesses = aggregate_max_accesses;
+ if ( aggregate_min_accesses > cache_ptr->min_accesses[i] )
+ aggregate_min_accesses = cache_ptr->min_accesses[i];
+ if ( aggregate_max_clears < cache_ptr->max_clears[i] )
+ aggregate_max_clears = cache_ptr->max_clears[i];
+ if ( aggregate_max_flushes < cache_ptr->max_flushes[i] )
+ aggregate_max_flushes = cache_ptr->max_flushes[i];
+ if ( aggregate_max_size < cache_ptr->max_size[i] )
+ aggregate_max_size = cache_ptr->max_size[i];
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+ }
+
+ if ( ( total_hits > 0 ) || ( total_misses > 0 ) ) {
+
+ hit_rate = 100.0 * ((double)(total_hits)) /
+ ((double)(total_hits + total_misses));
+ } else {
+ hit_rate = 0.0;
+ }
+
+ if ( cache_ptr->successful_ht_searches > 0 ) {
+
+ average_successful_search_depth =
+ ((double)(cache_ptr->total_successful_ht_search_depth)) /
+ ((double)(cache_ptr->successful_ht_searches));
+ }
+
+ if ( cache_ptr->failed_ht_searches > 0 ) {
+
+ average_failed_search_depth =
+ ((double)(cache_ptr->total_failed_ht_search_depth)) /
+ ((double)(cache_ptr->failed_ht_searches));
+ }
+
+
+ HDfprintf(stdout, "\nH5C: cache statistics for %s\n",
+ cache_name);
+
+ HDfprintf(stdout, "\n");
+
+ HDfprintf(stdout,
+ " hash table insertion / deletions = %ld / %ld\n",
+ (long)(cache_ptr->total_ht_insertions),
+ (long)(cache_ptr->total_ht_deletions));
+
+ HDfprintf(stdout,
+ " HT successful / failed searches = %ld / %ld\n",
+ (long)(cache_ptr->successful_ht_searches),
+ (long)(cache_ptr->failed_ht_searches));
+
+ HDfprintf(stdout,
+ " Av. HT suc / failed search depth = %f / %f\n",
+ average_successful_search_depth,
+ average_failed_search_depth);
+
+ HDfprintf(stdout,
+ " current (max) index size / length = %ld (%ld) / %ld (%ld)\n",
+ (long)(cache_ptr->index_size),
+ (long)(cache_ptr->max_index_size),
+ (long)(cache_ptr->index_len),
+ (long)(cache_ptr->max_index_len));
+
+ HDfprintf(stdout,
+ " current (max) tree size / length = %ld (%ld) / %ld (%ld)\n",
+ (long)(cache_ptr->tree_size),
+ (long)(cache_ptr->max_tree_size),
+ (long)(cache_ptr->tree_len),
+ (long)(cache_ptr->max_tree_len));
+
+ HDfprintf(stdout,
+ " current (max) PL size / length = %ld (%ld) / %ld (%ld)\n",
+ (long)(cache_ptr->pl_size),
+ (long)(cache_ptr->max_pl_size),
+ (long)(cache_ptr->pl_len),
+ (long)(cache_ptr->max_pl_len));
+
+ HDfprintf(stdout,
+ " current LRU list size / length = %ld / %ld\n",
+ (long)(cache_ptr->LRU_list_size),
+ (long)(cache_ptr->LRU_list_len));
+
+ HDfprintf(stdout,
+ " current clean LRU size / length = %ld / %ld\n",
+ (long)(cache_ptr->cLRU_list_size),
+ (long)(cache_ptr->cLRU_list_len));
+
+ HDfprintf(stdout,
+ " current dirty LRU size / length = %ld / %ld\n",
+ (long)(cache_ptr->dLRU_list_size),
+ (long)(cache_ptr->dLRU_list_len));
+
+ HDfprintf(stdout,
+ " Total hits / misses / hit_rate = %ld / %ld / %f\n",
+ (long)total_hits,
+ (long)total_misses,
+ hit_rate);
+
+ HDfprintf(stdout,
+ " Total clears / flushes / evictions = %ld / %ld / %ld\n",
+ (long)total_clears,
+ (long)total_flushes,
+ (long)total_evictions);
+
+ HDfprintf(stdout, " Total insertions / renames = %ld / %ld\n",
+ (long)total_insertions,
+ (long)total_renames);
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+
+ HDfprintf(stdout, " aggregate max / min accesses = %d / %d\n",
+ (int)aggregate_max_accesses,
+ (int)aggregate_min_accesses);
+
+ HDfprintf(stdout, " aggregate max_clears / max_flushes = %d / %d\n",
+ (int)aggregate_max_clears,
+ (int)aggregate_max_flushes);
+
+ HDfprintf(stdout, " aggregate max_size = %d\n",
+ (int)aggregate_max_size);
+
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+ if ( display_detailed_stats )
+ {
+
+ for ( i = 0; i <= cache_ptr->max_type_id; i++ ) {
+
+ HDfprintf(stdout, "\n");
+
+ HDfprintf(stdout, " Stats on %s:\n",
+ ((cache_ptr->type_name_table_ptr))[i]);
+
+ if ( ( cache_ptr->hits[i] > 0 ) || ( cache_ptr->misses[i] > 0 ) ) {
+
+ hit_rate = 100.0 * ((double)(cache_ptr->hits[i])) /
+ ((double)(cache_ptr->hits[i] + cache_ptr->misses[i]));
+ } else {
+ hit_rate = 0.0;
+ }
+
+ HDfprintf(stdout,
+ " hits / misses / hit_rate = %ld / %ld / %f\n",
+ (long)(cache_ptr->hits[i]),
+ (long)(cache_ptr->misses[i]),
+ hit_rate);
+
+ HDfprintf(stdout,
+ " clears / flushes / evictions = %ld / %ld / %ld\n",
+ (long)(cache_ptr->clears[i]),
+ (long)(cache_ptr->flushes[i]),
+ (long)(cache_ptr->evictions[i]));
+
+ HDfprintf(stdout,
+ " insertions / renames = %ld / %ld\n",
+ (long)(cache_ptr->insertions[i]),
+ (long)(cache_ptr->renames[i]));
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+
+ HDfprintf(stdout,
+ " entry max / min accesses = %d / %d\n",
+ cache_ptr->max_accesses[i],
+ cache_ptr->min_accesses[i]);
+
+ HDfprintf(stdout,
+ " entry max_clears / max_flushes = %d / %d\n",
+ cache_ptr->max_clears[i],
+ cache_ptr->max_flushes[i]);
+
+ HDfprintf(stdout,
+ " entry max_size = %d\n",
+ (int)(cache_ptr->max_size[i]));
+
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+ }
+ }
+
+ HDfprintf(stdout, "\n");
+
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_stats() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_stats__reset
+ *
+ * Purpose: Reset the stats fields to their initial values.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer, 4/28/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/21/04
+ * Updated for hash table related statistics.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+void
+H5C_stats__reset(H5C_t * cache_ptr)
+{
+#if H5C_COLLECT_CACHE_STATS
+ int i;
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+#if H5C_COLLECT_CACHE_STATS
+ for ( i = 0; i <= cache_ptr->max_type_id; i++ )
+ {
+ cache_ptr->hits[i] = 0;
+ cache_ptr->misses[i] = 0;
+ cache_ptr->insertions[i] = 0;
+ cache_ptr->clears[i] = 0;
+ cache_ptr->flushes[i] = 0;
+ cache_ptr->evictions[i] = 0;
+ cache_ptr->renames[i] = 0;
+ }
+
+ cache_ptr->total_ht_insertions = 0;
+ cache_ptr->total_ht_deletions = 0;
+ cache_ptr->successful_ht_searches = 0;
+ cache_ptr->total_successful_ht_search_depth = 0;
+ cache_ptr->failed_ht_searches = 0;
+ cache_ptr->total_failed_ht_search_depth = 0;
+
+ cache_ptr->max_index_len = 0;
+ cache_ptr->max_index_size = (size_t)0;
+
+ cache_ptr->max_tree_len = 0;
+ cache_ptr->max_tree_size = (size_t)0;
+
+ cache_ptr->max_pl_len = 0;
+ cache_ptr->max_pl_size = (size_t)0;
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+
+ for ( i = 0; i <= cache_ptr->max_type_id; i++ )
+ {
+ cache_ptr->max_accesses[i] = 0;
+ cache_ptr->min_accesses[i] = 1000000;
+ cache_ptr->max_clears[i] = 0;
+ cache_ptr->max_flushes[i] = 0;
+ cache_ptr->max_size[i] = (size_t)0;
+ }
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ return;
+
+} /* H5C_stats__reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5C_set_skip_flags
+ *
+ * Purpose: Set the values of the skip sanity check flags.
+ *
+ * This function and the skip sanity check flags were created
+ * for the convenience of the test bed. However it is
+ * possible that there may be other uses for the flags.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 6/11/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+herr_t
+H5C_set_skip_flags(H5C_t * cache_ptr,
+ hbool_t skip_file_checks,
+ hbool_t skip_dxpl_id_checks)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5C_set_skip_flags, FAIL)
+
+ /* This would normally be an assert, but we need to use an HGOTO_ERROR
+ * call to shut up the compiler.
+ */
+ if ( ( ! cache_ptr ) || ( cache_ptr->magic != H5C__H5C_T_MAGIC ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr")
+ }
+
+ cache_ptr->skip_file_checks = skip_file_checks;
+ cache_ptr->skip_dxpl_id_checks = skip_dxpl_id_checks;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_set_skip_flags() */
+
+
+/*************************************************************************/
+/**************************** Private Functions: *************************/
+/*************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_flush_single_entry
+ *
+ * Purpose: Flush or clear (and evict if requested) the cache entry
+ * with the specified address and type. If the type is NULL,
+ * any unprotected entry at the specified address will be
+ * flushed (and possibly evicted).
+ *
+ * Attempts to flush a protected entry will result in an
+ * error.
+ *
+ * *first_flush_ptr should be true if only one
+ * flush is contemplated before the next load, or if this
+ * is the first of a sequence of flushes that will be
+ * completed before the next load. *first_flush_ptr is set
+ * to false if a flush actually takes place, and should be
+ * left false until the end of the sequence.
+ *
+ * The primary_dxpl_id is used if *first_flush_ptr is TRUE
+ * on entry, and a flush actually takes place. The
+ * secondary_dxpl_id is used in any subsequent flush where
+ * *first_flush_ptr is FALSE on entry.
+ *
+ * If the H5F_FLUSH_CLEAR_ONLY flag is set, the entry will
+ * be cleared and not flushed -- in the case *first_flush_ptr,
+ * primary_dxpl_id, and secondary_dxpl_id are all irrelevent,
+ * and the call can't be part of a sequence of flushes.
+ *
+ * If the caller knows the address of the TBBT node at
+ * which the target entry resides, it can avoid a lookup
+ * by supplying that address in the tgt_node_ptr parameter.
+ * If this parameter is NULL, the function will do a TBBT
+ * search for the entry instead.
+ *
+ * The function does nothing silently if there is no entry
+ * at the supplied address, or if the entry found has the
+ * wrong type.
+ *
+ * Return: Non-negative on success/Negative on failure or if there was
+ * an attempt to flush a protected item.
+ *
+ * Programmer: John Mainzer, 5/5/04
+ *
+ * Modifications:
+ *
+ * JRM -- 7/21/04
+ * Updated function for the addition of the hash table.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5C_flush_single_entry(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ const H5C_class_t * type_ptr,
+ haddr_t addr,
+ unsigned flags,
+ H5TB_NODE * tgt_node_ptr,
+ hbool_t * first_flush_ptr,
+ hbool_t del_entry_from_tree_on_destroy)
+{
+ hbool_t destroy = ( (flags & H5F_FLUSH_INVALIDATE) != 0 );
+ hbool_t clear_only = ( (flags & H5F_FLUSH_CLEAR_ONLY) != 0);
+ herr_t ret_value = SUCCEED; /* Return value */
+ herr_t status;
+ H5TB_NODE * node_ptr;
+ H5C_cache_entry_t * entry_ptr = NULL;
+ H5C_cache_entry_t search_target;
+
+ 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 );
+ HDassert( H5F_addr_defined(addr) );
+ HDassert( first_flush_ptr );
+
+ /* attempt to find the target entry in the hash table */
+ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
+
+ /* If tgt_node_ptr is NULL, look up the target entry in the tree. */
+
+ if ( tgt_node_ptr == NULL ) {
+
+ HDassert( cache_ptr->tree_ptr );
+ search_target.addr = addr;
+
+ node_ptr = H5TB_dfind(cache_ptr->tree_ptr,
+ (void *)&search_target,
+ NULL);
+
+ } else {
+
+ node_ptr = tgt_node_ptr;
+ }
+
+#if H5C_DO_SANITY_CHECKS
+ if ( node_ptr != NULL ) {
+
+ if ( ( entry_ptr == NULL ) ||
+ ( entry_ptr != (H5C_cache_entry_t *)(node_ptr->data) ) ||
+ ( ! (entry_ptr->in_tree) ) ||
+ ( entry_ptr->addr != addr ) ||
+ ( node_ptr->data != node_ptr->key ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "Hash table and tree out of sync.")
+ }
+ } else if ( entry_ptr != NULL ) {
+
+ if ( ( entry_ptr->in_tree ) ||
+ ( entry_ptr->is_dirty ) ||
+ ( entry_ptr->addr != addr ) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
+ "entry failed sanity checks.")
+ }
+ }
+#endif /* H5C_DO_SANITY_CHECKS */
+
+ if ( ( entry_ptr != NULL ) && ( entry_ptr->is_protected ) )
+ {
+ /* Attempt to flush a protected entry -- scream and die. */
+ HGOTO_ERROR(H5E_CACHE, H5E_PROTECT, FAIL, \
+ "Attempt to flush a protected entry.")
+ }
+
+ if ( ( entry_ptr != NULL ) &&
+ ( ( type_ptr == NULL ) || ( type_ptr->id == entry_ptr->type->id ) ) )
+ {
+ /* we have work to do */
+
+#ifdef H5_HAVE_PARALLEL
+#ifndef NDEBUG
+
+ /* If MPI based VFD is used, do special parallel I/O sanity checks.
+ * Note that we only do these sanity checks when the clear_only flag
+ * is not set, and the entry to be flushed is dirty. Don't bother
+ * otherwise as no file I/O can result.
+ *
+ * There are also cases (testing for instance) where it is convenient
+ * to pass in dummy dxpl_ids. Since we don't use the dxpl_ids directly,
+ * this isn't a problem -- but we do have to turn off sanity checks
+ * involving them. We use cache_ptr->skip_dxpl_id_checks to do this.
+ */
+ if ( ( ! cache_ptr->skip_dxpl_id_checks ) &&
+ ( ! clear_only ) &&
+ ( entry_ptr->is_dirty ) &&
+ ( IS_H5FD_MPI(f) ) ) {
+
+ H5P_genplist_t *dxpl; /* Dataset transfer property list */
+ H5FD_mpio_xfer_t xfer_mode; /* I/O xfer mode property value */
+
+ /* Get the dataset transfer property list */
+ if ( NULL == (dxpl = H5I_object(primary_dxpl_id)) ) {
+
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, \
+ "not a dataset creation property list")
+ }
+
+ /* Get the transfer mode property */
+ if( H5P_get(dxpl, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0 ) {
+
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, \
+ "can't retrieve xfer mode")
+ }
+
+ /* Sanity check transfer mode */
+ HDassert( xfer_mode == H5FD_MPIO_COLLECTIVE || IS_H5FD_FPHDF5(f) );
+ }
+
+#endif /* NDEBUG */
+#endif /* H5_HAVE_PARALLEL */
+
+ if ( clear_only ) {
+ H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr)
+ } else {
+ H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr)
+ }
+
+ if ( destroy ) {
+ H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr)
+ }
+
+ /* Always remove the entry from the hash table on a destroy. On a
+ * flush with destroy, it is cheaper to discard the tree all at once
+ * rather than remove the entries one by one, so we only delete from
+ * the tree if requested.
+ *
+ * We must do deletions now as the callback routines will free the
+ * entry if destroy is true.
+ */
+ if ( destroy ) {
+
+ H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr)
+
+ if ( ( node_ptr ) && ( del_entry_from_tree_on_destroy ) ) {
+
+ H5C__REMOVE_ENTRY_FROM_TREE(cache_ptr, entry_ptr, node_ptr)
+ }
+ }
+
+ /* Update the replacement policy for the flush or eviction.
+ * Again, do this now so we don't have to reference freed
+ * memory in the destroy case.
+ */
+ if ( destroy ) { /* AKA eviction */
+
+ H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, FAIL)
+
+ } else {
+
+ H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, FAIL)
+ }
+
+ /* Clear the dirty flag only, if requested */
+ if ( clear_only ) {
+ /* Call the callback routine to clear all dirty flags for object */
+ if ( (entry_ptr->type->clear)(f, entry_ptr, destroy) < 0 ) {
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't clear entry")
+ }
+ } else {
+
+ /* Only block for all the processes on the first piece of metadata
+ */
+
+ if ( *first_flush_ptr && entry_ptr->is_dirty ) {
+ status = (entry_ptr->type->flush)(f, primary_dxpl_id, destroy,
+ entry_ptr->addr, entry_ptr);
+ *first_flush_ptr = FALSE;
+ } else {
+ status = (entry_ptr->type->flush)(f, secondary_dxpl_id,
+ destroy, entry_ptr->addr,
+ entry_ptr);
+ }
+
+ if ( status < 0 ) {
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
+ "unable to flush entry")
+ }
+ }
+
+ if ( ! destroy ) {
+
+ HDassert( !(entry_ptr->is_dirty) );
+ }
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_flush_single_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_load_entry
+ *
+ * Purpose: Attempt to load the entry at the specified disk address
+ * and with the specified type into memory. If successful.
+ * return the in memory address of the entry. Return NULL
+ * on failure.
+ *
+ * Note that this function simply loads the entry into
+ * core. It does not insert it into the cache.
+ *
+ * Return: Non-NULL on success / NULL on failure.
+ *
+ * Programmer: John Mainzer, 5/18/04
+ *
+ * Modifications:
+ *
+ * JRM - 7/21/04
+ * Updated function for the addition of the hash table.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void *
+H5C_load_entry(H5F_t * f,
+ hid_t dxpl_id,
+ const H5C_class_t * type,
+ haddr_t addr,
+ const void * udata1,
+ void * udata2,
+ hbool_t skip_file_checks)
+{
+ void * thing = NULL;
+ void * ret_value = NULL;
+ H5C_cache_entry_t * entry_ptr = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT(H5C_load_entry)
+
+ HDassert( skip_file_checks || f );
+ HDassert( type );
+ HDassert( type->load );
+ HDassert( type->size );
+ HDassert( H5F_addr_defined(addr) );
+
+ if ( NULL == (thing = (type->load)(f, dxpl_id, addr, udata1, udata2)) ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "unable to load entry")
+
+ }
+
+ entry_ptr = (H5C_cache_entry_t *)thing;
+
+ HDassert( entry_ptr->is_dirty == FALSE );
+
+ entry_ptr->addr = addr;
+ entry_ptr->type = type;
+ entry_ptr->is_protected = FALSE;
+ entry_ptr->in_tree = FALSE;
+
+ if ( (type->size)(f, thing, &(entry_ptr->size)) < 0 ) {
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGETSIZE, NULL, \
+ "Can't get size of thing")
+ }
+
+ HDassert( entry_ptr->size < H5C_MAX_ENTRY_SIZE );
+
+ entry_ptr->ht_next = NULL;
+ entry_ptr->ht_prev = NULL;
+
+ entry_ptr->next = NULL;
+ entry_ptr->prev = NULL;
+
+ entry_ptr->aux_next = NULL;
+ entry_ptr->aux_prev = NULL;
+
+ H5C__RESET_CACHE_ENTRY_STATS(entry_ptr);
+
+ ret_value = thing;
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_load_entry() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5C_make_space_in_cache
+ *
+ * Purpose: Attempt to evict cache entries until the index_size
+ * is at least needed_space below max_cache_size.
+ *
+ * In passing, also attempt to bring cLRU_list_size to a
+ * value greater than min_clean_size.
+ *
+ * Depending on circumstances, both of these goals may
+ * be impossible, as in parallel mode, we must avoid generating
+ * a write as part of a read (to avoid deadlock in collective
+ * I/O), and in all cases, it is possible (though hopefully
+ * highly unlikely) that the protected list may exceed the
+ * maximum size of the cache.
+ *
+ * Thus the function simply does its best, returning success
+ * unless an error is encountered.
+ *
+ * The primary_dxpl_id and secondary_dxpl_id parameters
+ * specify the dxpl_ids used on the first write occasioned
+ * by the call (primary_dxpl_id), and on all subsequent
+ * writes (secondary_dxpl_id). This is useful in the metadata
+ * cache, but may not be needed elsewhere. If so, just use the
+ * same dxpl_id for both parameters.
+ *
+ * Observe that this function cannot occasion a read.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 5/14/04
+ *
+ * Modifications:
+ *
+ * JRM --7/21/04
+ * Minor modifications in support of the addition of a hash
+ * table to facilitate lookups.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static herr_t
+H5C_make_space_in_cache(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ size_t space_needed,
+ hbool_t write_permitted)
+{
+ hbool_t first_flush = TRUE;
+ herr_t ret_value = SUCCEED; /* Return value */
+ herr_t result;
+ int32_t entries_examined = 0;
+ int32_t initial_list_len;
+ H5C_cache_entry_t * entry_ptr;
+ H5C_cache_entry_t * prev_ptr;
+
+ FUNC_ENTER_NOAPI_NOINIT(H5C_make_space_in_cache)
+
+ HDassert( cache_ptr );
+ HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
+
+ if ( write_permitted ) {
+
+ initial_list_len = cache_ptr->LRU_list_len;
+ entry_ptr = cache_ptr->LRU_tail_ptr;
+
+ while ( ( (cache_ptr->index_size + space_needed)
+ >
+ cache_ptr->max_cache_size
+ )
+ &&
+ ( entries_examined <= (2 * initial_list_len) )
+ &&
+ ( entry_ptr != NULL )
+ )
+ {
+ HDassert( ! (entry_ptr->is_protected) );
+
+ prev_ptr = entry_ptr->prev;
+
+ if ( entry_ptr->is_dirty ) {
+
+ result = H5C_flush_single_entry(f,
+ primary_dxpl_id,
+ secondary_dxpl_id,
+ cache_ptr,
+ entry_ptr->type,
+ entry_ptr->addr,
+ (unsigned)0,
+ NULL,
+ &first_flush,
+ FALSE);
+ } else {
+
+ result = H5C_flush_single_entry(f,
+ primary_dxpl_id,
+ secondary_dxpl_id,
+ cache_ptr,
+ entry_ptr->type,
+ entry_ptr->addr,
+ H5F_FLUSH_INVALIDATE,
+ NULL,
+ &first_flush,
+ TRUE);
+ }
+
+ if ( result < 0 ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
+ "unable to flush entry")
+ }
+
+ entry_ptr = prev_ptr;
+ }
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+ initial_list_len = cache_ptr->dLRU_list_len;
+ entry_ptr = cache_ptr->dLRU_tail_ptr;
+
+ while ( ( cache_ptr->cLRU_list_size < cache_ptr->min_clean_size ) &&
+ ( entries_examined <= initial_list_len ) &&
+ ( entry_ptr != NULL )
+ )
+ {
+ HDassert( ! (entry_ptr->is_protected) );
+ HDassert( entry_ptr->is_dirty );
+ HDassert( entry_ptr->in_tree );
+
+ prev_ptr = entry_ptr->aux_prev;
+
+ result = H5C_flush_single_entry(f,
+ primary_dxpl_id,
+ secondary_dxpl_id,
+ cache_ptr,
+ entry_ptr->type,
+ entry_ptr->addr,
+ (unsigned)0,
+ NULL,
+ &first_flush,
+ FALSE);
+
+ if ( result < 0 ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
+ "unable to flush entry")
+ }
+
+ entry_ptr = prev_ptr;
+ }
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+ } else {
+
+ HDassert( H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS );
+
+ initial_list_len = cache_ptr->cLRU_list_len;
+ entry_ptr = cache_ptr->cLRU_tail_ptr;
+
+ while ( ( (cache_ptr->index_size + space_needed)
+ >
+ cache_ptr->max_cache_size
+ )
+ &&
+ ( entries_examined <= initial_list_len )
+ &&
+ ( entry_ptr != NULL )
+ )
+ {
+ HDassert( ! (entry_ptr->is_protected) );
+ HDassert( ! (entry_ptr->is_dirty) );
+
+ prev_ptr = entry_ptr->aux_prev;
+
+ result = H5C_flush_single_entry(f,
+ primary_dxpl_id,
+ secondary_dxpl_id,
+ cache_ptr,
+ entry_ptr->type,
+ entry_ptr->addr,
+ H5F_FLUSH_INVALIDATE,
+ NULL,
+ &first_flush,
+ TRUE);
+
+ if ( result < 0 ) {
+
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
+ "unable to flush entry")
+ }
+
+ entry_ptr = prev_ptr;
+ }
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* H5C_make_space_in_cache() */
diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h
new file mode 100644
index 0000000..4c14c4c
--- /dev/null
+++ b/src/H5Cprivate.h
@@ -0,0 +1,421 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------
+ *
+ * Created: H5Cprivate.h
+ * 6/3/04
+ * John Mainzer
+ *
+ * Purpose: Constants and typedefs available to the rest of the
+ * library.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef _H5Cprivate_H
+#define _H5Cprivate_H
+
+#include "H5Cpublic.h" /*public prototypes */
+
+/* Pivate headers needed by this header */
+#include "H5private.h" /* Generic Functions */
+#include "H5Fprivate.h" /* File access */
+
+#define H5C_DO_SANITY_CHECKS 0
+
+/* This sanity checking constant was picked out of the air. Increase
+ * or decrease it if appropriate. Its purposes is to detect corrupt
+ * object sizes, so it probably doesn't matter if it is a bit big.
+ *
+ * JRM - 5/17/04
+ */
+#define H5C_MAX_ENTRY_SIZE ((size_t)(10 * 1024 * 1024))
+
+/* H5C_COLLECT_CACHE_STATS controls overall collection of statistics
+ * on cache activity. In general, this #define should be set to 0.
+ */
+#define H5C_COLLECT_CACHE_STATS 0
+
+/* H5C_COLLECT_CACHE_ENTRY_STATS controls collection of statistics
+ * in individual cache entries.
+ *
+ * H5C_COLLECT_CACHE_ENTRY_STATS should only be defined to true if
+ * H5C_COLLECT_CACHE_STATS is also defined to true.
+ */
+#if H5C_COLLECT_CACHE_STATS
+
+#define H5C_COLLECT_CACHE_ENTRY_STATS 1
+
+#else
+
+#define H5C_COLLECT_CACHE_ENTRY_STATS 0
+
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+
+#ifdef H5_HAVE_PARALLEL
+
+/* we must maintain the clean and dirty LRU lists when we are compiled
+ * with parallel support.
+ */
+#define H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS 1
+
+#else /* H5_HAVE_PARALLEL */
+
+/* The clean and dirty LRU lists don't buy us anything here -- we may
+ * want them on for testing on occasion, but in general they should be
+ * off.
+ */
+#define H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS 0
+
+#endif /* H5_HAVE_PARALLEL */
+
+
+/*
+ * Class methods pertaining to caching. Each type of cached object will
+ * have a constant variable with permanent life-span that describes how
+ * to cache the object. That variable will be of type H5C_class_t and
+ * have the following required fields...
+ *
+ * LOAD: Loads an object from disk to memory. The function
+ * should allocate some data structure and return it.
+ *
+ * FLUSH: Writes some data structure back to disk. It would be
+ * wise for the data structure to include dirty flags to
+ * indicate whether it really needs to be written. This
+ * function is also responsible for freeing memory allocated
+ * by the LOAD method if the DEST argument is non-zero (by
+ * calling the DEST method).
+ *
+ * DEST: Just frees memory allocated by the LOAD method.
+ *
+ * CLEAR: Just marks object as non-dirty.
+ *
+ * SIZE: Report the size (on disk) of the specified cache object.
+ * Note that the space allocated on disk may not be contiguous.
+ */
+
+typedef void *(*H5C_load_func_t)(H5F_t *f,
+ hid_t dxpl_id,
+ haddr_t addr,
+ const void *udata1,
+ void *udata2);
+typedef herr_t (*H5C_flush_func_t)(H5F_t *f,
+ hid_t dxpl_id,
+ hbool_t dest,
+ haddr_t addr,
+ void *thing);
+typedef herr_t (*H5C_dest_func_t)(H5F_t *f,
+ void *thing);
+typedef herr_t (*H5C_clear_func_t)(H5F_t *f,
+ void *thing,
+ hbool_t dest);
+typedef herr_t (*H5C_size_func_t)(H5F_t *f,
+ void *thing,
+ size_t *size_ptr);
+
+typedef struct H5C_class_t {
+ int id;
+ H5C_load_func_t load;
+ H5C_flush_func_t flush;
+ H5C_dest_func_t dest;
+ H5C_clear_func_t clear;
+ H5C_size_func_t size;
+} H5C_class_t;
+
+
+/* Type defintions of call back functions used by the cache as a whole */
+
+typedef herr_t (*H5C_write_permitted_func_t)(H5F_t *f,
+ hid_t dxpl_id,
+ hbool_t * write_permitted_ptr);
+
+
+/* Default max cache size and min clean size are give here to make
+ * them generally accessable.
+ */
+
+#define H5C__DEFAULT_MAX_CACHE_SIZE ((size_t)(4 * 1024 * 1024))
+#define H5C__DEFAULT_MIN_CLEAN_SIZE ((size_t)(2 * 1024 * 1024))
+
+
+/****************************************************************************
+ *
+ * structure H5C_cache_entry_t
+ *
+ * Instances of the H5C_cache_entry_t structure are used to store cache
+ * entries in a hash table and sometimes in a threaded balanced binary tree.
+ * See H5TB.c for the particulars of the tree.
+ *
+ * In typical application, this structure is the first field in a
+ * structure to be cached. For historical reasons, the external module
+ * is responsible for managing the is_dirty field. All other fields are
+ * managed by the cache.
+ *
+ * Note that our current implementation of a threaded balanced binary tree
+ * will occasionaly change the node a particular datum is associated with.
+ * Thus this structure does not have a back pointer to its tree node. If we
+ * ever modify the threaded balanced binary tree code to fix this, a back
+ * pointer would save us a few tree traversals.
+ *
+ * The fields of this structure are discussed individually below:
+ *
+ * JRM - 4/26/04
+ *
+ * addr: Base address of the cache entry on disk.
+ *
+ * size: Length of the cache entry on disk. Note that unlike normal
+ * caches, the entries in this cache are of variable length.
+ * The entries should never overlap, and when we do writebacks,
+ * we will want to writeback adjacent entries where possible.
+ *
+ * type: Pointer to the instance of H5C_class_t containing pointers
+ * to the methods for cache entries of the current type. This
+ * field should be NULL when the instance of H5C_cache_entry_t
+ * is not in use.
+ *
+ * The name is not particularly descriptive, but is retained
+ * to avoid changes in existing code.
+ *
+ * is_dirty: Boolean flag indicating whether the contents of the cache
+ * entry has been modified since the last time it was written
+ * to disk.
+ *
+ * NOTE: For historical reasons, this field is not maintained
+ * by the cache. Instead, the module using the cache
+ * sets this flag when it modifies the entry, and the
+ * flush and clear functions supplied by that module
+ * reset the dirty when appropriate.
+ *
+ * This is a bit quirky, so we may want to change this
+ * someday. However it will require a change in the
+ * cache interface.
+ *
+ * is_protected: Boolean flag indicating whether this entry is protected
+ * (or locked, to use more conventional terms). When it is
+ * protected, the entry cannot be flushed or accessed until
+ * it is unprotected (or unlocked -- again to use more
+ * conventional terms).
+ *
+ * Note that protected entries are removed from the LRU lists
+ * and inserted on the protected list.
+ *
+ * in_tree: Boolean flag indicating whether the entry is in the threaded
+ * balanced binary tree. As a general rule, entries are placed
+ * in the tree when they are marked dirty. However they may
+ * remain in the tree after being flushed.
+ *
+ *
+ * Fields supporting the hash table:
+ *
+ * Fields in the cache are indexed by a more or less conventional hash table.
+ * If there are multiple entries in any hash bin, they are stored in a doubly
+ * linked list.
+ *
+ * ht_next: Next pointer used by the hash table to store multiple
+ * entries in a single hash bin. This field points to the
+ * next entry in the doubly linked list of entries in the
+ * hash bin, or NULL if there is no next entry.
+ *
+ * ht_prev: Prev pointer used by the hash table to store multiple
+ * entries in a single hash bin. This field points to the
+ * previous entry in the doubly linked list of entries in
+ * the hash bin, or NULL if there is no previuos entry.
+ *
+ *
+ * Fields supporting replacement policies:
+ *
+ * The cache must have a replacement policy, and it will usually be
+ * necessary for this structure to contain fields supporting that policy.
+ *
+ * While there has been interest in several replacement policies for
+ * this cache, the initial development schedule is tight. Thus I have
+ * elected to support only a modified LRU policy for the first cut.
+ *
+ * When additional replacement policies are added, the fields in this
+ * section will be used in different ways or not at all. Thus the
+ * documentation of these fields is repeated for each replacement policy.
+ *
+ * Modified LRU:
+ *
+ * When operating in parallel mode, we must ensure that a read does not
+ * cause a write. If it does, the process will hang, as the write will
+ * be collective and the other processes will not know to participate.
+ *
+ * To deal with this issue, I have modified the usual LRU policy by adding
+ * clean and dirty LRU lists to the usual LRU list. When reading in
+ * parallel mode, we evict from the clean LRU list only. This implies
+ * that we must try to ensure that the clean LRU list is reasonably well
+ * stocked. See the comments on H5C_t in H5C.c for more details.
+ *
+ * Note that even if we start with a completely clean cache, a sequence
+ * of protects without unprotects can empty the clean LRU list. In this
+ * case, the cache must grow temporarily. At the next write, we will
+ * attempt to evict enough entries to get the cache down to its nominal
+ * maximum size.
+ *
+ * The use of the replacement policy fields under the Modified LRU policy
+ * is discussed below:
+ *
+ * next: Next pointer in either the LRU or the protected list,
+ * depending on the current value of protected. If there
+ * is no next entry on the list, this field should be set
+ * to NULL.
+ *
+ * prev: Prev pointer in either the LRU or the protected list,
+ * depending on the current value of protected. If there
+ * is no previous entry on the list, this field should be
+ * set to NULL.
+ *
+ * aux_next: Next pointer on either the clean or dirty LRU lists.
+ * This entry should be NULL when protected is true. When
+ * protected is false, and dirty is true, it should point
+ * to the next item on the dirty LRU list. When protected
+ * is false, and dirty is false, it should point to the
+ * next item on the clean LRU list. In either case, when
+ * there is no next item, it should be NULL.
+ *
+ * aux_prev: Previous pointer on either the clean or dirty LRU lists.
+ * This entry should be NULL when protected is true. When
+ * protected is false, and dirty is true, it should point
+ * to the previous item on the dirty LRU list. When protected
+ * is false, and dirty is false, it should point to the
+ * previous item on the clean LRU list. In either case, when
+ * there is no previous item, it should be NULL.
+ *
+ *
+ * Cache entry stats collection fields:
+ *
+ * These fields should only be compiled in when both H5C_COLLECT_CACHE_STATS
+ * and H5C_COLLECT_CACHE_ENTRY_STATS are true. When present, they allow
+ * collection of statistics on individual cache entries.
+ *
+ * accesses: int32_t containing the number of times this cache entry has
+ * been referenced in its lifetime.
+ *
+ * clears: int32_t containing the number of times this cache entry has
+ * been cleared in its life time.
+ *
+ * flushes: int32_t containing the number of times this cache entry has
+ * been flushed to file in its life time.
+ *
+ ****************************************************************************/
+
+typedef struct H5C_cache_entry_t
+{
+ haddr_t addr;
+ size_t size;
+ const H5C_class_t * type;
+ hbool_t is_dirty;
+ hbool_t is_protected;
+ hbool_t in_tree;
+
+ /* fields supporting the hash table: */
+
+ struct H5C_cache_entry_t * ht_next;
+ struct H5C_cache_entry_t * ht_prev;
+
+ /* fields supporting replacement policies: */
+
+ struct H5C_cache_entry_t * next;
+ struct H5C_cache_entry_t * prev;
+ struct H5C_cache_entry_t * aux_next;
+ struct H5C_cache_entry_t * aux_prev;
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+
+ /* cache entry stats fields */
+
+ int32_t accesses;
+ int32_t clears;
+ int32_t flushes;
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+} H5C_cache_entry_t;
+
+
+/* Typedef for the main structure for the cache (defined in H5C.c) */
+
+typedef struct H5C_t H5C_t;
+
+/*
+ * Library prototypes.
+ */
+H5_DLL H5C_t * H5C_create(size_t max_cache_size,
+ size_t min_clean_size,
+ int max_type_id,
+ const char * (* type_name_table_ptr),
+ H5C_write_permitted_func_t check_write_permitted);
+
+H5_DLL herr_t H5C_dest(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr);
+
+H5_DLL herr_t H5C_dest_empty(H5C_t * cache_ptr);
+
+H5_DLL herr_t H5C_flush_cache(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ unsigned flags);
+
+H5_DLL herr_t H5C_insert_entry(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ const H5C_class_t * type,
+ haddr_t addr,
+ void * thing);
+
+H5_DLL herr_t H5C_rename_entry(H5F_t * f,
+ H5C_t * cache_ptr,
+ const H5C_class_t * type,
+ haddr_t old_addr,
+ haddr_t new_addr);
+
+H5_DLL void * H5C_protect(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ const H5C_class_t * type,
+ haddr_t addr,
+ const void * udata1,
+ void * udata2);
+
+H5_DLL herr_t H5C_unprotect(H5F_t * f,
+ hid_t primary_dxpl_id,
+ hid_t secondary_dxpl_id,
+ H5C_t * cache_ptr,
+ const H5C_class_t * type,
+ haddr_t addr,
+ void * thing,
+ hbool_t deleted);
+
+H5_DLL herr_t H5C_stats(H5C_t * cache_ptr,
+ const char * cache_name,
+ hbool_t display_detailed_stats);
+
+H5_DLL void H5C_stats__reset(H5C_t * cache_ptr);
+
+H5_DLL herr_t H5C_set_skip_flags(H5C_t * cache_ptr,
+ hbool_t skip_file_checks,
+ hbool_t skip_dxpl_id_checks);
+
+#endif /* !_H5Cprivate_H */
+
diff --git a/src/H5Defl.c b/src/H5Defl.c
new file mode 100644
index 0000000..ab3e260
--- /dev/null
+++ b/src/H5Defl.c
@@ -0,0 +1,371 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Thursday, September 30, 2004
+ */
+
+#define H5D_PACKAGE /*suppress error about including H5Dpkg */
+
+/* Pablo information */
+/* (Put before include files to avoid problems with inline functions) */
+#define PABLO_MASK H5D_efl_mask
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* Files */
+
+/* PRIVATE PROTOTYPES */
+static herr_t H5D_efl_read (const H5O_efl_t *efl, haddr_t addr, size_t size,
+ uint8_t *buf);
+static herr_t H5D_efl_write(const H5O_efl_t *efl, haddr_t addr, size_t size,
+ const uint8_t *buf);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_efl_read
+ *
+ * Purpose: Reads data from an external file list. It is an error to
+ * read past the logical end of file, but reading past the end
+ * of any particular member of the external file list results in
+ * zeros.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, March 4, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-07-28
+ * The ADDR argument is passed by value.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D_efl_read (const H5O_efl_t *efl, haddr_t addr, size_t size, uint8_t *buf)
+{
+ int fd=-1;
+ size_t to_read;
+#ifndef NDEBUG
+ hsize_t tempto_read;
+#endif /* NDEBUG */
+ hsize_t skip=0;
+ haddr_t cur;
+ ssize_t n;
+ size_t u; /* Local index variable */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_efl_read);
+
+ /* Check args */
+ assert (efl && efl->nused>0);
+ assert (H5F_addr_defined (addr));
+ assert (size < SIZET_MAX);
+ assert (buf || 0==size);
+
+ /* Find the first efl member from which to read */
+ for (u=0, cur=0; u<efl->nused; u++) {
+ if (H5O_EFL_UNLIMITED==efl->slot[u].size || addr < cur+efl->slot[u].size) {
+ skip = addr - cur;
+ break;
+ }
+ cur += efl->slot[u].size;
+ }
+
+ /* Read the data */
+ while (size) {
+ if (u>=efl->nused)
+ HGOTO_ERROR (H5E_EFL, H5E_OVERFLOW, FAIL, "read past logical end of file");
+ if (H5F_OVERFLOW_HSIZET2OFFT (efl->slot[u].offset+skip))
+ HGOTO_ERROR (H5E_EFL, H5E_OVERFLOW, FAIL, "external file address overflowed");
+ if ((fd=HDopen (efl->slot[u].name, O_RDONLY, 0))<0)
+ HGOTO_ERROR (H5E_EFL, H5E_CANTOPENFILE, FAIL, "unable to open external raw data file");
+ if (HDlseek (fd, (off_t)(efl->slot[u].offset+skip), SEEK_SET)<0)
+ HGOTO_ERROR (H5E_EFL, H5E_SEEKERROR, FAIL, "unable to seek in external raw data file");
+#ifndef NDEBUG
+ tempto_read = MIN(efl->slot[u].size-skip,(hsize_t)size);
+ H5_CHECK_OVERFLOW(tempto_read,hsize_t,size_t);
+ to_read = (size_t)tempto_read;
+#else /* NDEBUG */
+ to_read = MIN((size_t)(efl->slot[u].size-skip), size);
+#endif /* NDEBUG */
+ if ((n=HDread (fd, buf, to_read))<0) {
+ HGOTO_ERROR (H5E_EFL, H5E_READERROR, FAIL, "read error in external raw data file");
+ } else if ((size_t)n<to_read) {
+ HDmemset (buf+n, 0, to_read-n);
+ }
+ HDclose (fd);
+ fd = -1;
+ size -= to_read;
+ buf += to_read;
+ skip = 0;
+ u++;
+ }
+
+done:
+ if (fd>=0)
+ HDclose (fd);
+
+ FUNC_LEAVE_NOAPI(ret_value);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_efl_write
+ *
+ * Purpose: Writes data to an external file list. It is an error to
+ * write past the logical end of file, but writing past the end
+ * of any particular member of the external file list just
+ * extends that file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, March 4, 1998
+ *
+ * Modifications:
+ * Robb Matzke, 1999-07-28
+ * The ADDR argument is passed by value.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D_efl_write (const H5O_efl_t *efl, haddr_t addr, size_t size, const uint8_t *buf)
+{
+ int fd=-1;
+ size_t to_write;
+#ifndef NDEBUG
+ hsize_t tempto_write;
+#endif /* NDEBUG */
+ haddr_t cur;
+ hsize_t skip=0;
+ size_t u; /* Local index variable */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_efl_write);
+
+ /* Check args */
+ assert (efl && efl->nused>0);
+ assert (H5F_addr_defined (addr));
+ assert (size < SIZET_MAX);
+ assert (buf || 0==size);
+
+ /* Find the first efl member in which to write */
+ for (u=0, cur=0; u<efl->nused; u++) {
+ if (H5O_EFL_UNLIMITED==efl->slot[u].size || addr < cur+efl->slot[u].size) {
+ skip = addr - cur;
+ break;
+ }
+ cur += efl->slot[u].size;
+ }
+
+ /* Write the data */
+ while (size) {
+ if (u>=efl->nused)
+ HGOTO_ERROR (H5E_EFL, H5E_OVERFLOW, FAIL, "write past logical end of file");
+ if (H5F_OVERFLOW_HSIZET2OFFT (efl->slot[u].offset+skip))
+ HGOTO_ERROR (H5E_EFL, H5E_OVERFLOW, FAIL, "external file address overflowed");
+ if ((fd=HDopen (efl->slot[u].name, O_CREAT|O_RDWR, 0666))<0) {
+ if (HDaccess (efl->slot[u].name, F_OK)<0) {
+ HGOTO_ERROR (H5E_EFL, H5E_CANTOPENFILE, FAIL, "external raw data file does not exist");
+ } else {
+ HGOTO_ERROR (H5E_EFL, H5E_CANTOPENFILE, FAIL, "unable to open external raw data file");
+ }
+ }
+ if (HDlseek (fd, (off_t)(efl->slot[u].offset+skip), SEEK_SET)<0)
+ HGOTO_ERROR (H5E_EFL, H5E_SEEKERROR, FAIL, "unable to seek in external raw data file");
+#ifndef NDEBUG
+ tempto_write = MIN(efl->slot[u].size-skip,(hsize_t)size);
+ H5_CHECK_OVERFLOW(tempto_write,hsize_t,size_t);
+ to_write = (size_t)tempto_write;
+#else /* NDEBUG */
+ to_write = MIN((size_t)(efl->slot[u].size-skip), size);
+#endif /* NDEBUG */
+ if ((size_t)HDwrite (fd, buf, to_write)!=to_write)
+ HGOTO_ERROR (H5E_EFL, H5E_READERROR, FAIL, "write error in external raw data file");
+ HDclose (fd);
+ fd = -1;
+ size -= to_write;
+ buf += to_write;
+ skip = 0;
+ u++;
+ }
+
+done:
+ if (fd>=0)
+ HDclose (fd);
+
+ FUNC_LEAVE_NOAPI(ret_value);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_efl_readvv
+ *
+ * Purpose: Reads data from an external file list. It is an error to
+ * read past the logical end of file, but reading past the end
+ * of any particular member of the external file list results in
+ * zeros.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, May 7, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5D_efl_readvv(H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[],
+ void *_buf)
+{
+ const H5O_efl_t *efl=&(io_info->store->efl); /* Pointer to efl info */
+ unsigned char *buf; /* Pointer to buffer to write */
+ haddr_t addr; /* Actual address to read */
+ size_t size; /* Size of sequence in bytes */
+ size_t u; /* Counting variable */
+ size_t v; /* Counting variable */
+ ssize_t ret_value=0; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5D_efl_readvv, FAIL);
+
+ /* Check args */
+ assert (efl && efl->nused>0);
+ assert (_buf);
+
+ /* Work through all the sequences */
+ for(u=*dset_curr_seq, v=*mem_curr_seq; u<dset_max_nseq && v<mem_max_nseq; ) {
+ /* Choose smallest buffer to write */
+ if(mem_len_arr[v]<dset_len_arr[u])
+ size=mem_len_arr[v];
+ else
+ size=dset_len_arr[u];
+
+ /* Compute offset on disk */
+ addr=dset_offset_arr[u];
+
+ /* Compute offset in memory */
+ buf = (unsigned char *)_buf + mem_offset_arr[v];
+
+ /* Read data */
+ if (H5D_efl_read(efl, addr, size, buf)<0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed");
+
+ /* Update memory information */
+ mem_len_arr[v]-=size;
+ mem_offset_arr[v]+=size;
+ if(mem_len_arr[v]==0)
+ v++;
+
+ /* Update file information */
+ dset_len_arr[u]-=size;
+ dset_offset_arr[u]+=size;
+ if(dset_len_arr[u]==0)
+ u++;
+
+ /* Increment number of bytes copied */
+ ret_value+=size;
+ } /* end for */
+
+ /* Update current sequence vectors */
+ *dset_curr_seq=u;
+ *mem_curr_seq=v;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5D_efl_readvv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_efl_writevv
+ *
+ * Purpose: Writes data to an external file list. It is an error to
+ * write past the logical end of file, but writing past the end
+ * of any particular member of the external file list just
+ * extends that file.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Friday, May 2, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+ssize_t
+H5D_efl_writevv(H5D_io_info_t *io_info,
+ size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[],
+ size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[],
+ const void *_buf)
+{
+ const H5O_efl_t *efl=&(io_info->store->efl); /* Pointer to efl info */
+ const unsigned char *buf; /* Pointer to buffer to write */
+ haddr_t addr; /* Actual address to read */
+ size_t size; /* Size of sequence in bytes */
+ size_t u; /* Counting variable */
+ size_t v; /* Counting variable */
+ ssize_t ret_value=0; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5D_efl_writevv, FAIL);
+
+ /* Check args */
+ assert (efl && efl->nused>0);
+ assert (_buf);
+
+ /* Work through all the sequences */
+ for(u=*dset_curr_seq, v=*mem_curr_seq; u<dset_max_nseq && v<mem_max_nseq; ) {
+ /* Choose smallest buffer to write */
+ if(mem_len_arr[v]<dset_len_arr[u])
+ size=mem_len_arr[v];
+ else
+ size=dset_len_arr[u];
+
+ /* Compute offset on disk */
+ addr=dset_offset_arr[u];
+
+ /* Compute offset in memory */
+ buf = (const unsigned char *)_buf + mem_offset_arr[v];
+
+ /* Write data */
+ if (H5D_efl_write(efl, addr, size, buf)<0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed");
+
+ /* Update memory information */
+ mem_len_arr[v]-=size;
+ mem_offset_arr[v]+=size;
+ if(mem_len_arr[v]==0)
+ v++;
+
+ /* Update file information */
+ dset_len_arr[u]-=size;
+ dset_offset_arr[u]+=size;
+ if(dset_len_arr[u]==0)
+ u++;
+
+ /* Increment number of bytes copied */
+ ret_value+=size;
+ } /* end for */
+
+ /* Update current sequence vectors */
+ *dset_curr_seq=u;
+ *mem_curr_seq=v;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5D_efl_writevv() */
+
diff --git a/src/H5Dselect.c b/src/H5Dselect.c
new file mode 100644
index 0000000..a12823e
--- /dev/null
+++ b/src/H5Dselect.c
@@ -0,0 +1,691 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.ued>
+ * Thursday, September 30, 2004
+ *
+ * Purpose: Dataspace I/O functions.
+ */
+
+#define H5D_PACKAGE /*suppress error about including H5Dpkg */
+
+/* Pablo information */
+/* (Put before include files to avoid problems with inline functions) */
+#define PABLO_MASK H5D_select_mask
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Dpkg.h" /* Datasets */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+
+/* Declare a free list to manage sequences of size_t */
+H5FL_SEQ_DEFINE_STATIC(size_t);
+
+/* Declare a free list to manage sequences of hsize_t */
+H5FL_SEQ_DEFINE_STATIC(hsize_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_select_fscat
+ *
+ * Purpose: Scatters dataset elements from the type conversion buffer BUF
+ * to the file F where the data points are arranged according to
+ * the file dataspace FILE_SPACE and stored according to
+ * LAYOUT and EFL. Each element is ELMT_SIZE bytes.
+ * The caller is requesting that NELMTS elements are copied.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, June 20, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_select_fscat (H5D_io_info_t *io_info,
+ const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts,
+ const void *_buf)
+{
+ const uint8_t *buf=_buf; /* Alias for pointer arithmetic */
+ hsize_t _off[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence offsets */
+ hsize_t *off=NULL; /* Pointer to sequence offsets */
+ hsize_t mem_off; /* Offset in memory */
+ size_t mem_curr_seq; /* "Current sequence" in memory */
+ size_t dset_curr_seq; /* "Current sequence" in dataset */
+ size_t _len[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence lengths */
+ size_t *len=NULL; /* Array to store sequence lengths */
+ size_t orig_mem_len, mem_len; /* Length of sequence in memory */
+ size_t nseq; /* Number of sequences generated */
+ size_t nelem; /* Number of elements used in sequences */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5D_select_fscat, FAIL);
+
+ /* Check args */
+ assert (io_info);
+ assert (space);
+ assert (iter);
+ assert (nelmts>0);
+ assert (_buf);
+ assert(TRUE==H5P_isa_class(io_info->dxpl_id,H5P_DATASET_XFER));
+
+ /* Allocate the vector I/O arrays */
+ if(io_info->dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if((len = H5FL_SEQ_MALLOC(size_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array");
+ if((off = H5FL_SEQ_MALLOC(hsize_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array");
+ } /* end if */
+ else {
+ len=_len;
+ off=_off;
+ } /* end else */
+
+ /* Loop until all elements are written */
+ while(nelmts>0) {
+ /* Get list of sequences for selection to write */
+ if(H5S_SELECT_GET_SEQ_LIST(space,H5S_GET_SEQ_LIST_SORTED,iter,io_info->dxpl_cache->vec_size,nelmts,&nseq,&nelem,off,len)<0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed");
+
+ /* Reset the current sequence information */
+ mem_curr_seq=dset_curr_seq=0;
+ orig_mem_len=mem_len=nelem*iter->elmt_size;
+ mem_off=0;
+
+ /* Write sequence list out */
+ if ((*io_info->ops.writevv)(io_info, nseq, &dset_curr_seq, len, off, 1, &mem_curr_seq, &mem_len, &mem_off, buf)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error");
+
+ /* Update buffer */
+ buf += orig_mem_len;
+
+ /* Decrement number of elements left to process */
+ nelmts -= nelem;
+ } /* end while */
+
+done:
+ if(io_info->dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if(len!=NULL)
+ H5FL_SEQ_FREE(size_t,len);
+ if(off!=NULL)
+ H5FL_SEQ_FREE(hsize_t,off);
+ } /* end if */
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* H5D_select_fscat() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_select_fgath
+ *
+ * Purpose: Gathers data points from file F and accumulates them in the
+ * type conversion buffer BUF. The LAYOUT argument describes
+ * how the data is stored on disk and EFL describes how the data
+ * is organized in external files. ELMT_SIZE is the size in
+ * bytes of a datum which this function treats as opaque.
+ * FILE_SPACE describes the dataspace of the dataset on disk
+ * and the elements that have been selected for reading (via
+ * hyperslab, etc). This function will copy at most NELMTS
+ * elements.
+ *
+ * Return: Success: Number of elements copied.
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 24, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5D_select_fgath (H5D_io_info_t *io_info,
+ const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts,
+ void *_buf/*out*/)
+{
+ uint8_t *buf=_buf; /* Alias for pointer arithmetic */
+ hsize_t _off[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence offsets */
+ hsize_t *off=NULL; /* Pointer to sequence offsets */
+ hsize_t mem_off; /* Offset in memory */
+ size_t mem_curr_seq; /* "Current sequence" in memory */
+ size_t dset_curr_seq; /* "Current sequence" in dataset */
+ size_t _len[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence lengths */
+ size_t *len=NULL; /* Pointer to sequence lengths */
+ size_t orig_mem_len, mem_len; /* Length of sequence in memory */
+ size_t nseq; /* Number of sequences generated */
+ size_t nelem; /* Number of elements used in sequences */
+ size_t ret_value=nelmts; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5D_select_fgath, 0);
+
+ /* Check args */
+ assert (io_info);
+ assert (io_info->dset);
+ assert (io_info->store);
+ assert (space);
+ assert (iter);
+ assert (nelmts>0);
+ assert (_buf);
+
+ /* Allocate the vector I/O arrays */
+ if(io_info->dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if((len = H5FL_SEQ_MALLOC(size_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O length vector array");
+ if((off = H5FL_SEQ_MALLOC(hsize_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O offset vector array");
+ } /* end if */
+ else {
+ len=_len;
+ off=_off;
+ } /* end else */
+
+ /* Loop until all elements are read */
+ while(nelmts>0) {
+ /* Get list of sequences for selection to read */
+ if(H5S_SELECT_GET_SEQ_LIST(space,H5S_GET_SEQ_LIST_SORTED,iter,io_info->dxpl_cache->vec_size,nelmts,&nseq,&nelem,off,len)<0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed");
+
+ /* Reset the current sequence information */
+ mem_curr_seq=dset_curr_seq=0;
+ orig_mem_len=mem_len=nelem*iter->elmt_size;
+ mem_off=0;
+
+ /* Read sequence list in */
+ if ((*io_info->ops.readvv)(io_info, nseq, &dset_curr_seq, len, off, 1, &mem_curr_seq, &mem_len, &mem_off, buf)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error");
+
+ /* Update buffer */
+ buf += orig_mem_len;
+
+ /* Decrement number of elements left to process */
+ nelmts -= nelem;
+ } /* end while */
+
+done:
+ if(io_info->dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if(len!=NULL)
+ H5FL_SEQ_FREE(size_t,len);
+ if(off!=NULL)
+ H5FL_SEQ_FREE(hsize_t,off);
+ } /* end if */
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* H5D_select_fgath() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_select_mscat
+ *
+ * Purpose: Scatters NELMTS data points from the scatter buffer
+ * TSCAT_BUF to the application buffer BUF. Each element is
+ * ELMT_SIZE bytes and they are organized in application memory
+ * according to SPACE.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Monday, July 8, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_select_mscat (const void *_tscat_buf, const H5S_t *space,
+ H5S_sel_iter_t *iter, size_t nelmts, const H5D_dxpl_cache_t *dxpl_cache,
+ void *_buf/*out*/)
+{
+ uint8_t *buf=(uint8_t *)_buf; /* Get local copies for address arithmetic */
+ const uint8_t *tscat_buf=(const uint8_t *)_tscat_buf;
+ hsize_t _off[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence offsets */
+ hsize_t *off=NULL; /* Pointer to sequence offsets */
+ size_t _len[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence lengths */
+ size_t *len=NULL; /* Pointer to sequence lengths */
+ size_t curr_len; /* Length of bytes left to process in sequence */
+ size_t nseq; /* Number of sequences generated */
+ size_t curr_seq; /* Current sequence being processed */
+ size_t nelem; /* Number of elements used in sequences */
+ herr_t ret_value=SUCCEED; /* Number of elements scattered */
+
+ FUNC_ENTER_NOAPI(H5D_select_mscat, FAIL);
+
+ /* Check args */
+ assert (tscat_buf);
+ assert (space);
+ assert (iter);
+ assert (nelmts>0);
+ assert (buf);
+
+ /* Allocate the vector I/O arrays */
+ if(dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if((len = H5FL_SEQ_MALLOC(size_t,dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array");
+ if((off = H5FL_SEQ_MALLOC(hsize_t,dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array");
+ } /* end if */
+ else {
+ len=_len;
+ off=_off;
+ } /* end else */
+
+ /* Loop until all elements are written */
+ while(nelmts>0) {
+ /* Get list of sequences for selection to write */
+ if(H5S_SELECT_GET_SEQ_LIST(space,0,iter,dxpl_cache->vec_size,nelmts,&nseq,&nelem,off,len)<0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed");
+
+ /* Loop, while sequences left to process */
+ for(curr_seq=0; curr_seq<nseq; curr_seq++) {
+ /* Get the number of bytes in sequence */
+ curr_len=len[curr_seq];
+
+ HDmemcpy(buf+off[curr_seq],tscat_buf,curr_len);
+
+ /* Advance offset in destination buffer */
+ tscat_buf+=curr_len;
+ } /* end for */
+
+ /* Decrement number of elements left to process */
+ nelmts -= nelem;
+ } /* end while */
+
+done:
+ if(dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if(len!=NULL)
+ H5FL_SEQ_FREE(size_t,len);
+ if(off!=NULL)
+ H5FL_SEQ_FREE(hsize_t,off);
+ } /* end if */
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* H5D_select_mscat() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_select_mgath
+ *
+ * Purpose: Gathers dataset elements from application memory BUF and
+ * copies them into the gather buffer TGATH_BUF.
+ * Each element is ELMT_SIZE bytes and arranged in application
+ * memory according to SPACE.
+ * The caller is requesting that at most NELMTS be gathered.
+ *
+ * Return: Success: Number of elements copied.
+ * Failure: 0
+ *
+ * Programmer: Quincey Koziol
+ * Monday, June 24, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+size_t
+H5D_select_mgath (const void *_buf, const H5S_t *space,
+ H5S_sel_iter_t *iter, size_t nelmts, const H5D_dxpl_cache_t *dxpl_cache,
+ void *_tgath_buf/*out*/)
+{
+ const uint8_t *buf=(const uint8_t *)_buf; /* Get local copies for address arithmetic */
+ uint8_t *tgath_buf=(uint8_t *)_tgath_buf;
+ hsize_t _off[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence offsets */
+ hsize_t *off=NULL; /* Pointer to sequence offsets */
+ size_t _len[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence lengths */
+ size_t *len=NULL; /* Pointer to sequence lengths */
+ size_t curr_len; /* Length of bytes left to process in sequence */
+ size_t nseq; /* Number of sequences generated */
+ size_t curr_seq; /* Current sequence being processed */
+ size_t nelem; /* Number of elements used in sequences */
+ size_t ret_value=nelmts; /* Number of elements gathered */
+
+ FUNC_ENTER_NOAPI(H5D_select_mgath, 0);
+
+ /* Check args */
+ assert (buf);
+ assert (space);
+ assert (iter);
+ assert (nelmts>0);
+ assert (tgath_buf);
+
+ /* Allocate the vector I/O arrays */
+ if(dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if((len = H5FL_SEQ_MALLOC(size_t,dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O length vector array");
+ if((off = H5FL_SEQ_MALLOC(hsize_t,dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O offset vector array");
+ } /* end if */
+ else {
+ len=_len;
+ off=_off;
+ } /* end else */
+
+ /* Loop until all elements are written */
+ while(nelmts>0) {
+ /* Get list of sequences for selection to write */
+ if(H5S_SELECT_GET_SEQ_LIST(space,0,iter,dxpl_cache->vec_size,nelmts,&nseq,&nelem,off,len)<0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed");
+
+ /* Loop, while sequences left to process */
+ for(curr_seq=0; curr_seq<nseq; curr_seq++) {
+ /* Get the number of bytes in sequence */
+ curr_len=len[curr_seq];
+
+ HDmemcpy(tgath_buf,buf+off[curr_seq],curr_len);
+
+ /* Advance offset in gather buffer */
+ tgath_buf+=curr_len;
+ } /* end for */
+
+ /* Decrement number of elements left to process */
+ nelmts -= nelem;
+ } /* end while */
+
+done:
+ if(dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if(len!=NULL)
+ H5FL_SEQ_FREE(size_t,len);
+ if(off!=NULL)
+ H5FL_SEQ_FREE(hsize_t,off);
+ } /* end if */
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* H5D_select_mgath() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_select_read
+ *
+ * Purpose: Reads directly from file into application memory.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 23, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_select_read(H5D_io_info_t *io_info,
+ size_t nelmts, size_t elmt_size,
+ const H5S_t *file_space, const H5S_t *mem_space,
+ void *buf/*out*/)
+{
+ H5S_sel_iter_t mem_iter; /* Memory selection iteration info */
+ hbool_t mem_iter_init=0; /* Memory selection iteration info has been initialized */
+ H5S_sel_iter_t file_iter; /* File selection iteration info */
+ hbool_t file_iter_init=0; /* File selection iteration info has been initialized */
+ hsize_t _mem_off[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence offsets in memory */
+ hsize_t *mem_off=NULL; /* Pointer to sequence offsets in memory */
+ hsize_t _file_off[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence offsets in the file */
+ hsize_t *file_off=NULL; /* Pointer to sequence offsets in the file */
+ size_t _mem_len[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence lengths in memory */
+ size_t *mem_len=NULL; /* Pointer to sequence lengths in memory */
+ size_t _file_len[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence lengths in the file */
+ size_t *file_len=NULL; /* Pointer to sequence lengths in the file */
+ size_t mem_nseq; /* Number of sequences generated in the file */
+ size_t file_nseq; /* Number of sequences generated in memory */
+ size_t mem_nelem; /* Number of elements used in memory sequences */
+ size_t file_nelem; /* Number of elements used in file sequences */
+ size_t curr_mem_seq; /* Current memory sequence to operate on */
+ size_t curr_file_seq; /* Current file sequence to operate on */
+ ssize_t tmp_file_len; /* Temporary number of bytes in file sequence */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5D_select_read, FAIL);
+
+ /* Check args */
+ assert(io_info);
+ assert(io_info->dset);
+ assert(io_info->dxpl_cache);
+ assert(io_info->store);
+ assert(buf);
+ assert(TRUE==H5P_isa_class(io_info->dxpl_id,H5P_DATASET_XFER));
+
+ /* Initialize file iterator */
+ if (H5S_select_iter_init(&file_iter, file_space, elmt_size)<0)
+ HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator");
+ file_iter_init=1; /* File selection iteration info has been initialized */
+
+ /* Initialize memory iterator */
+ if (H5S_select_iter_init(&mem_iter, mem_space, elmt_size)<0)
+ HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator");
+ mem_iter_init=1; /* Memory selection iteration info has been initialized */
+
+ /* Allocate the vector I/O arrays */
+ if(io_info->dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if((mem_len = H5FL_SEQ_MALLOC(size_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array");
+ if((mem_off = H5FL_SEQ_MALLOC(hsize_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array");
+ if((file_len = H5FL_SEQ_MALLOC(size_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array");
+ if((file_off = H5FL_SEQ_MALLOC(hsize_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array");
+ } /* end if */
+ else {
+ mem_len=_mem_len;
+ mem_off=_mem_off;
+ file_len=_file_len;
+ file_off=_file_off;
+ } /* end else */
+
+ /* Initialize sequence counts */
+ curr_mem_seq=curr_file_seq=0;
+ mem_nseq=file_nseq=0;
+
+ /* Loop, until all bytes are processed */
+ while(nelmts>0) {
+ /* Check if more file sequences are needed */
+ if(curr_file_seq>=file_nseq) {
+ /* Get sequences for file selection */
+ if(H5S_SELECT_GET_SEQ_LIST(file_space,H5S_GET_SEQ_LIST_SORTED,&file_iter,io_info->dxpl_cache->vec_size,nelmts,&file_nseq,&file_nelem,file_off,file_len)<0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed");
+
+ /* Start at the beginning of the sequences again */
+ curr_file_seq=0;
+ } /* end if */
+
+ /* Check if more memory sequences are needed */
+ if(curr_mem_seq>=mem_nseq) {
+ /* Get sequences for memory selection */
+ if(H5S_SELECT_GET_SEQ_LIST(mem_space,0,&mem_iter,io_info->dxpl_cache->vec_size,nelmts,&mem_nseq,&mem_nelem,mem_off,mem_len)<0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed");
+
+ /* Start at the beginning of the sequences again */
+ curr_mem_seq=0;
+ } /* end if */
+
+ /* Read file sequences into current memory sequence */
+ if ((tmp_file_len=(*io_info->ops.readvv)(io_info,
+ file_nseq, &curr_file_seq, file_len, file_off,
+ mem_nseq, &curr_mem_seq, mem_len, mem_off,
+ buf))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error");
+
+ /* Decrement number of elements left to process */
+ assert((tmp_file_len%elmt_size)==0);
+ nelmts-=(tmp_file_len/elmt_size);
+ } /* end while */
+
+done:
+ /* Release file selection iterator */
+ if(file_iter_init) {
+ if (H5S_SELECT_ITER_RELEASE(&file_iter)<0)
+ HDONE_ERROR (H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator");
+ } /* end if */
+
+ /* Release memory selection iterator */
+ if(mem_iter_init) {
+ if (H5S_SELECT_ITER_RELEASE(&mem_iter)<0)
+ HDONE_ERROR (H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator");
+ } /* end if */
+
+ /* Free vector arrays */
+ if(io_info->dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if(file_len!=NULL)
+ H5FL_SEQ_FREE(size_t,file_len);
+ if(file_off!=NULL)
+ H5FL_SEQ_FREE(hsize_t,file_off);
+ if(mem_len!=NULL)
+ H5FL_SEQ_FREE(size_t,mem_len);
+ if(mem_off!=NULL)
+ H5FL_SEQ_FREE(hsize_t,mem_off);
+ } /* end if */
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5D_select_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_select_write
+ *
+ * Purpose: Writes directly from application memory into a file
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, July 23, 2002
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5D_select_write(H5D_io_info_t *io_info,
+ size_t nelmts, size_t elmt_size,
+ const H5S_t *file_space, const H5S_t *mem_space,
+ const void *buf/*out*/)
+{
+ H5S_sel_iter_t mem_iter; /* Memory selection iteration info */
+ hbool_t mem_iter_init=0; /* Memory selection iteration info has been initialized */
+ H5S_sel_iter_t file_iter; /* File selection iteration info */
+ hbool_t file_iter_init=0; /* File selection iteration info has been initialized */
+ hsize_t _mem_off[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence offsets in memory */
+ hsize_t *mem_off=NULL; /* Pointer to sequence offsets in memory */
+ hsize_t _file_off[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence offsets in the file */
+ hsize_t *file_off=NULL; /* Pointer to sequence offsets in the file */
+ size_t _mem_len[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence lengths in memory */
+ size_t *mem_len=NULL; /* Pointer to sequence lengths in memory */
+ size_t _file_len[H5D_XFER_HYPER_VECTOR_SIZE_DEF]; /* Array to store sequence lengths in the file */
+ size_t *file_len=NULL; /* Pointer to sequence lengths in the file */
+ size_t mem_nseq; /* Number of sequences generated in the file */
+ size_t file_nseq; /* Number of sequences generated in memory */
+ size_t mem_nelem; /* Number of elements used in memory sequences */
+ size_t file_nelem; /* Number of elements used in file sequences */
+ size_t curr_mem_seq; /* Current memory sequence to operate on */
+ size_t curr_file_seq; /* Current file sequence to operate on */
+ ssize_t tmp_file_len; /* Temporary number of bytes in file sequence */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5D_select_write, FAIL);
+
+ /* Check args */
+ assert(io_info);
+ assert(io_info->dset);
+ assert(io_info->store);
+ assert(TRUE==H5P_isa_class(io_info->dxpl_id,H5P_DATASET_XFER));
+ assert(buf);
+
+ /* Allocate the vector I/O arrays */
+ if(io_info->dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if((mem_len = H5FL_SEQ_MALLOC(size_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array");
+ if((mem_off = H5FL_SEQ_MALLOC(hsize_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array");
+ if((file_len = H5FL_SEQ_MALLOC(size_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array");
+ if((file_off = H5FL_SEQ_MALLOC(hsize_t,io_info->dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array");
+ } /* end if */
+ else {
+ mem_len=_mem_len;
+ mem_off=_mem_off;
+ file_len=_file_len;
+ file_off=_file_off;
+ } /* end else */
+
+ /* Initialize file iterator */
+ if (H5S_select_iter_init(&file_iter, file_space, elmt_size)<0)
+ HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator");
+ file_iter_init=1; /* File selection iteration info has been initialized */
+
+ /* Initialize memory iterator */
+ if (H5S_select_iter_init(&mem_iter, mem_space, elmt_size)<0)
+ HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator");
+ mem_iter_init=1; /* Memory selection iteration info has been initialized */
+
+ /* Initialize sequence counts */
+ curr_mem_seq=curr_file_seq=0;
+ mem_nseq=file_nseq=0;
+
+ /* Loop, until all bytes are processed */
+ while(nelmts>0) {
+ /* Check if more file sequences are needed */
+ if(curr_file_seq>=file_nseq) {
+ /* Get sequences for file selection */
+ if(H5S_SELECT_GET_SEQ_LIST(file_space,H5S_GET_SEQ_LIST_SORTED,&file_iter,io_info->dxpl_cache->vec_size,nelmts,&file_nseq,&file_nelem,file_off,file_len)<0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed");
+
+ /* Start at the beginning of the sequences again */
+ curr_file_seq=0;
+ } /* end if */
+
+ /* Check if more memory sequences are needed */
+ if(curr_mem_seq>=mem_nseq) {
+ /* Get sequences for memory selection */
+ if(H5S_SELECT_GET_SEQ_LIST(mem_space,0,&mem_iter,io_info->dxpl_cache->vec_size,nelmts,&mem_nseq,&mem_nelem,mem_off,mem_len)<0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed");
+
+ /* Start at the beginning of the sequences again */
+ curr_mem_seq=0;
+ } /* end if */
+
+ /* Write memory sequences into file sequences */
+ if ((tmp_file_len=(*io_info->ops.writevv)(io_info,
+ file_nseq, &curr_file_seq, file_len, file_off,
+ mem_nseq, &curr_mem_seq, mem_len, mem_off,
+ buf))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error");
+
+ /* Decrement number of elements left to process */
+ assert((tmp_file_len%elmt_size)==0);
+ nelmts-=(tmp_file_len/elmt_size);
+ } /* end while */
+
+done:
+ /* Release file selection iterator */
+ if(file_iter_init) {
+ if (H5S_SELECT_ITER_RELEASE(&file_iter)<0)
+ HDONE_ERROR (H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator");
+ } /* end if */
+
+ /* Release memory selection iterator */
+ if(mem_iter_init) {
+ if (H5S_SELECT_ITER_RELEASE(&mem_iter)<0)
+ HDONE_ERROR (H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator");
+ } /* end if */
+
+ /* Free vector arrays */
+ if(io_info->dxpl_cache->vec_size!=H5D_XFER_HYPER_VECTOR_SIZE_DEF) {
+ if(file_len!=NULL)
+ H5FL_SEQ_FREE(size_t,file_len);
+ if(file_off!=NULL)
+ H5FL_SEQ_FREE(hsize_t,file_off);
+ if(mem_len!=NULL)
+ H5FL_SEQ_FREE(size_t,mem_len);
+ if(mem_off!=NULL)
+ H5FL_SEQ_FREE(hsize_t,mem_off);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5D_select_write() */
+
diff --git a/test/cache.c b/test/cache.c
new file mode 100644
index 0000000..bdd27d1
--- /dev/null
+++ b/test/cache.c
@@ -0,0 +1,4160 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Programmer: John Mainzer
+ * 6/9/04
+ *
+ * This file contains tests for the cache implemented in
+ * H5C.c
+ */
+#include "h5test.h"
+#include "H5Iprivate.h"
+
+const char *FILENAME[] = {
+ "cache",
+ NULL
+};
+
+#include "H5TBprivate.h"
+#include "H5Cprivate.h"
+
+/* with apologies for the abuse of terminology... */
+
+#define PICO_ENTRY_TYPE 0
+#define NANO_ENTRY_TYPE 1
+#define MICRO_ENTRY_TYPE 2
+#define TINY_ENTRY_TYPE 3
+#define SMALL_ENTRY_TYPE 4
+#define MEDIUM_ENTRY_TYPE 5
+#define LARGE_ENTRY_TYPE 6
+#define HUGE_ENTRY_TYPE 7
+#define MONSTER_ENTRY_TYPE 8
+
+#define NUMBER_OF_ENTRY_TYPES 9
+
+#define PICO_ENTRY_SIZE (size_t)1
+#define NANO_ENTRY_SIZE (size_t)4
+#define MICRO_ENTRY_SIZE (size_t)16
+#define TINY_ENTRY_SIZE (size_t)64
+#define SMALL_ENTRY_SIZE (size_t)256
+#define MEDIUM_ENTRY_SIZE (size_t)1024
+#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 NUM_PICO_ENTRIES (10 * 1024)
+#define NUM_NANO_ENTRIES (10 * 1024)
+#define NUM_MICRO_ENTRIES (10 * 1024)
+#define NUM_TINY_ENTRIES (10 * 1024)
+#define NUM_SMALL_ENTRIES (10 * 1024)
+#define NUM_MEDIUM_ENTRIES (10 * 1024)
+#define NUM_LARGE_ENTRIES (10 * 1024)
+#define NUM_HUGE_ENTRIES (10 * 1024)
+#define NUM_MONSTER_ENTRIES (10 * 1024)
+
+#define MAX_ENTRIES (10 * 1024)
+
+#define PICO_BASE_ADDR (haddr_t)0
+#define NANO_BASE_ADDR (haddr_t)(PICO_BASE_ADDR + \
+ (PICO_ENTRY_SIZE * NUM_PICO_ENTRIES))
+#define MICRO_BASE_ADDR (haddr_t)(NANO_BASE_ADDR + \
+ (NANO_ENTRY_SIZE * NUM_NANO_ENTRIES))
+#define TINY_BASE_ADDR (haddr_t)(MICRO_BASE_ADDR + \
+ (MICRO_ENTRY_SIZE * NUM_MICRO_ENTRIES))
+#define SMALL_BASE_ADDR (haddr_t)(TINY_BASE_ADDR + \
+ (TINY_ENTRY_SIZE * NUM_TINY_ENTRIES))
+#define MEDIUM_BASE_ADDR (haddr_t)(SMALL_BASE_ADDR + \
+ (SMALL_ENTRY_SIZE * NUM_SMALL_ENTRIES))
+#define LARGE_BASE_ADDR (haddr_t)(MEDIUM_BASE_ADDR + \
+ (MEDIUM_ENTRY_SIZE * NUM_MEDIUM_ENTRIES))
+#define HUGE_BASE_ADDR (haddr_t)(LARGE_BASE_ADDR + \
+ (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 + \
+ (MONSTER_ENTRY_SIZE * NUM_MONSTER_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 + \
+ (NANO_ENTRY_SIZE * NUM_NANO_ENTRIES))
+#define TINY_ALT_BASE_ADDR (haddr_t)(MICRO_ALT_BASE_ADDR + \
+ (MICRO_ENTRY_SIZE * NUM_MICRO_ENTRIES))
+#define SMALL_ALT_BASE_ADDR (haddr_t)(TINY_ALT_BASE_ADDR + \
+ (TINY_ENTRY_SIZE * NUM_TINY_ENTRIES))
+#define MEDIUM_ALT_BASE_ADDR (haddr_t)(SMALL_ALT_BASE_ADDR + \
+ (SMALL_ENTRY_SIZE * NUM_SMALL_ENTRIES))
+#define LARGE_ALT_BASE_ADDR (haddr_t)(MEDIUM_ALT_BASE_ADDR + \
+ (MEDIUM_ENTRY_SIZE * NUM_MEDIUM_ENTRIES))
+#define HUGE_ALT_BASE_ADDR (haddr_t)(LARGE_ALT_BASE_ADDR + \
+ (LARGE_ENTRY_SIZE * NUM_LARGE_ENTRIES))
+#define MONSTER_ALT_BASE_ADDR (haddr_t)(HUGE_ALT_BASE_ADDR + \
+ (HUGE_ENTRY_SIZE * NUM_HUGE_ENTRIES))
+
+typedef struct test_entry_t
+{
+ H5C_cache_entry_t header; /* entry data used by the cache
+ * -- must be first
+ */
+ struct test_entry_t * self; /* pointer to this entry -- used for
+ * sanity checking.
+ */
+ haddr_t addr; /* where the cache thinks this entry
+ * is located
+ */
+ hbool_t at_main_addr; /* boolean flag indicating whether
+ * the entry is supposed to be at
+ * either its main or alternate
+ * address.
+ */
+ haddr_t main_addr; /* initial location of the entry
+ */
+ haddr_t alt_addr; /* location to which the entry
+ * can be relocated or "renamed"
+ */
+ size_t size; /* how big the cache thinks this
+ * entry is
+ */
+ int32_t type; /* indicates which entry array this
+ * entry is in
+ */
+ int32_t index; /* index in its entry array
+ */
+ int32_t reads; /* number of times this entry has
+ * been loaded.
+ */
+ int32_t writes; /* number of times this entry has
+ * been written
+ */
+ hbool_t is_dirty; /* entry has been modified since
+ * last write
+ */
+ hbool_t is_protected; /* entry should currently be on
+ * the cache's protected list.
+ */
+} test_entry_t;
+
+/* The following is a cut down copy of the hash table manipulation
+ * macros from H5C.c, which have been further modified to avoid references
+ * to the error reporting macros. Needless to say, these macros must be
+ * updated as necessary.
+ */
+
+#define H5C__HASH_TABLE_LEN (32 * 1024) /* must be a power of 2 */
+#define H5C__HASH_MASK ((size_t)(H5C__HASH_TABLE_LEN - 1) << 3)
+#define H5C__HASH_FCN(x) (int)(((x) & H5C__HASH_MASK) >> 3)
+
+#define H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( ! H5F_addr_defined(Addr) ) || \
+ ( H5C__HASH_FCN(Addr) < 0 ) || \
+ ( H5C__HASH_FCN(Addr) >= H5C__HASH_TABLE_LEN ) ) { \
+ HDfprintf(stdout, "Pre HT search SC failed.\n"); \
+}
+
+#define H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k) \
+if ( ( (cache_ptr) == NULL ) || \
+ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \
+ ( (cache_ptr)->index_len < 1 ) || \
+ ( (entry_ptr) == NULL ) || \
+ ( (cache_ptr)->index_size < (entry_ptr)->size ) || \
+ ( H5F_addr_ne((entry_ptr)->addr, (Addr)) ) || \
+ ( (entry_ptr)->size <= 0 ) || \
+ ( ((cache_ptr)->index)[k] == NULL ) || \
+ ( ( ((cache_ptr)->index)[k] != (entry_ptr) ) && \
+ ( (entry_ptr)->ht_prev == NULL ) ) || \
+ ( ( ((cache_ptr)->index)[k] == (entry_ptr) ) && \
+ ( (entry_ptr)->ht_prev != NULL ) ) || \
+ ( ( (entry_ptr)->ht_prev != NULL ) && \
+ ( (entry_ptr)->ht_prev->ht_next != (entry_ptr) ) ) || \
+ ( ( (entry_ptr)->ht_next != NULL ) && \
+ ( (entry_ptr)->ht_next->ht_prev != (entry_ptr) ) ) ) { \
+ HDfprintf(stdout, "Post successful HT search SC failed.\n"); \
+}
+
+
+#define H5C__SEARCH_INDEX(cache_ptr, Addr, entry_ptr) \
+{ \
+ int k; \
+ int depth = 0; \
+ H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr) \
+ k = H5C__HASH_FCN(Addr); \
+ entry_ptr = ((cache_ptr)->index)[k]; \
+ while ( ( entry_ptr ) && ( H5F_addr_ne(Addr, (entry_ptr)->addr) ) ) \
+ { \
+ (entry_ptr) = (entry_ptr)->ht_next; \
+ (depth)++; \
+ } \
+ if ( entry_ptr ) \
+ { \
+ H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k) \
+ if ( entry_ptr != ((cache_ptr)->index)[k] ) \
+ { \
+ if ( (entry_ptr)->ht_next ) \
+ { \
+ (entry_ptr)->ht_next->ht_prev = (entry_ptr)->ht_prev; \
+ } \
+ HDassert( (entry_ptr)->ht_prev != NULL ); \
+ (entry_ptr)->ht_prev->ht_next = (entry_ptr)->ht_next; \
+ ((cache_ptr)->index)[k]->ht_prev = (entry_ptr); \
+ (entry_ptr)->ht_next = ((cache_ptr)->index)[k]; \
+ (entry_ptr)->ht_prev = NULL; \
+ ((cache_ptr)->index)[k] = (entry_ptr); \
+ } \
+ } \
+}
+
+
+/* The following is a local copy of the H5C_t structure -- any changes in
+ * that structure must be reproduced here. The typedef is used to allow
+ * local access to the cache's private data.
+ */
+
+#define H5C__H5C_T_MAGIC 0x005CAC0E
+#define H5C__MAX_NUM_TYPE_IDS 9
+
+typedef struct local_H5C_t
+{
+ uint32_t magic;
+
+ int32_t max_type_id;
+ const char * (* type_name_table_ptr);
+
+ size_t max_cache_size;
+ size_t min_clean_size;
+
+ H5C_write_permitted_func_t check_write_permitted;
+
+ int32_t index_len;
+ size_t index_size;
+ H5C_cache_entry_t * (index[H5C__HASH_TABLE_LEN]);
+
+
+ int32_t tree_len;
+ size_t tree_size;
+ H5TB_TREE * tree_ptr;
+
+ int32_t pl_len;
+ size_t pl_size;
+ H5C_cache_entry_t * pl_head_ptr;
+ H5C_cache_entry_t * pl_tail_ptr;
+
+ int32_t LRU_list_len;
+ size_t LRU_list_size;
+ H5C_cache_entry_t * LRU_head_ptr;
+ H5C_cache_entry_t * LRU_tail_ptr;
+
+ int32_t cLRU_list_len;
+ size_t cLRU_list_size;
+ H5C_cache_entry_t * cLRU_head_ptr;
+ H5C_cache_entry_t * cLRU_tail_ptr;
+
+ int32_t dLRU_list_len;
+ size_t dLRU_list_size;
+ H5C_cache_entry_t * dLRU_head_ptr;
+ H5C_cache_entry_t * dLRU_tail_ptr;
+
+#if H5C_COLLECT_CACHE_STATS
+
+ /* stats fields */
+ int64_t hits[H5C__MAX_NUM_TYPE_IDS];
+ int64_t misses[H5C__MAX_NUM_TYPE_IDS];
+ int64_t insertions[H5C__MAX_NUM_TYPE_IDS];
+ int64_t clears[H5C__MAX_NUM_TYPE_IDS];
+ int64_t flushes[H5C__MAX_NUM_TYPE_IDS];
+ int64_t evictions[H5C__MAX_NUM_TYPE_IDS];
+ int64_t renames[H5C__MAX_NUM_TYPE_IDS];
+
+ int64_t total_ht_insertions;
+ int64_t total_ht_deletions;
+ int64_t successful_ht_searches;
+ int64_t total_successful_ht_search_depth;
+ int64_t failed_ht_searches;
+ int64_t total_failed_ht_search_depth;
+
+ int32_t max_index_len;
+ size_t max_index_size;
+
+ int32_t max_tree_len;
+ size_t max_tree_size;
+
+ int32_t max_pl_len;
+ size_t max_pl_size;
+
+#if H5C_COLLECT_CACHE_ENTRY_STATS
+
+ int32_t max_accesses[H5C__MAX_NUM_TYPE_IDS];
+ int32_t min_accesses[H5C__MAX_NUM_TYPE_IDS];
+ int32_t max_clears[H5C__MAX_NUM_TYPE_IDS];
+ int32_t max_flushes[H5C__MAX_NUM_TYPE_IDS];
+ size_t max_size[H5C__MAX_NUM_TYPE_IDS];
+
+#endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
+
+#endif /* H5C_COLLECT_CACHE_STATS */
+
+ hbool_t skip_file_checks;
+ hbool_t skip_dxpl_id_checks;
+
+} local_H5C_t;
+
+
+/* global variable declarations: */
+
+static hbool_t write_permitted = TRUE;
+static hbool_t pass = TRUE; /* set to false on error */
+const char *failure_mssg = NULL;
+
+test_entry_t pico_entries[NUM_PICO_ENTRIES];
+test_entry_t nano_entries[NUM_NANO_ENTRIES];
+test_entry_t micro_entries[NUM_MICRO_ENTRIES];
+test_entry_t tiny_entries[NUM_TINY_ENTRIES];
+test_entry_t small_entries[NUM_SMALL_ENTRIES];
+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 * entries[NUMBER_OF_ENTRY_TYPES] =
+{
+ pico_entries,
+ nano_entries,
+ micro_entries,
+ tiny_entries,
+ small_entries,
+ medium_entries,
+ large_entries,
+ huge_entries,
+ monster_entries
+};
+
+const int32_t max_indices[NUMBER_OF_ENTRY_TYPES] =
+{
+ NUM_PICO_ENTRIES - 1,
+ NUM_NANO_ENTRIES - 1,
+ NUM_MICRO_ENTRIES - 1,
+ NUM_TINY_ENTRIES - 1,
+ NUM_SMALL_ENTRIES - 1,
+ NUM_MEDIUM_ENTRIES - 1,
+ NUM_LARGE_ENTRIES - 1,
+ NUM_HUGE_ENTRIES - 1,
+ NUM_MONSTER_ENTRIES - 1
+};
+
+const size_t entry_sizes[NUMBER_OF_ENTRY_TYPES] =
+{
+ PICO_ENTRY_SIZE,
+ NANO_ENTRY_SIZE,
+ MICRO_ENTRY_SIZE,
+ TINY_ENTRY_SIZE,
+ SMALL_ENTRY_SIZE,
+ MEDIUM_ENTRY_SIZE,
+ LARGE_ENTRY_SIZE,
+ HUGE_ENTRY_SIZE,
+ MONSTER_ENTRY_SIZE
+};
+
+const haddr_t base_addrs[NUMBER_OF_ENTRY_TYPES] =
+{
+ PICO_BASE_ADDR,
+ NANO_BASE_ADDR,
+ MICRO_BASE_ADDR,
+ TINY_BASE_ADDR,
+ SMALL_BASE_ADDR,
+ MEDIUM_BASE_ADDR,
+ LARGE_BASE_ADDR,
+ HUGE_BASE_ADDR,
+ MONSTER_BASE_ADDR
+};
+
+const haddr_t alt_base_addrs[NUMBER_OF_ENTRY_TYPES] =
+{
+ PICO_ALT_BASE_ADDR,
+ NANO_ALT_BASE_ADDR,
+ MICRO_ALT_BASE_ADDR,
+ TINY_ALT_BASE_ADDR,
+ SMALL_ALT_BASE_ADDR,
+ MEDIUM_ALT_BASE_ADDR,
+ LARGE_ALT_BASE_ADDR,
+ HUGE_ALT_BASE_ADDR,
+ MONSTER_ALT_BASE_ADDR
+};
+
+const char * entry_type_names[NUMBER_OF_ENTRY_TYPES] =
+{
+ "pico entries -- 1 B",
+ "nano entries -- 4 B",
+ "micro entries -- 16 B",
+ "tiny entries -- 64 B",
+ "small entries -- 256 B",
+ "medium entries -- 1 KB",
+ "large entries -- 4 KB",
+ "huge entries -- 16 KB",
+ "monster entries -- 64 KB"
+};
+
+
+/* call back function declarations: */
+
+static herr_t check_write_permitted(H5F_t UNUSED * f,
+ hid_t UNUSED dxpl_id,
+ hbool_t * write_permitted_ptr);
+
+static herr_t clear(H5F_t * f, void * thing, hbool_t dest);
+
+herr_t pico_clear(H5F_t * f, void * thing, hbool_t dest);
+herr_t nano_clear(H5F_t * f, void * thing, hbool_t dest);
+herr_t micro_clear(H5F_t * f, void * thing, hbool_t dest);
+herr_t tiny_clear(H5F_t * f, void * thing, hbool_t dest);
+herr_t small_clear(H5F_t * f, void * thing, hbool_t dest);
+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);
+
+
+static herr_t destroy(H5F_t UNUSED * f, void * thing);
+
+herr_t pico_dest(H5F_t * f, void * thing);
+herr_t nano_dest(H5F_t * f, void * thing);
+herr_t micro_dest(H5F_t * f, void * thing);
+herr_t tiny_dest(H5F_t * f, void * thing);
+herr_t small_dest(H5F_t * f, void * thing);
+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);
+
+
+static herr_t flush(H5F_t *f, hid_t UNUSED 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);
+herr_t nano_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest,
+ haddr_t addr, void *thing);
+herr_t micro_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest,
+ haddr_t addr, void *thing);
+herr_t tiny_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest,
+ haddr_t addr, void *thing);
+herr_t small_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest,
+ haddr_t addr, void *thing);
+herr_t medium_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest,
+ haddr_t addr, void *thing);
+herr_t large_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest,
+ haddr_t addr, void *thing);
+herr_t huge_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest,
+ haddr_t addr, void *thing);
+herr_t monster_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest,
+ haddr_t addr, void *thing);
+
+
+static void * load(H5F_t UNUSED *f, hid_t UNUSED dxpl_id, haddr_t addr,
+ const void UNUSED *udata1, void UNUSED *udata2);
+
+void * pico_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2);
+void * nano_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2);
+void * micro_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2);
+void * tiny_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2);
+void * small_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2);
+void * medium_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2);
+void * large_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2);
+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);
+
+
+static herr_t size(H5F_t UNUSED * f, void * thing, size_t * size_ptr);
+
+herr_t pico_size(H5F_t * f, void * thing, size_t * size_ptr);
+herr_t nano_size(H5F_t * f, void * thing, size_t * size_ptr);
+herr_t micro_size(H5F_t * f, void * thing, size_t * size_ptr);
+herr_t tiny_size(H5F_t * f, void * thing, size_t * size_ptr);
+herr_t small_size(H5F_t * f, void * thing, size_t * size_ptr);
+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);
+
+
+/* callback table declaration */
+
+static const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] =
+{
+ {
+ PICO_ENTRY_TYPE,
+ (H5C_load_func_t)pico_load,
+ (H5C_flush_func_t)pico_flush,
+ (H5C_dest_func_t)pico_dest,
+ (H5C_clear_func_t)pico_clear,
+ (H5C_size_func_t)pico_size
+ },
+ {
+ NANO_ENTRY_TYPE,
+ (H5C_load_func_t)nano_load,
+ (H5C_flush_func_t)nano_flush,
+ (H5C_dest_func_t)nano_dest,
+ (H5C_clear_func_t)nano_clear,
+ (H5C_size_func_t)nano_size
+ },
+ {
+ MICRO_ENTRY_TYPE,
+ (H5C_load_func_t)micro_load,
+ (H5C_flush_func_t)micro_flush,
+ (H5C_dest_func_t)micro_dest,
+ (H5C_clear_func_t)micro_clear,
+ (H5C_size_func_t)micro_size
+ },
+ {
+ TINY_ENTRY_TYPE,
+ (H5C_load_func_t)tiny_load,
+ (H5C_flush_func_t)tiny_flush,
+ (H5C_dest_func_t)tiny_dest,
+ (H5C_clear_func_t)tiny_clear,
+ (H5C_size_func_t)tiny_size
+ },
+ {
+ SMALL_ENTRY_TYPE,
+ (H5C_load_func_t)small_load,
+ (H5C_flush_func_t)small_flush,
+ (H5C_dest_func_t)small_dest,
+ (H5C_clear_func_t)small_clear,
+ (H5C_size_func_t)small_size
+ },
+ {
+ MEDIUM_ENTRY_TYPE,
+ (H5C_load_func_t)medium_load,
+ (H5C_flush_func_t)medium_flush,
+ (H5C_dest_func_t)medium_dest,
+ (H5C_clear_func_t)medium_clear,
+ (H5C_size_func_t)medium_size
+ },
+ {
+ LARGE_ENTRY_TYPE,
+ (H5C_load_func_t)large_load,
+ (H5C_flush_func_t)large_flush,
+ (H5C_dest_func_t)large_dest,
+ (H5C_clear_func_t)large_clear,
+ (H5C_size_func_t)large_size
+ },
+ {
+ HUGE_ENTRY_TYPE,
+ (H5C_load_func_t)huge_load,
+ (H5C_flush_func_t)huge_flush,
+ (H5C_dest_func_t)huge_dest,
+ (H5C_clear_func_t)huge_clear,
+ (H5C_size_func_t)huge_size
+ },
+ {
+ MONSTER_ENTRY_TYPE,
+ (H5C_load_func_t)monster_load,
+ (H5C_flush_func_t)monster_flush,
+ (H5C_dest_func_t)monster_dest,
+ (H5C_clear_func_t)monster_clear,
+ (H5C_size_func_t)monster_size
+ }
+};
+
+
+/* private function declarations: */
+
+static void addr_to_type_and_index(haddr_t addr,
+ int32_t * type_ptr,
+ int32_t * index_ptr);
+
+#if 0 /* keep this for a while -- it may be useful */
+static haddr_t type_and_index_to_addr(int32_t type,
+ int32_t idx);
+#endif
+
+static void insert_entry(H5C_t * cache_ptr,
+ int32_t type,
+ int32_t idx,
+ hbool_t dirty);
+
+static void rename_entry(H5C_t * cache_ptr,
+ int32_t type,
+ int32_t idx,
+ hbool_t main_addr);
+
+static void protect_entry(H5C_t * cache_ptr,
+ int32_t type,
+ int32_t idx);
+
+hbool_t entry_in_cache(H5C_t * cache_ptr,
+ int32_t type,
+ int32_t idx);
+
+static void reset_entries(void);
+
+static H5C_t * setup_cache(size_t max_cache_size, size_t min_clean_size);
+
+static void row_major_scan_forward(H5C_t * cache_ptr,
+ int32_t lag,
+ hbool_t verbose,
+ hbool_t reset_stats,
+ hbool_t display_stats,
+ hbool_t display_detailed_stats,
+ hbool_t do_inserts,
+ hbool_t dirty_inserts,
+ hbool_t do_renames,
+ hbool_t rename_to_main_addr,
+ hbool_t do_destroys,
+ int dirty_destroys,
+ int dirty_unprotects);
+
+static void row_major_scan_backward(H5C_t * cache_ptr,
+ int32_t lag,
+ hbool_t verbose,
+ hbool_t reset_stats,
+ hbool_t display_stats,
+ hbool_t display_detailed_stats,
+ hbool_t do_inserts,
+ hbool_t dirty_inserts,
+ hbool_t do_renames,
+ hbool_t rename_to_main_addr,
+ hbool_t do_destroys,
+ int dirty_destroys,
+ int dirty_unprotects);
+
+static void col_major_scan_forward(H5C_t * cache_ptr,
+ int32_t lag,
+ hbool_t verbose,
+ hbool_t reset_stats,
+ hbool_t display_stats,
+ hbool_t display_detailed_stats,
+ hbool_t do_inserts,
+ hbool_t dirty_inserts,
+ int dirty_unprotects);
+
+static void col_major_scan_backward(H5C_t * cache_ptr,
+ int32_t lag,
+ hbool_t verbose,
+ hbool_t reset_stats,
+ hbool_t display_stats,
+ hbool_t display_detailed_stats,
+ hbool_t do_inserts,
+ hbool_t dirty_inserts,
+ int dirty_unprotects);
+
+static void smoke_check_1(void);
+static void smoke_check_2(void);
+static void smoke_check_3(void);
+static void smoke_check_4(void);
+static void write_permitted_check(void);
+static void check_flush_protected_err(void);
+static void check_destroy_protected_err(void);
+static void check_duplicate_insert_err(void);
+static void check_rename_err(void);
+static void check_double_protect_err(void);
+static void check_double_unprotect_err(void);
+
+static void takedown_cache(H5C_t * cache_ptr,
+ hbool_t dump_stats,
+ hbool_t dump_detailed_stats);
+
+static void flush_cache(H5C_t * cache_ptr,
+ hbool_t destroy_entries,
+ hbool_t dump_stats,
+ hbool_t dump_detailed_stats);
+
+static void unprotect_entry(H5C_t * cache_ptr,
+ int32_t type,
+ int32_t idx,
+ int dirty,
+ hbool_t deleted);
+
+static void verify_clean(void);
+
+static void verify_unprotected(void);
+
+
+
+/* address translation funtions: */
+
+/*-------------------------------------------------------------------------
+ * Function: addr_to_type_and_index
+ *
+ * Purpose: Given an address, compute the type and index of the
+ * associated entry.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+addr_to_type_and_index(haddr_t addr,
+ int32_t * type_ptr,
+ int32_t * index_ptr)
+{
+ int i;
+ int32_t type;
+ int32_t idx;
+
+ HDassert( type_ptr );
+ HDassert( index_ptr );
+
+ /* we only have a small number of entry types, so just do a
+ * linear search. If NUMBER_OF_ENTRY_TYPES grows, we may want
+ * to do a binary search instead.
+ */
+ i = 1;
+ if ( addr >= PICO_ALT_BASE_ADDR ) {
+
+ while ( ( i < NUMBER_OF_ENTRY_TYPES ) &&
+ ( addr >= alt_base_addrs[i] ) )
+ {
+ i++;
+ }
+
+ } else {
+
+ while ( ( i < NUMBER_OF_ENTRY_TYPES ) &&
+ ( addr >= base_addrs[i] ) )
+ {
+ i++;
+ }
+ }
+
+ type = i - 1;
+
+ HDassert( ( type >= 0 ) && ( type < NUMBER_OF_ENTRY_TYPES ) );
+
+ if ( addr >= PICO_ALT_BASE_ADDR ) {
+
+ idx = (addr - alt_base_addrs[type]) / entry_sizes[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( (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;
+ *index_ptr = idx;
+
+ return;
+
+} /* addr_to_type_and_index() */
+
+
+#if 0 /* This function has never been used, but we may want it
+ * some time. Lets keep it for now.
+ */
+/*-------------------------------------------------------------------------
+ * Function: type_and_index_to_addr
+ *
+ * Purpose: Given a type and index of an entry, compute the associated
+ * addr and return that value.
+ *
+ * Return: computed addr
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+type_and_index_to_addr(int32_t type,
+ int32_t idx)
+{
+ haddr_t addr;
+
+ HDassert( ( type >= 0 ) && ( type < NUMBER_OF_ENTRY_TYPES ) );
+ HDassert( ( idx >= 0 ) && ( idx <= max_indices[type] ) );
+
+ addr = base_addrs[type] + (((haddr_t)idx) * entry_sizes[type]);
+
+ HDassert( addr == (entries[type])[idx].addr );
+
+ if ( (entries[type])[idx].at_main_addr ) {
+
+ HDassert( addr == (entries[type])[idx].main_addr );
+
+ } else {
+
+ HDassert( addr == (entries[type])[idx].alt_addr );
+ }
+
+ return(addr);
+
+} /* type_and_index_to_addr() */
+
+#endif
+
+
+/* Call back functions: */
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5AC_check_if_write_permitted
+ *
+ * Purpose: Determine if a write is permitted under the current
+ * circumstances, and set *write_permitted_ptr accordingly.
+ * As a general rule it is, but when we are running in parallel
+ * mode with collective I/O, we must ensure that a read cannot
+ * cause a write.
+ *
+ * In the event of failure, the value of *write_permitted_ptr
+ * is undefined.
+ *
+ * Return: Non-negative on success/Negative on failure.
+ *
+ * Programmer: John Mainzer, 5/15/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static herr_t
+check_write_permitted(H5F_t UNUSED * f,
+ hid_t UNUSED dxpl_id,
+ hbool_t * write_permitted_ptr)
+{
+
+ HDassert( write_permitted_ptr );
+ *write_permitted_ptr = write_permitted;
+
+ return(SUCCEED);
+
+} /* check_write_permitted() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: clear & friends
+ *
+ * Purpose: clear the entry. The helper functions verify that the
+ * correct version of clear is being called, and then call
+ * clear proper.
+ *
+ * Return: SUCCEED
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static herr_t
+clear(H5F_t * f,
+ void * thing,
+ hbool_t dest)
+{
+ test_entry_t * entry_ptr;
+ test_entry_t * base_addr;
+
+ HDassert( thing );
+
+ entry_ptr = (test_entry_t *)thing;
+ base_addr = entries[entry_ptr->type];
+
+ HDassert( entry_ptr->index >= 0 );
+ HDassert( entry_ptr->index <= max_indices[entry_ptr->type] );
+ 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->header.size == entry_ptr->size );
+ HDassert( entry_ptr->size == entry_sizes[entry_ptr->type] );
+
+ entry_ptr->header.is_dirty = FALSE;
+ entry_ptr->is_dirty = FALSE;
+
+ if ( dest ) {
+
+ destroy(f, thing);
+
+ }
+
+ return(SUCCEED);
+
+} /* clear() */
+
+herr_t
+pico_clear(H5F_t * f, void * thing, hbool_t dest)
+{
+ HDassert ( ((test_entry_t *)thing)->type == PICO_ENTRY_TYPE );
+ return(clear(f, thing, dest));
+}
+
+herr_t
+nano_clear(H5F_t * f, void * thing, hbool_t dest)
+{
+ HDassert ( ((test_entry_t *)thing)->type == NANO_ENTRY_TYPE );
+ return(clear(f, thing, dest));
+}
+
+herr_t
+micro_clear(H5F_t * f, void * thing, hbool_t dest)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MICRO_ENTRY_TYPE );
+ return(clear(f, thing, dest));
+}
+
+herr_t
+tiny_clear(H5F_t * f, void * thing, hbool_t dest)
+{
+ HDassert ( ((test_entry_t *)thing)->type == TINY_ENTRY_TYPE );
+ return(clear(f, thing, dest));
+}
+
+herr_t
+small_clear(H5F_t * f, void * thing, hbool_t dest)
+{
+ HDassert ( ((test_entry_t *)thing)->type == SMALL_ENTRY_TYPE );
+ return(clear(f, thing, dest));
+}
+
+herr_t
+medium_clear(H5F_t * f, void * thing, hbool_t dest)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MEDIUM_ENTRY_TYPE );
+ return(clear(f, thing, dest));
+}
+
+herr_t
+large_clear(H5F_t * f, void * thing, hbool_t dest)
+{
+ HDassert ( ((test_entry_t *)thing)->type == LARGE_ENTRY_TYPE );
+ return(clear(f, thing, dest));
+}
+
+herr_t
+huge_clear(H5F_t * f, void * thing, hbool_t dest)
+{
+ HDassert ( ((test_entry_t *)thing)->type == HUGE_ENTRY_TYPE );
+ return(clear(f, thing, dest));
+}
+
+herr_t
+monster_clear(H5F_t * f, void * thing, hbool_t dest)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MONSTER_ENTRY_TYPE );
+ return(clear(f, thing, dest));
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: dest & friends
+ *
+ * Purpose: Destroy the entry. The helper functions verify that the
+ * correct version of dest is being called, and then call
+ * dest proper.
+ *
+ * Return: SUCCEED
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static herr_t
+destroy(H5F_t UNUSED * f,
+ void * thing)
+{
+ test_entry_t * entry_ptr;
+ test_entry_t * base_addr;
+
+ HDassert( thing );
+
+ entry_ptr = (test_entry_t *)thing;
+ base_addr = entries[entry_ptr->type];
+
+ HDassert ( entry_ptr->index >= 0 );
+ HDassert ( entry_ptr->index <= max_indices[entry_ptr->type] );
+ 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->header.size == entry_ptr->size );
+ HDassert( entry_ptr->size == entry_sizes[entry_ptr->type] );
+
+ HDassert( !(entry_ptr->is_dirty) );
+ HDassert( !(entry_ptr->header.is_dirty) );
+
+ return(SUCCEED);
+
+} /* dest() */
+
+herr_t
+pico_dest(H5F_t * f, void * thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == PICO_ENTRY_TYPE );
+ return(destroy(f, thing));
+}
+
+herr_t
+nano_dest(H5F_t * f, void * thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == NANO_ENTRY_TYPE );
+ return(destroy(f, thing));
+}
+
+herr_t
+micro_dest(H5F_t * f, void * thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MICRO_ENTRY_TYPE );
+ return(destroy(f, thing));
+}
+
+herr_t
+tiny_dest(H5F_t * f, void * thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == TINY_ENTRY_TYPE );
+ return(destroy(f, thing));
+}
+
+herr_t
+small_dest(H5F_t * f, void * thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == SMALL_ENTRY_TYPE );
+ return(destroy(f, thing));
+}
+
+herr_t
+medium_dest(H5F_t * f, void * thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MEDIUM_ENTRY_TYPE );
+ return(destroy(f, thing));
+}
+
+herr_t
+large_dest(H5F_t * f, void * thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == LARGE_ENTRY_TYPE );
+ return(destroy(f, thing));
+}
+
+herr_t
+huge_dest(H5F_t * f, void * thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == HUGE_ENTRY_TYPE );
+ return(destroy(f, thing));
+}
+
+herr_t
+monster_dest(H5F_t * f, void * thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MONSTER_ENTRY_TYPE );
+ return(destroy(f, thing));
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: flush & friends
+ *
+ * Purpose: flush the entry and mark it as clean. The helper functions
+ * verify that the correct version of flush is being called,
+ * and then call flush proper.
+ *
+ * Return: SUCCEED
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static herr_t
+flush(H5F_t *f,
+ hid_t UNUSED dxpl_id,
+ hbool_t dest,
+ haddr_t addr,
+ void *thing)
+{
+ test_entry_t * entry_ptr;
+ test_entry_t * base_addr;
+
+ HDassert( thing );
+
+ entry_ptr = (test_entry_t *)thing;
+ base_addr = entries[entry_ptr->type];
+
+ HDassert( entry_ptr->index >= 0 );
+ HDassert( entry_ptr->index <= max_indices[entry_ptr->type] );
+ 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->addr == addr );
+ HDassert( entry_ptr->header.size == entry_ptr->size );
+ HDassert( entry_ptr->size == entry_sizes[entry_ptr->type] );
+
+ if ( ( ! write_permitted ) && ( entry_ptr->is_dirty ) ) {
+
+ pass = FALSE;
+ failure_mssg = "called flush when write_permitted is FALSE.";
+ }
+
+ if ( entry_ptr->is_dirty ) {
+
+ (entry_ptr->writes)++;
+ entry_ptr->is_dirty = FALSE;
+ entry_ptr->header.is_dirty = FALSE;
+ }
+
+ if ( dest ) {
+
+ destroy(f, thing);
+
+ }
+
+ return(SUCCEED);
+
+} /* flush() */
+
+herr_t
+pico_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == PICO_ENTRY_TYPE );
+ return(flush(f, dxpl_id, dest, addr, thing));
+}
+
+herr_t
+nano_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == NANO_ENTRY_TYPE );
+ return(flush(f, dxpl_id, dest, addr, thing));
+}
+
+herr_t
+micro_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MICRO_ENTRY_TYPE );
+ return(flush(f, dxpl_id, dest, addr, thing));
+}
+
+herr_t
+tiny_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == TINY_ENTRY_TYPE );
+ return(flush(f, dxpl_id, dest, addr, thing));
+}
+
+herr_t
+small_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == SMALL_ENTRY_TYPE );
+ return(flush(f, dxpl_id, dest, addr, thing));
+}
+
+herr_t
+medium_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MEDIUM_ENTRY_TYPE );
+ return(flush(f, dxpl_id, dest, addr, thing));
+}
+
+herr_t
+large_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == LARGE_ENTRY_TYPE );
+ return(flush(f, dxpl_id, dest, addr, thing));
+}
+
+herr_t
+huge_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == HUGE_ENTRY_TYPE );
+ return(flush(f, dxpl_id, dest, addr, thing));
+}
+
+herr_t
+monster_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, void *thing)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MONSTER_ENTRY_TYPE );
+ return(flush(f, dxpl_id, dest, addr, thing));
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: load & friends
+ *
+ * Purpose: "load" the requested entry and mark it as clean. The
+ * helper functions verify that the correct version of load
+ * is being called, and then call load proper.
+ *
+ * Return: SUCCEED
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void *
+load(H5F_t UNUSED *f,
+ hid_t UNUSED dxpl_id,
+ haddr_t addr,
+ const void UNUSED *udata1,
+ void UNUSED *udata2)
+{
+ int32_t type;
+ int32_t idx;
+ test_entry_t * entry_ptr;
+ test_entry_t * base_addr;
+
+ addr_to_type_and_index(addr, &type, &idx);
+
+ base_addr = entries[type];
+ entry_ptr = &(base_addr[idx]);
+
+ HDassert( entry_ptr->type == type );
+ HDassert( entry_ptr->type >= 0 );
+ HDassert( entry_ptr->type < NUMBER_OF_ENTRY_TYPES );
+ HDassert( entry_ptr->index == idx );
+ HDassert( entry_ptr->index >= 0 );
+ 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] );
+
+ entry_ptr->is_dirty = FALSE;
+
+ (entry_ptr->reads)++;
+
+ return(entry_ptr);
+
+} /* load() */
+
+void *
+pico_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2)
+{
+ return(load(f, dxpl_id, addr, udata1, udata2));
+}
+
+void *
+nano_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2)
+{
+ return(load(f, dxpl_id, addr, udata1, udata2));
+}
+
+void *
+micro_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2)
+{
+ return(load(f, dxpl_id, addr, udata1, udata2));
+}
+
+void *
+tiny_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2)
+{
+ return(load(f, dxpl_id, addr, udata1, udata2));
+}
+
+void *
+small_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2)
+{
+ return(load(f, dxpl_id, addr, udata1, udata2));
+}
+
+void *
+medium_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2)
+{
+ return(load(f, dxpl_id, addr, udata1, udata2));
+}
+
+void *
+large_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2)
+{
+ return(load(f, dxpl_id, addr, udata1, udata2));
+}
+
+void *
+huge_load(H5F_t *f, hid_t dxpl_id, haddr_t addr,
+ const void *udata1, void *udata2)
+{
+ return(load(f, dxpl_id, addr, udata1, udata2));
+}
+
+void *
+monster_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
+ *
+ * Purpose: Get the size of the specified entry. The helper functions
+ * verify that the correct version of size is being called,
+ * and then call size proper.
+ *
+ * Return: SUCCEED
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static herr_t
+size(H5F_t UNUSED * f,
+ void * thing,
+ size_t * size_ptr)
+{
+ test_entry_t * entry_ptr;
+ test_entry_t * base_addr;
+
+ HDassert( size_ptr );
+ HDassert( thing );
+
+ entry_ptr = (test_entry_t *)thing;
+ base_addr = entries[entry_ptr->type];
+
+ HDassert( entry_ptr->index >= 0 );
+ HDassert( entry_ptr->index <= max_indices[entry_ptr->type] );
+ 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] );
+
+ *size_ptr = entry_ptr->size;
+
+ return(SUCCEED);
+
+} /* size() */
+
+herr_t
+pico_size(H5F_t * f, void * thing, size_t * size_ptr)
+{
+ HDassert ( ((test_entry_t *)thing)->type == PICO_ENTRY_TYPE );
+ return(size(f, thing, size_ptr));
+}
+
+herr_t
+nano_size(H5F_t * f, void * thing, size_t * size_ptr)
+{
+ HDassert ( ((test_entry_t *)thing)->type == NANO_ENTRY_TYPE );
+ return(size(f, thing, size_ptr));
+}
+
+herr_t
+micro_size(H5F_t * f, void * thing, size_t * size_ptr)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MICRO_ENTRY_TYPE );
+ return(size(f, thing, size_ptr));
+}
+
+herr_t
+tiny_size(H5F_t * f, void * thing, size_t * size_ptr)
+{
+ HDassert ( ((test_entry_t *)thing)->type == TINY_ENTRY_TYPE );
+ return(size(f, thing, size_ptr));
+}
+
+herr_t
+small_size(H5F_t * f, void * thing, size_t * size_ptr)
+{
+ HDassert ( ((test_entry_t *)thing)->type == SMALL_ENTRY_TYPE );
+ return(size(f, thing, size_ptr));
+}
+
+herr_t
+medium_size(H5F_t * f, void * thing, size_t * size_ptr)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MEDIUM_ENTRY_TYPE );
+ return(size(f, thing, size_ptr));
+}
+
+herr_t
+large_size(H5F_t * f, void * thing, size_t * size_ptr)
+{
+ HDassert ( ((test_entry_t *)thing)->type == LARGE_ENTRY_TYPE );
+ return(size(f, thing, size_ptr));
+}
+
+herr_t
+huge_size(H5F_t * f, void * thing, size_t * size_ptr)
+{
+ HDassert ( ((test_entry_t *)thing)->type == HUGE_ENTRY_TYPE );
+ return(size(f, thing, size_ptr));
+}
+
+herr_t
+monster_size(H5F_t * f, void * thing, size_t * size_ptr)
+{
+ HDassert ( ((test_entry_t *)thing)->type == MONSTER_ENTRY_TYPE );
+ return(size(f, thing, size_ptr));
+}
+
+
+/**************************************************************************/
+/**************************************************************************/
+/************************** test utility functions: ***********************/
+/**************************************************************************/
+/**************************************************************************/
+
+/*-------------------------------------------------------------------------
+ * Function: entry_in_cache
+ *
+ * Purpose: Given a pointer to a cache, an entry type, and an index,
+ * determine if the entry is currently in the cache.
+ *
+ * Return: TRUE if the entry is in the cache, and FALSE otherwise.
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+hbool_t
+entry_in_cache(H5C_t * cache_ptr,
+ int32_t type,
+ int32_t idx)
+{
+ hbool_t in_cache = FALSE; /* will set to TRUE if necessary */
+ test_entry_t * base_addr;
+ test_entry_t * entry_ptr;
+ H5C_cache_entry_t * test_ptr = NULL;
+
+ HDassert( cache_ptr );
+ HDassert( ( 0 <= type ) && ( type < NUMBER_OF_ENTRY_TYPES ) );
+ HDassert( ( 0 <= idx ) && ( idx <= max_indices[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 );
+
+ H5C__SEARCH_INDEX(((local_H5C_t *)cache_ptr), entry_ptr->addr, test_ptr)
+
+ if ( test_ptr != NULL ) {
+
+ in_cache = TRUE;
+ HDassert( test_ptr == (H5C_cache_entry_t *)entry_ptr );
+ HDassert( entry_ptr->addr == entry_ptr->header.addr );
+ }
+
+ return(in_cache);
+
+} /* entry_in_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: reset_entries
+ *
+ * Purpose: reset the contents of the entries arrays to know values.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+reset_entries(void)
+
+{
+ int i;
+ int j;
+ int32_t max_index;
+ haddr_t addr = 0;
+ haddr_t alt_addr = PICO_ALT_BASE_ADDR;
+ size_t entry_size;
+ test_entry_t * base_addr;
+
+ for ( i = 0; i < NUMBER_OF_ENTRY_TYPES; i++ )
+ {
+ entry_size = entry_sizes[i];
+ max_index = max_indices[i];
+ base_addr = entries[i];
+
+ HDassert( base_addr );
+
+ for ( j = 0; j <= max_index; j++ )
+ {
+ /* one can argue that we should fill the header with garbage.
+ * If this is desired, we can simply comment out the header
+ * initialization - the headers will be full of garbage soon
+ * enough.
+ */
+
+ base_addr[j].header.addr = (haddr_t)0;
+ base_addr[j].header.size = (size_t)0;
+ base_addr[j].header.type = NULL;
+ base_addr[j].header.is_dirty = FALSE;
+ base_addr[j].header.is_protected = FALSE;
+ base_addr[j].header.next = NULL;
+ base_addr[j].header.prev = NULL;
+ base_addr[j].header.aux_next = NULL;
+ base_addr[j].header.aux_prev = NULL;
+
+ base_addr[j].self = &(base_addr[j]);
+ base_addr[j].addr = addr;
+ base_addr[j].at_main_addr = TRUE;
+ base_addr[j].main_addr = addr;
+ base_addr[j].alt_addr = alt_addr;
+ base_addr[j].size = entry_size;
+ base_addr[j].type = i;
+ base_addr[j].index = j;
+ base_addr[j].reads = 0;
+ base_addr[j].writes = 0;
+ base_addr[j].is_dirty = FALSE;
+ base_addr[j].is_protected = FALSE;
+
+ addr += (haddr_t)entry_size;
+ alt_addr += (haddr_t)entry_size;
+ }
+ }
+
+ return;
+
+} /* reset_entries() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: verify_clean
+ *
+ * Purpose: Verify that all cache entries are marked as clean. If any
+ * are not, set pass to FALSE.
+ *
+ * Do nothing if pass is FALSE on entry.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+verify_clean(void)
+
+{
+ int i;
+ int j;
+ int dirty_count = 0;
+ int32_t max_index;
+ test_entry_t * base_addr;
+
+ if ( pass ) {
+
+ for ( i = 0; i < NUMBER_OF_ENTRY_TYPES; i++ )
+ {
+ max_index = max_indices[i];
+ base_addr = entries[i];
+
+ HDassert( base_addr );
+
+ for ( j = 0; j <= max_index; j++ )
+ {
+ if ( ( base_addr[j].header.is_dirty ) || ( base_addr[j].is_dirty ) ) {
+
+ dirty_count++;
+ }
+ }
+ }
+
+ if ( dirty_count > 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "verify_clean() found dirty entry(s).";
+ }
+ }
+
+ return;
+
+} /* verify_clean() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: verify_unprotected
+ *
+ * Purpose: Verify that no cache entries are marked as protected. If
+ * any are, set pass to FALSE.
+ *
+ * Do nothing if pass is FALSE on entry.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/10/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+verify_unprotected(void)
+
+{
+ int i;
+ int j;
+ int protected_count = 0;
+ int32_t max_index;
+ test_entry_t * base_addr;
+
+ if ( pass ) {
+
+ for ( i = 0; i < NUMBER_OF_ENTRY_TYPES; i++ )
+ {
+ max_index = max_indices[i];
+ base_addr = entries[i];
+
+ HDassert( base_addr );
+
+ for ( j = 0; j <= max_index; j++ )
+ {
+ HDassert( base_addr[j].header.is_protected ==
+ base_addr[j].is_protected );
+
+ if ( ( base_addr[j].header.is_protected ) ||
+ ( base_addr[j].is_protected ) ) {
+
+ protected_count++;
+ }
+ }
+ }
+
+ if ( protected_count > 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "verify_unprotected() found protected entry(s).";
+ }
+ }
+
+ return;
+
+} /* verify_unprotected() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: setup_cache()
+ *
+ * Purpose: Allocate a cache of the desired size and configure it for
+ * use in the test bed. Return a pointer to the new cache
+ * structure.
+ *
+ * Return: Pointer to new cache, or NULL on failure.
+ *
+ * Programmer: John Mainzer
+ * 6/11/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static H5C_t *
+setup_cache(size_t max_cache_size,
+ size_t min_clean_size)
+{
+ H5C_t * cache_ptr = NULL;
+
+ cache_ptr = H5C_create(max_cache_size,
+ min_clean_size,
+ (NUMBER_OF_ENTRY_TYPES - 1),
+ (const char **)entry_type_names,
+ check_write_permitted);
+
+ if ( cache_ptr == NULL ) {
+
+ pass = FALSE;
+ failure_mssg = "H5C_create() returned NULL.";
+
+ } else {
+
+ H5C_set_skip_flags(cache_ptr, TRUE, TRUE);
+ }
+
+ return(cache_ptr);
+
+} /* setup_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: takedown_cache()
+ *
+ * Purpose: Flush the specified cache and disable it. If requested,
+ * dump stats first. If pass is FALSE, do nothing.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/11/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+takedown_cache(H5C_t * cache_ptr,
+ hbool_t dump_stats,
+ hbool_t dump_detailed_stats)
+{
+ HDassert(cache_ptr);
+
+ if ( pass ) {
+
+ if ( dump_stats ) {
+
+ H5C_stats(cache_ptr, "test cache", dump_detailed_stats);
+ }
+
+ H5C_dest(NULL, -1, -1, cache_ptr);
+ }
+
+ return;
+
+} /* takedown_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: flush_cache()
+ *
+ * Purpose: Flush the specified cache, destroying all entries if
+ requested. If requested, dump stats first.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/23/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+flush_cache(H5C_t * cache_ptr,
+ hbool_t destroy_entries,
+ hbool_t dump_stats,
+ hbool_t dump_detailed_stats)
+{
+ herr_t result = 0;
+
+ HDassert(cache_ptr);
+
+ verify_unprotected();
+
+ if ( pass ) {
+
+ if ( destroy_entries ) {
+
+ result = H5C_flush_cache(NULL, -1, -1, cache_ptr,
+ H5F_FLUSH_INVALIDATE);
+
+ } else {
+
+ result = H5C_flush_cache(NULL, -1, -1, cache_ptr, 0);
+ }
+ }
+
+ if ( dump_stats ) {
+
+ H5C_stats(cache_ptr, "test cache", dump_detailed_stats);
+ }
+
+ if ( result < 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "error in H5C_flush_cache().";
+ }
+
+ return;
+
+} /* flush_cache() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: insert_entry()
+ *
+ * Purpose: Insert the entry indicated by the type and index. Mark
+ * it clean or dirty as indicated.
+ *
+ * Note that I don't see much practical use for inserting
+ * a clean entry, but the interface permits it so we should
+ * test it.
+ *
+ * Do nothing if pass is false.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/16/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+insert_entry(H5C_t * cache_ptr,
+ int32_t type,
+ int32_t idx,
+ hbool_t dirty)
+{
+ herr_t result;
+ 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] ) );
+
+ 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->is_protected) );
+
+ if ( dirty ) {
+
+ (entry_ptr->header).is_dirty = dirty;
+ entry_ptr->is_dirty = dirty;
+ }
+
+ result = H5C_insert_entry(NULL, -1, -1, cache_ptr, &(types[type]),
+ entry_ptr->addr, (void *)entry_ptr);
+
+ 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_insert().";
+ }
+
+ HDassert( ((entry_ptr->header).type)->id == type );
+ }
+
+ return;
+
+} /* insert_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: rename_entry()
+ *
+ * Purpose: Rename the entry indicated by the type and index to its
+ * main or alternate address as indicated. If the entry is
+ * already at the desired entry, do nothing.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/21/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+rename_entry(H5C_t * cache_ptr,
+ int32_t type,
+ int32_t idx,
+ hbool_t main_addr)
+{
+ herr_t result;
+ hbool_t done = TRUE; /* will set to FALSE if we have work to do */
+ haddr_t old_addr = HADDR_UNDEF;
+ haddr_t new_addr = HADDR_UNDEF;
+ 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] ) );
+
+ 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->is_protected) );
+ HDassert( !(entry_ptr->header.is_protected) );
+
+ if ( entry_ptr->at_main_addr && !main_addr ) {
+
+ /* rename to alt addr */
+
+ HDassert( entry_ptr->addr == entry_ptr->main_addr );
+
+ done = FALSE;
+ old_addr = entry_ptr->addr;
+ new_addr = entry_ptr->alt_addr;
+
+ } else if ( !(entry_ptr->at_main_addr) && main_addr ) {
+
+ /* rename to main addr */
+
+ HDassert( entry_ptr->addr == entry_ptr->alt_addr );
+
+ done = FALSE;
+ old_addr = entry_ptr->addr;
+ new_addr = entry_ptr->main_addr;
+ }
+
+ if ( ! done ) {
+
+ result = H5C_rename_entry(NULL, cache_ptr, &(types[type]),
+ old_addr, new_addr);
+ }
+
+ if ( ! done ) {
+
+ if ( ( result < 0 ) || ( entry_ptr->header.addr != new_addr ) ) {
+
+ pass = FALSE;
+ failure_mssg = "error in H5C_rename_entry().";
+
+ } else {
+
+ entry_ptr->addr = new_addr;
+ entry_ptr->at_main_addr = main_addr;
+ }
+ }
+
+ HDassert( ((entry_ptr->header).type)->id == type );
+
+ return;
+
+} /* insert_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: protect_entry()
+ *
+ * Purpose: Protect the entry indicated by the type and index.
+ *
+ * Do nothing if pass is FALSE on entry.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/11/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+protect_entry(H5C_t * cache_ptr,
+ int32_t type,
+ int32_t idx)
+{
+ /* const char * fcn_name = "protect_entry()"; */
+ test_entry_t * base_addr;
+ test_entry_t * entry_ptr;
+ H5C_cache_entry_t * cache_entry_ptr;
+
+ if ( pass ) {
+
+ HDassert( cache_ptr );
+ HDassert( ( 0 <= type ) && ( type < NUMBER_OF_ENTRY_TYPES ) );
+ HDassert( ( 0 <= idx ) && ( idx <= max_indices[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->is_protected) );
+
+ cache_entry_ptr = H5C_protect(NULL, -1, -1, cache_ptr, &(types[type]),
+ entry_ptr->addr, NULL, NULL);
+
+ if ( ( cache_entry_ptr != (void *)entry_ptr ) ||
+ ( !(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_protect().";
+
+ } else {
+
+ entry_ptr->is_protected = TRUE;
+
+ }
+
+ HDassert( ((entry_ptr->header).type)->id == type );
+ }
+
+ return;
+
+} /* protect_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: unprotect_entry()
+ *
+ * Purpose: Unprotect the entry indicated by the type and index.
+ *
+ * Do nothing if pass is FALSE on entry.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/12/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define NO_CHANGE -1
+
+static void
+unprotect_entry(H5C_t * cache_ptr,
+ int32_t type,
+ int32_t idx,
+ int dirty,
+ hbool_t deleted)
+{
+ /* const char * fcn_name = "unprotect_entry()"; */
+ herr_t result;
+ 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] ) );
+
+ 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->header.is_protected );
+ HDassert( entry_ptr->is_protected );
+
+ if ( ( dirty == TRUE ) || ( dirty == FALSE ) ) {
+
+ entry_ptr->header.is_dirty = dirty;
+ entry_ptr->is_dirty = dirty;
+ }
+
+ result = H5C_unprotect(NULL, -1, -1, cache_ptr, &(types[type]),
+ entry_ptr->addr, (void *)entry_ptr, deleted);
+
+ 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;
+ }
+
+ HDassert( ((entry_ptr->header).type)->id == type );
+ }
+
+ return;
+
+} /* unprotect_entry() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: row_major_scan_forward()
+ *
+ * Purpose: Do a sequence of inserts, protects, unprotects, renames,
+ * destroys while scanning through the set of entries. If
+ * pass is false on entry, do nothing.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/12/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+row_major_scan_forward(H5C_t * cache_ptr,
+ int32_t lag,
+ hbool_t verbose,
+ hbool_t reset_stats,
+ hbool_t display_stats,
+ hbool_t display_detailed_stats,
+ hbool_t do_inserts,
+ hbool_t dirty_inserts,
+ hbool_t do_renames,
+ hbool_t rename_to_main_addr,
+ hbool_t do_destroys,
+ int dirty_destroys,
+ int dirty_unprotects)
+{
+ const char * fcn_name = "row_major_scan_forward";
+ int32_t type;
+ int32_t idx;
+
+ if ( verbose )
+ HDfprintf(stdout, "%s(): entering.\n", fcn_name);
+
+ HDassert( lag > 5 );
+
+ type = 0;
+
+ if ( ( pass ) && ( reset_stats ) ) {
+
+ H5C_stats__reset(cache_ptr);
+ }
+
+ while ( ( pass ) && ( type < NUMBER_OF_ENTRY_TYPES ) )
+ {
+ idx = -lag;
+
+ while ( ( pass ) && ( idx <= (max_indices[type] + lag) ) )
+ {
+ if ( ( pass ) && ( do_inserts ) && ( (idx + lag) >= 0 ) &&
+ ( (idx + lag) <= max_indices[type] ) &&
+ ( ((idx + lag) % 2) == 0 ) &&
+ ( ! entry_in_cache(cache_ptr, type, (idx + lag)) ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(i, %d, %d) ", type, (idx + lag));
+
+ insert_entry(cache_ptr, type, (idx + lag), dirty_inserts);
+ }
+
+
+ if ( ( pass ) && ( (idx + lag - 1) >= 0 ) &&
+ ( (idx + lag - 1) <= max_indices[type] ) &&
+ ( ( (idx + lag - 1) % 3 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(p, %d, %d) ", type, (idx + lag - 1));
+
+ protect_entry(cache_ptr, type, (idx + lag - 1));
+ }
+
+ if ( ( pass ) && ( (idx + lag - 2) >= 0 ) &&
+ ( (idx + lag - 2) <= max_indices[type] ) &&
+ ( ( (idx + lag - 2) % 3 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(u, %d, %d) ", type, (idx + lag - 2));
+
+ unprotect_entry(cache_ptr, type, idx+lag-2, NO_CHANGE, FALSE);
+ }
+
+
+ if ( ( pass ) && ( do_renames ) && ( (idx + lag - 2) >= 0 ) &&
+ ( (idx + lag - 2) <= max_indices[type] ) &&
+ ( ( (idx + lag - 2) % 3 ) == 0 ) ) {
+
+ rename_entry(cache_ptr, type, (idx + lag - 2),
+ rename_to_main_addr);
+ }
+
+
+ if ( ( pass ) && ( (idx + lag - 3) >= 0 ) &&
+ ( (idx + lag - 3) <= max_indices[type] ) &&
+ ( ( (idx + lag - 3) % 5 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(p, %d, %d) ", type, (idx + lag - 3));
+
+ protect_entry(cache_ptr, type, (idx + lag - 3));
+ }
+
+ if ( ( pass ) && ( (idx + lag - 5) >= 0 ) &&
+ ( (idx + lag - 5) <= max_indices[type] ) &&
+ ( ( (idx + lag - 5) % 5 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(u, %d, %d) ", type, (idx + lag - 5));
+
+ unprotect_entry(cache_ptr, type, idx+lag-5, NO_CHANGE, FALSE);
+ }
+
+ if ( ( pass ) && ( idx >= 0 ) && ( idx <= max_indices[type] ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(p, %d, %d) ", type, idx);
+
+ protect_entry(cache_ptr, type, idx);
+ }
+
+
+ if ( ( pass ) && ( (idx - lag + 2) >= 0 ) &&
+ ( (idx - lag + 2) <= max_indices[type] ) &&
+ ( ( (idx - lag + 2) % 7 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(u, %d, %d) ", type, (idx - lag + 2));
+
+ unprotect_entry(cache_ptr, type, idx-lag+2, NO_CHANGE, FALSE);
+ }
+
+ if ( ( pass ) && ( (idx - lag + 1) >= 0 ) &&
+ ( (idx - lag + 1) <= max_indices[type] ) &&
+ ( ( (idx - lag + 1) % 7 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(p, %d, %d) ", type, (idx - lag + 1));
+
+ protect_entry(cache_ptr, type, (idx - lag + 1));
+ }
+
+
+ if ( do_destroys ) {
+
+ if ( ( pass ) && ( (idx - lag) >= 0 ) &&
+ ( ( idx - lag) <= max_indices[type] ) ) {
+
+ switch ( (idx - lag) %4 ) {
+
+ case 0: /* we just did an insert */
+ unprotect_entry(cache_ptr, type, idx - lag,
+ NO_CHANGE, FALSE);
+ break;
+
+ case 1:
+ if ( (entries[type])[idx-lag].is_dirty ) {
+
+ unprotect_entry(cache_ptr, type, idx - lag,
+ NO_CHANGE, FALSE);
+ } else {
+
+ unprotect_entry(cache_ptr, type, idx - lag,
+ dirty_unprotects, FALSE);
+ }
+ break;
+
+ case 2: /* we just did an insrt */
+ unprotect_entry(cache_ptr, type, idx - lag,
+ NO_CHANGE, TRUE);
+ break;
+
+ case 3:
+ if ( (entries[type])[idx-lag].is_dirty ) {
+
+ unprotect_entry(cache_ptr, type, idx - lag,
+ NO_CHANGE, TRUE);
+ } else {
+
+ unprotect_entry(cache_ptr, type, idx - lag,
+ dirty_destroys, TRUE);
+ }
+ break;
+
+ default:
+ HDassert(0); /* this can't happen... */
+ break;
+ }
+ }
+
+ } else {
+
+ if ( ( pass ) && ( (idx - lag) >= 0 ) &&
+ ( ( idx - lag) <= max_indices[type] ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(u, %d, %d) ", type, (idx - lag));
+
+ unprotect_entry(cache_ptr, type, idx - lag,
+ dirty_unprotects, FALSE);
+ }
+ }
+
+ if ( verbose )
+ HDfprintf(stdout, "\n");
+
+ idx++;
+ }
+ type++;
+ }
+
+ if ( ( pass ) && ( display_stats ) ) {
+
+ H5C_stats(cache_ptr, "test cache", display_detailed_stats);
+ }
+
+ return;
+
+} /* row_major_scan_forward() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: row_major_scan_backward()
+ *
+ * Purpose: Do a sequence of inserts, protects, unprotects, renames,
+ * destroys while scanning backwards through the set of
+ * entries. If pass is false on entry, do nothing.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/12/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+row_major_scan_backward(H5C_t * cache_ptr,
+ int32_t lag,
+ hbool_t verbose,
+ hbool_t reset_stats,
+ hbool_t display_stats,
+ hbool_t display_detailed_stats,
+ hbool_t do_inserts,
+ hbool_t dirty_inserts,
+ hbool_t do_renames,
+ hbool_t rename_to_main_addr,
+ hbool_t do_destroys,
+ int dirty_destroys,
+ int dirty_unprotects)
+{
+ const char * fcn_name = "row_major_scan_backward";
+ int32_t type;
+ int32_t idx;
+
+ if ( verbose )
+ HDfprintf(stdout, "%s(): Entering.\n", fcn_name);
+
+ HDassert( lag > 5 );
+
+ type = NUMBER_OF_ENTRY_TYPES - 1;
+
+ if ( ( pass ) && ( reset_stats ) ) {
+
+ H5C_stats__reset(cache_ptr);
+ }
+
+ while ( ( pass ) && ( type >= 0 ) )
+ {
+ idx = max_indices[type] + lag;
+
+ while ( ( pass ) && ( idx >= -lag ) )
+ {
+ if ( ( pass ) && ( do_inserts ) && ( (idx - lag) >= 0 ) &&
+ ( (idx - lag) <= max_indices[type] ) &&
+ ( ((idx - lag) % 2) == 1 ) &&
+ ( ! entry_in_cache(cache_ptr, type, (idx - lag)) ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(i, %d, %d) ", type, (idx - lag));
+
+ insert_entry(cache_ptr, type, (idx - lag), dirty_inserts);
+ }
+
+
+ if ( ( pass ) && ( (idx - lag + 1) >= 0 ) &&
+ ( (idx - lag + 1) <= max_indices[type] ) &&
+ ( ( (idx - lag + 1) % 3 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(p, %d, %d) ", type, (idx - lag + 1));
+
+ protect_entry(cache_ptr, type, (idx - lag + 1));
+ }
+
+ if ( ( pass ) && ( (idx - lag + 2) >= 0 ) &&
+ ( (idx - lag + 2) <= max_indices[type] ) &&
+ ( ( (idx - lag + 2) % 3 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(u, %d, %d) ", type, (idx - lag + 2));
+
+ unprotect_entry(cache_ptr, type, idx-lag+2, NO_CHANGE, FALSE);
+ }
+
+
+ if ( ( pass ) && ( do_renames ) && ( (idx - lag + 2) >= 0 ) &&
+ ( (idx - lag + 2) <= max_indices[type] ) &&
+ ( ( (idx - lag + 2) % 3 ) == 0 ) ) {
+
+ rename_entry(cache_ptr, type, (idx - lag + 2),
+ rename_to_main_addr);
+ }
+
+
+ if ( ( pass ) && ( (idx - lag + 3) >= 0 ) &&
+ ( (idx - lag + 3) <= max_indices[type] ) &&
+ ( ( (idx - lag + 3) % 5 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(p, %d, %d) ", type, (idx - lag + 3));
+
+ protect_entry(cache_ptr, type, (idx - lag + 3));
+ }
+
+ if ( ( pass ) && ( (idx - lag + 5) >= 0 ) &&
+ ( (idx - lag + 5) <= max_indices[type] ) &&
+ ( ( (idx - lag + 5) % 5 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(u, %d, %d) ", type, (idx - lag + 5));
+
+ unprotect_entry(cache_ptr, type, idx-lag+5, NO_CHANGE, FALSE);
+ }
+
+ if ( ( pass ) && ( idx >= 0 ) && ( idx <= max_indices[type] ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(p, %d, %d) ", type, idx);
+
+ protect_entry(cache_ptr, type, idx);
+ }
+
+
+ if ( ( pass ) && ( (idx + lag - 2) >= 0 ) &&
+ ( (idx + lag - 2) <= max_indices[type] ) &&
+ ( ( (idx + lag - 2) % 7 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(u, %d, %d) ", type, (idx + lag - 2));
+
+ unprotect_entry(cache_ptr, type, idx+lag-2, NO_CHANGE, FALSE);
+ }
+
+ if ( ( pass ) && ( (idx + lag - 1) >= 0 ) &&
+ ( (idx + lag - 1) <= max_indices[type] ) &&
+ ( ( (idx + lag - 1) % 7 ) == 0 ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(p, %d, %d) ", type, (idx + lag - 1));
+
+ protect_entry(cache_ptr, type, (idx + lag - 1));
+ }
+
+
+ if ( do_destroys ) {
+
+ if ( ( pass ) && ( (idx + lag) >= 0 ) &&
+ ( ( idx + lag) <= max_indices[type] ) ) {
+
+ switch ( (idx + lag) %4 ) {
+
+ case 0:
+ if ( (entries[type])[idx+lag].is_dirty ) {
+
+ unprotect_entry(cache_ptr, type, idx + lag,
+ NO_CHANGE, FALSE);
+ } else {
+
+ unprotect_entry(cache_ptr, type, idx + lag,
+ dirty_unprotects, FALSE);
+ }
+ break;
+
+ case 1: /* we just did an insert */
+ unprotect_entry(cache_ptr, type, idx + lag,
+ NO_CHANGE, FALSE);
+ break;
+
+ case 2:
+ if ( (entries[type])[idx + lag].is_dirty ) {
+
+ unprotect_entry(cache_ptr, type, idx + lag,
+ NO_CHANGE, TRUE);
+ } else {
+
+ unprotect_entry(cache_ptr, type, idx + lag,
+ dirty_destroys, TRUE);
+ }
+ break;
+
+ case 3: /* we just did an insrt */
+ unprotect_entry(cache_ptr, type, idx + lag,
+ NO_CHANGE, TRUE);
+ break;
+
+ default:
+ HDassert(0); /* this can't happen... */
+ break;
+ }
+ }
+ } else {
+
+ if ( ( pass ) && ( (idx + lag) >= 0 ) &&
+ ( ( idx + lag) <= max_indices[type] ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(u, %d, %d) ", type, (idx - lag));
+
+ unprotect_entry(cache_ptr, type, idx + lag,
+ dirty_unprotects, FALSE);
+ }
+ }
+
+ if ( verbose )
+ HDfprintf(stdout, "\n");
+
+ idx--;
+ }
+ type--;
+ }
+
+ if ( ( pass ) && ( display_stats ) ) {
+
+ H5C_stats(cache_ptr, "test cache", display_detailed_stats);
+ }
+
+ return;
+
+} /* row_major_scan_backward() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: col_major_scan_forward()
+ *
+ * Purpose: Do a sequence of inserts, protects, and unprotects
+ * while scanning through the set of entries. If
+ * pass is false on entry, do nothing.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/23/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+col_major_scan_forward(H5C_t * cache_ptr,
+ int32_t lag,
+ hbool_t verbose,
+ hbool_t reset_stats,
+ hbool_t display_stats,
+ hbool_t display_detailed_stats,
+ hbool_t do_inserts,
+ hbool_t dirty_inserts,
+ int dirty_unprotects)
+{
+ const char * fcn_name = "col_major_scan_forward()";
+ int32_t type;
+ int32_t idx;
+
+ if ( verbose )
+ HDfprintf(stdout, "%s: entering.\n", fcn_name);
+
+ HDassert( lag > 5 );
+
+ type = 0;
+
+ if ( ( pass ) && ( reset_stats ) ) {
+
+ H5C_stats__reset(cache_ptr);
+ }
+
+ idx = -lag;
+
+ while ( ( pass ) && ( (idx - lag) <= MAX_ENTRIES ) )
+ {
+ type = 0;
+
+ while ( ( pass ) && ( type < NUMBER_OF_ENTRY_TYPES ) )
+ {
+ if ( ( pass ) && ( do_inserts ) && ( (idx + lag) >= 0 ) &&
+ ( (idx + lag) <= max_indices[type] ) &&
+ ( ((idx + lag) % 3) == 0 ) &&
+ ( ! entry_in_cache(cache_ptr, type, (idx + lag)) ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(i, %d, %d) ", type, (idx + lag));
+
+ insert_entry(cache_ptr, type, (idx + lag), dirty_inserts);
+ }
+
+ if ( ( pass ) && ( idx >= 0 ) && ( idx <= max_indices[type] ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(p, %d, %d) ", type, idx);
+
+ protect_entry(cache_ptr, type, idx);
+ }
+
+ if ( ( pass ) && ( (idx - lag) >= 0 ) &&
+ ( (idx - lag) <= max_indices[type] ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(u, %d, %d) ", type, (idx - lag));
+
+ unprotect_entry(cache_ptr, type, idx - lag,
+ dirty_unprotects, FALSE);
+ }
+
+ if ( verbose )
+ HDfprintf(stdout, "\n");
+
+ type++;
+ }
+
+ idx++;
+ }
+
+ if ( ( pass ) && ( display_stats ) ) {
+
+ H5C_stats(cache_ptr, "test cache", display_detailed_stats);
+ }
+
+ return;
+
+} /* col_major_scan_forward() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: col_major_scan_backward()
+ *
+ * Purpose: Do a sequence of inserts, protects, and unprotects
+ * while scanning backwards through the set of
+ * entries. If pass is false on entry, do nothing.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/23/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+col_major_scan_backward(H5C_t * cache_ptr,
+ int32_t lag,
+ hbool_t verbose,
+ hbool_t reset_stats,
+ hbool_t display_stats,
+ hbool_t display_detailed_stats,
+ hbool_t do_inserts,
+ hbool_t dirty_inserts,
+ int dirty_unprotects)
+{
+ const char * fcn_name = "col_major_scan_backward()";
+ int mile_stone = 1;
+ int32_t type;
+ int32_t idx;
+
+ if ( verbose )
+ HDfprintf(stdout, "%s: entering.\n", fcn_name);
+
+ HDassert( lag > 5 );
+
+ if ( ( pass ) && ( reset_stats ) ) {
+
+ H5C_stats__reset(cache_ptr);
+ }
+
+ idx = MAX_ENTRIES + lag;
+
+ if ( verbose ) /* 1 */
+ HDfprintf(stdout, "%s: point %d.\n", fcn_name, mile_stone++);
+
+
+ while ( ( pass ) && ( (idx + lag) >= 0 ) )
+ {
+ type = NUMBER_OF_ENTRY_TYPES - 1;
+
+ while ( ( pass ) && ( type >= 0 ) )
+ {
+ if ( ( pass ) && ( do_inserts) && ( (idx - lag) >= 0 ) &&
+ ( (idx - lag) <= max_indices[type] ) &&
+ ( ((idx - lag) % 3) == 0 ) &&
+ ( ! entry_in_cache(cache_ptr, type, (idx - lag)) ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(i, %d, %d) ", type, (idx - lag));
+
+ insert_entry(cache_ptr, type, (idx - lag), dirty_inserts);
+ }
+
+ if ( ( pass ) && ( idx >= 0 ) && ( idx <= max_indices[type] ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(p, %d, %d) ", type, idx);
+
+ protect_entry(cache_ptr, type, idx);
+ }
+
+ if ( ( pass ) && ( (idx + lag) >= 0 ) &&
+ ( (idx + lag) <= max_indices[type] ) ) {
+
+ if ( verbose )
+ HDfprintf(stdout, "(u, %d, %d) ", type, (idx + lag));
+
+ unprotect_entry(cache_ptr, type, idx + lag,
+ dirty_unprotects, FALSE);
+ }
+
+ if ( verbose )
+ HDfprintf(stdout, "\n");
+
+ type--;
+ }
+
+ idx--;
+ }
+
+ if ( verbose ) /* 2 */
+ HDfprintf(stdout, "%s: point %d.\n", fcn_name, mile_stone++);
+
+ if ( ( pass ) && ( display_stats ) ) {
+
+ H5C_stats(cache_ptr, "test cache", display_detailed_stats);
+ }
+
+ if ( verbose )
+ HDfprintf(stdout, "%s: exiting.\n", fcn_name);
+
+ return;
+
+} /* col_major_scan_backward() */
+
+
+/**************************************************************************/
+/**************************************************************************/
+/********************************* tests: *********************************/
+/**************************************************************************/
+/**************************************************************************/
+
+/*-------------------------------------------------------------------------
+ * Function: smoke_check_1()
+ *
+ * Purpose: A basic functional test, inserts, destroys, and renames in
+ * the mix, along with repeated protects and unprotects.
+ * All entries are marked as clean.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/16/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+smoke_check_1(void)
+{
+ const char * fcn_name = "smoke_check_1";
+ hbool_t show_progress = FALSE;
+ hbool_t dirty_inserts = FALSE;
+ int dirty_unprotects = FALSE;
+ int dirty_destroys = FALSE;
+ hbool_t display_stats = FALSE;
+ int32_t lag = 10;
+ int mile_stone = 1;
+ H5C_t * cache_ptr = NULL;
+
+ TESTING("smoke check #1 -- all clean, ins, dest, ren, 4/2 MB cache");
+
+ pass = TRUE;
+
+ if ( show_progress ) /* 1 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ reset_entries();
+
+ if ( show_progress ) /* 2 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ cache_ptr = setup_cache((size_t)(4 * 1024 * 1024),
+ (size_t)(2 * 1024 * 1024));
+
+ if ( show_progress ) /* 3 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ FALSE,
+ /* do_destroys */ TRUE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 4 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_backward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ FALSE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ TRUE,
+ /* do_destroys */ FALSE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 5 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ FALSE,
+ /* do_destroys */ FALSE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 6 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ /* flush and destroy all entries in the cache: */
+
+ flush_cache(/* cache_ptr */ cache_ptr,
+ /* destroy_entries */ TRUE,
+ /* dump_stats */ FALSE,
+ /* dump_detailed_stats */ FALSE);
+
+ if ( show_progress ) /* 7 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ col_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 8 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ /* flush all entries in the cache: */
+
+ flush_cache(/* cache_ptr */ cache_ptr,
+ /* destroy_entries */ FALSE,
+ /* dump_stats */ FALSE,
+ /* dump_detailed_stats */ FALSE);
+
+ if ( show_progress ) /* 9 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ col_major_scan_backward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 10 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ takedown_cache(cache_ptr, display_stats, TRUE);
+
+ if ( show_progress ) /* 11 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ verify_clean();
+ verify_unprotected();
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s(): failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+} /* smoke_check_1() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: smoke_check_2()
+ *
+ * Purpose: A basic functional test, with inserts, destroys, and
+ * renames in the mix, along with some repeated protects
+ * and unprotects. About half the entries are marked as
+ * dirty.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/24/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+smoke_check_2(void)
+{
+ const char * fcn_name = "smoke_check_2";
+ hbool_t show_progress = FALSE;
+ hbool_t dirty_inserts = TRUE;
+ int dirty_unprotects = TRUE;
+ int dirty_destroys = TRUE;
+ hbool_t display_stats = FALSE;
+ int32_t lag = 10;
+ int mile_stone = 1;
+ H5C_t * cache_ptr = NULL;
+
+ TESTING("smoke check #2 -- ~1/2 dirty, ins, dest, ren, 4/2 MB cache");
+
+ pass = TRUE;
+
+ if ( show_progress ) /* 1 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ reset_entries();
+
+ if ( show_progress ) /* 2 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ cache_ptr = setup_cache((size_t)(4 * 1024 * 1024),
+ (size_t)(2 * 1024 * 1024));
+
+ if ( show_progress ) /* 3 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ FALSE,
+ /* do_destroys */ TRUE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 4 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_backward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ FALSE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ TRUE,
+ /* do_destroys */ FALSE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 5 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ FALSE,
+ /* do_destroys */ FALSE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 6 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ /* flush and destroy all entries in the cache: */
+
+ flush_cache(/* cache_ptr */ cache_ptr,
+ /* destroy_entries */ TRUE,
+ /* dump_stats */ FALSE,
+ /* dump_detailed_stats */ FALSE);
+
+ if ( show_progress ) /* 7 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ col_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 8 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ /* flush all entries in the cache: */
+
+ flush_cache(/* cache_ptr */ cache_ptr,
+ /* destroy_entries */ FALSE,
+ /* dump_stats */ FALSE,
+ /* dump_detailed_stats */ FALSE);
+
+ if ( show_progress ) /* 9 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ col_major_scan_backward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 10 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ takedown_cache(cache_ptr, display_stats, TRUE);
+
+ if ( show_progress ) /* 11 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ verify_clean();
+ verify_unprotected();
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s(): failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+} /* smoke_check_2() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: smoke_check_3()
+ *
+ * Purpose: A basic functional test on a tiny cache, with inserts,
+ * destroys, and renames in the mix, along with repeated
+ * protects and unprotects. All entries are marked as clean.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/16/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+smoke_check_3(void)
+{
+ const char * fcn_name = "smoke_check_3";
+ hbool_t show_progress = FALSE;
+ hbool_t dirty_inserts = FALSE;
+ int dirty_unprotects = FALSE;
+ int dirty_destroys = FALSE;
+ hbool_t display_stats = FALSE;
+ int32_t lag = 10;
+ int mile_stone = 1;
+ H5C_t * cache_ptr = NULL;
+
+ TESTING("smoke check #3 -- all clean, ins, dest, ren, 2/1 KB cache");
+
+ pass = TRUE;
+
+ if ( show_progress ) /* 1 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ reset_entries();
+
+ if ( show_progress ) /* 2 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ cache_ptr = setup_cache((size_t)(2 * 1024),
+ (size_t)(1 * 1024));
+
+ if ( show_progress ) /* 3 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ FALSE,
+ /* do_destroys */ TRUE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 4 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_backward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ FALSE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ TRUE,
+ /* do_destroys */ FALSE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 5 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ FALSE,
+ /* do_destroys */ FALSE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 6 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ /* flush and destroy all entries in the cache: */
+
+ flush_cache(/* cache_ptr */ cache_ptr,
+ /* destroy_entries */ TRUE,
+ /* dump_stats */ FALSE,
+ /* dump_detailed_stats */ FALSE);
+
+ if ( show_progress ) /* 7 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ col_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 8 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ /* flush all entries in the cache: */
+
+ flush_cache(/* cache_ptr */ cache_ptr,
+ /* destroy_entries */ FALSE,
+ /* dump_stats */ FALSE,
+ /* dump_detailed_stats */ FALSE);
+
+ if ( show_progress ) /* 9 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ col_major_scan_backward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 10 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ takedown_cache(cache_ptr, display_stats, TRUE);
+
+ if ( show_progress ) /* 11 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ verify_clean();
+ verify_unprotected();
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s(): failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+} /* smoke_check_3() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: smoke_check_4()
+ *
+ * Purpose: A basic functional test on a tiny cache, with inserts,
+ * destroys, and renames in the mix, along with repeated
+ * protects and unprotects. About half the entries are
+ * marked as dirty.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/24/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+smoke_check_4(void)
+{
+ const char * fcn_name = "smoke_check_4";
+ hbool_t show_progress = FALSE;
+ hbool_t dirty_inserts = TRUE;
+ int dirty_unprotects = TRUE;
+ int dirty_destroys = TRUE;
+ hbool_t display_stats = FALSE;
+ int32_t lag = 10;
+ int mile_stone = 1;
+ H5C_t * cache_ptr = NULL;
+
+ TESTING("smoke check #4 -- ~1/2 dirty, ins, dest, ren, 2/1 KB cache");
+
+ pass = TRUE;
+
+ if ( show_progress ) /* 1 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ reset_entries();
+
+ if ( show_progress ) /* 2 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ cache_ptr = setup_cache((size_t)(2 * 1024),
+ (size_t)(1 * 1024));
+
+ if ( show_progress ) /* 3 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ FALSE,
+ /* do_destroys */ TRUE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 4 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_backward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ FALSE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ TRUE,
+ /* do_destroys */ FALSE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 5 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ FALSE,
+ /* do_destroys */ FALSE,
+ /* dirty_destroys */ dirty_destroys,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 6 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ /* flush and destroy all entries in the cache: */
+
+ flush_cache(/* cache_ptr */ cache_ptr,
+ /* destroy_entries */ TRUE,
+ /* dump_stats */ FALSE,
+ /* dump_detailed_stats */ FALSE);
+
+ if ( show_progress ) /* 7 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ col_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 8 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ /* flush all entries in the cache: */
+
+ flush_cache(/* cache_ptr */ cache_ptr,
+ /* destroy_entries */ FALSE,
+ /* dump_stats */ FALSE,
+ /* dump_detailed_stats */ FALSE);
+
+ if ( show_progress ) /* 9 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ col_major_scan_backward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ dirty_inserts,
+ /* dirty_unprotects */ dirty_unprotects);
+
+ if ( show_progress ) /* 10 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ takedown_cache(cache_ptr, display_stats, TRUE);
+
+ if ( show_progress ) /* 11 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ verify_clean();
+ verify_unprotected();
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s(): failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+} /* smoke_check_4() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: write_permitted_check()
+ *
+ * Purpose: A basic test of the write permitted function. In essence,
+ * we load the cache up with dirty entryies, set
+ * write_permitted to FALSE, and then protect a bunch of
+ * entries. If there are any writes while write_permitted is
+ * FALSE, the test will fail.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/24/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+write_permitted_check(void)
+{
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+ const char * fcn_name = "write_permitted_check";
+ hbool_t show_progress = FALSE;
+ hbool_t display_stats = FALSE;
+ int32_t lag = 10;
+ int mile_stone = 1;
+ H5C_t * cache_ptr = NULL;
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+ TESTING("write permitted check -- 1/0 MB cache");
+
+#if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
+
+ pass = TRUE;
+
+ if ( show_progress ) /* 1 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ reset_entries();
+
+ if ( show_progress ) /* 2 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ cache_ptr = setup_cache((size_t)(1 * 1024 * 1024),
+ (size_t)(0));
+
+ if ( show_progress ) /* 3 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ row_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ TRUE,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ FALSE,
+ /* do_destroys */ TRUE,
+ /* dirty_destroys */ TRUE,
+ /* dirty_unprotects */ TRUE);
+
+ if ( show_progress ) /* 4 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ write_permitted = FALSE;
+
+ row_major_scan_backward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ FALSE,
+ /* dirty_inserts */ FALSE,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ TRUE,
+ /* do_destroys */ FALSE,
+ /* dirty_destroys */ FALSE,
+ /* dirty_unprotects */ NO_CHANGE);
+
+ if ( show_progress ) /* 5 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ write_permitted = TRUE;
+
+ row_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ TRUE,
+ /* do_renames */ TRUE,
+ /* rename_to_main_addr */ FALSE,
+ /* do_destroys */ FALSE,
+ /* dirty_destroys */ TRUE,
+ /* dirty_unprotects */ TRUE);
+
+ if ( show_progress ) /* 6 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ /* flush and destroy all entries in the cache: */
+
+ flush_cache(/* cache_ptr */ cache_ptr,
+ /* destroy_entries */ TRUE,
+ /* dump_stats */ FALSE,
+ /* dump_detailed_stats */ FALSE);
+
+ if ( show_progress ) /* 7 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ col_major_scan_forward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ TRUE,
+ /* dirty_inserts */ TRUE,
+ /* dirty_unprotects */ TRUE);
+
+ if ( show_progress ) /* 8 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ write_permitted = FALSE;
+
+ col_major_scan_backward(/* cache_ptr */ cache_ptr,
+ /* lag */ lag,
+ /* verbose */ FALSE,
+ /* reset_stats */ TRUE,
+ /* display_stats */ display_stats,
+ /* display_detailed_stats */ TRUE,
+ /* do_inserts */ FALSE,
+ /* dirty_inserts */ FALSE,
+ /* dirty_unprotects */ NO_CHANGE);
+
+ write_permitted = TRUE;
+
+ if ( show_progress ) /* 9 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ takedown_cache(cache_ptr, display_stats, TRUE);
+
+ if ( show_progress ) /* 10 */
+ HDfprintf(stdout, "%s() - %0d -- pass = %d\n",
+ fcn_name, mile_stone++, (int)pass);
+
+ verify_clean();
+ verify_unprotected();
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s(): failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+#else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+ SKIPPED();
+
+ HDfprintf(stdout, " Clean and dirty LRU lists disabled.\n");
+
+#endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
+
+} /* write_permitted_check() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: check_flush_protected_err()
+ *
+ * Purpose: Verify that an attempt to flush the cache when it contains
+ * a protected entry will generate an error.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/24/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+check_flush_protected_err(void)
+{
+ const char * fcn_name = "check_flush_protected_err";
+ H5C_t * cache_ptr = NULL;
+
+ TESTING("flush cache with protected entry error");
+
+ pass = TRUE;
+
+ /* allocate a cache, protect an entry, and try to flush. This
+ * should fail. Unprotect the entry and flush again -- should
+ * succeed.
+ */
+
+ if ( pass ) {
+
+ reset_entries();
+
+ cache_ptr = setup_cache((size_t)(2 * 1024),
+ (size_t)(1 * 1024));
+
+ protect_entry(cache_ptr, 0, 0);
+
+ if ( H5C_flush_cache(NULL, -1, -1, cache_ptr, 0) >= 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "flush succeeded on cache with protected entry.\n";
+
+ } else {
+
+ unprotect_entry(cache_ptr, 0, 0, TRUE, FALSE);
+
+ if ( H5C_flush_cache(NULL, -1, -1, cache_ptr, 0) < 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "flush failed after unprotect.\n";
+
+ } else {
+
+ takedown_cache(cache_ptr, FALSE, FALSE);
+ }
+ }
+ }
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s(): failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+} /* check_flush_protected_err() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: check_destroy_protected_err()
+ *
+ * Purpose: Verify that an attempt to destroy the cache when it contains
+ * a protected entry will generate an error.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/24/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+check_destroy_protected_err(void)
+{
+ const char * fcn_name = "check_destroy_protected_err";
+ H5C_t * cache_ptr = NULL;
+
+ TESTING("destroy cache with protected entry error");
+
+ pass = TRUE;
+
+ /* allocate a cache, protect an entry, and try to flush. This
+ * should fail. Unprotect the entry and flush again -- should
+ * succeed.
+ */
+
+ if ( pass ) {
+
+ reset_entries();
+
+ cache_ptr = setup_cache((size_t)(2 * 1024),
+ (size_t)(1 * 1024));
+
+ protect_entry(cache_ptr, 0, 0);
+
+ if ( H5C_dest(NULL, -1, -1, cache_ptr) >= 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "destroy succeeded on cache with protected entry.\n";
+
+ } else {
+
+ unprotect_entry(cache_ptr, 0, 0, TRUE, FALSE);
+
+ if ( H5C_dest(NULL, -1, -1, cache_ptr) < 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "destroy failed after unprotect.\n";
+
+ }
+ }
+ }
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s(): failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+} /* check_destroy_protected_err() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: check_duplicate_insert_err()
+ *
+ * Purpose: Verify that an attempt to insert and entry that is
+ * alread in the cache will generate an error.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/24/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+check_duplicate_insert_err(void)
+{
+ const char * fcn_name = "check_duplicate_insert_err";
+ herr_t result;
+ H5C_t * cache_ptr = NULL;
+ test_entry_t * base_addr;
+ test_entry_t * entry_ptr;
+
+ TESTING("duplicate entry insertion error");
+
+ pass = TRUE;
+
+ /* allocate a cache, protect an entry, and then try to insert
+ * the entry again. This should fail. Unprotect the entry and
+ * destroy the cache -- should succeed.
+ */
+
+ if ( pass ) {
+
+ reset_entries();
+
+ cache_ptr = setup_cache((size_t)(2 * 1024),
+ (size_t)(1 * 1024));
+
+ protect_entry(cache_ptr, 0, 0);
+
+ if ( pass ) {
+
+ base_addr = entries[0];
+ entry_ptr = &(base_addr[0]);
+
+ result = H5C_insert_entry(NULL, -1, -1, cache_ptr,
+ &(types[0]), entry_ptr->addr,
+ (void *)entry_ptr);
+
+ if ( result >= 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "insert of duplicate entry succeeded.\n";
+
+ } else {
+
+ unprotect_entry(cache_ptr, 0, 0, TRUE, FALSE);
+
+ takedown_cache(cache_ptr, FALSE, FALSE);
+ }
+ }
+ }
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s(): failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+} /* check_duplicate_insert_err() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: check_rename_err()
+ *
+ * Purpose: Verify that an attempt to rename an entry to the address
+ * of an existing entry will generate an error.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/24/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+check_rename_err(void)
+{
+ const char * fcn_name = "check_rename_err()";
+ herr_t result;
+ H5C_t * cache_ptr = NULL;
+ test_entry_t * entry_0_0_ptr;
+ test_entry_t * entry_0_1_ptr;
+ test_entry_t * entry_1_0_ptr;
+
+ TESTING("rename to existing entry errors");
+
+ pass = TRUE;
+
+ /* allocate a cache, and insert several entries. Try to rename
+ * entries to other entries resident in the cache. This should
+ * fail. Destroy the cache -- should succeed.
+ */
+
+ if ( pass ) {
+
+ reset_entries();
+
+ cache_ptr = setup_cache((size_t)(2 * 1024),
+ (size_t)(1 * 1024));
+
+ insert_entry(cache_ptr, 0, 0, TRUE);
+ insert_entry(cache_ptr, 0, 1, TRUE);
+ insert_entry(cache_ptr, 1, 0, TRUE);
+
+ entry_0_0_ptr = &((entries[0])[0]);
+ entry_0_1_ptr = &((entries[0])[1]);
+ entry_1_0_ptr = &((entries[1])[0]);
+ }
+
+ if ( pass ) {
+
+ result = H5C_rename_entry(NULL, cache_ptr, &(types[0]),
+ entry_0_0_ptr->addr, entry_0_1_ptr->addr);
+
+ if ( result >= 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "rename to addr of same type succeeded.\n";
+ }
+ }
+
+ if ( pass ) {
+
+ result = H5C_rename_entry(NULL, cache_ptr, &(types[0]),
+ entry_0_0_ptr->addr, entry_1_0_ptr->addr);
+
+ if ( result >= 0 ) {
+
+ pass = FALSE;
+ failure_mssg = "rename to addr of different type succeeded.\n";
+ }
+ }
+
+ if ( pass ) {
+
+ takedown_cache(cache_ptr, FALSE, FALSE);
+ }
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+} /* check_rename_err() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: check_double_protect_err()
+ *
+ * Purpose: Verify that an attempt to protect an entry that is already
+ * protected will generate an error.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/24/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+check_double_protect_err(void)
+{
+ const char * fcn_name = "check_double_protect_err()";
+ H5C_t * cache_ptr = NULL;
+ test_entry_t * entry_ptr;
+ H5C_cache_entry_t * cache_entry_ptr;
+
+ TESTING("protect a protected entry error");
+
+ pass = TRUE;
+
+ /* allocate a cache, protect an entry, and then try to protect
+ * the entry again. This should fail. Unprotect the entry and
+ * destroy the cache -- should succeed.
+ */
+
+ if ( pass ) {
+
+ reset_entries();
+
+ cache_ptr = setup_cache((size_t)(2 * 1024),
+ (size_t)(1 * 1024));
+
+ protect_entry(cache_ptr, 0, 0);
+
+ entry_ptr = &((entries[0])[0]);
+ }
+
+ if ( pass ) {
+
+ cache_entry_ptr = H5C_protect(NULL, -1, -1, cache_ptr, &(types[0]),
+ entry_ptr->addr, NULL, NULL);
+
+ if ( cache_entry_ptr != NULL ) {
+
+ pass = FALSE;
+ failure_mssg = "attempt to protect a protected entry succeeded.\n";
+ }
+ }
+
+ if ( pass ) {
+
+ unprotect_entry(cache_ptr, 0, 0, FALSE, FALSE);
+ }
+
+ if ( pass ) {
+
+ takedown_cache(cache_ptr, FALSE, FALSE);
+ }
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+} /* check_double_protect_err() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: check_double_unprotect_err()
+ *
+ * Purpose: Verify that an attempt to unprotect an entry that is already
+ * unprotected will generate an error.
+ *
+ * Return: void
+ *
+ * Programmer: John Mainzer
+ * 6/24/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+check_double_unprotect_err(void)
+{
+ const char * fcn_name = "check_double_unprotect_err()";
+ herr_t result;
+ H5C_t * cache_ptr = NULL;
+ test_entry_t * entry_ptr;
+
+ TESTING("unprotect an unprotected entry error");
+
+ pass = TRUE;
+
+ /* allocate a cache, protect an entry, unprotect it, and then try to
+ * unprotect the entry again. This should fail. Destroy the cache
+ * -- should succeed.
+ */
+
+ if ( pass ) {
+
+ reset_entries();
+
+ cache_ptr = setup_cache((size_t)(2 * 1024),
+ (size_t)(1 * 1024));
+
+ protect_entry(cache_ptr, 0, 0);
+
+ unprotect_entry(cache_ptr, 0, 0, FALSE, FALSE);
+
+ entry_ptr = &((entries[0])[0]);
+ }
+
+ if ( pass ) {
+
+ result = H5C_unprotect(NULL, -1, -1, cache_ptr, &(types[0]),
+ entry_ptr->addr, (void *)entry_ptr, FALSE);
+
+ if ( result > 0 ) {
+
+ pass = FALSE;
+ failure_mssg =
+ "attempt to unprotect an unprotected entry succeeded.\n";
+ }
+ }
+
+ if ( pass ) {
+
+ takedown_cache(cache_ptr, FALSE, FALSE);
+ }
+
+ if ( pass ) { PASSED(); } else { H5_FAILED(); }
+
+ if ( ! pass )
+ HDfprintf(stdout, "%s: failure_mssg = \"%s\".\n",
+ fcn_name, failure_mssg);
+
+} /* check_double_unprotect_err() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: Run tests on the cache code contained in H5C.c
+ *
+ * Return: Success:
+ *
+ * Failure:
+ *
+ * Programmer: John Mainzer
+ * 6/24/04
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main(void)
+{
+ H5open();
+
+ smoke_check_1();
+ smoke_check_2();
+ smoke_check_3();
+ smoke_check_4();
+ write_permitted_check();
+ check_flush_protected_err();
+ check_destroy_protected_err();
+ check_duplicate_insert_err();
+ check_rename_err();
+ check_double_protect_err();
+ check_double_unprotect_err();
+
+ return(0);
+
+} /* main() */
diff --git a/tools/h5jam/Dependencies b/tools/h5jam/Dependencies
new file mode 100644
index 0000000..be3a92b
--- /dev/null
+++ b/tools/h5jam/Dependencies
@@ -0,0 +1,83 @@
+## This file is machine generated on GNU systems.
+## Only temporary changes may be made here.
+
+h5jam.lo: \
+ $(top_srcdir)/tools/h5jam/h5jam.c \
+ $(top_srcdir)/src/hdf5.h \
+ $(top_srcdir)/src/H5public.h \
+ $(top_builddir)/src/H5pubconf.h \
+ $(top_srcdir)/src/H5api_adpt.h \
+ $(top_srcdir)/src/H5Apublic.h \
+ $(top_srcdir)/src/H5Ipublic.h \
+ $(top_srcdir)/src/H5ACpublic.h \
+ $(top_srcdir)/src/H5Bpublic.h \
+ $(top_srcdir)/src/H5Dpublic.h \
+ $(top_srcdir)/src/H5Epublic.h \
+ $(top_srcdir)/src/H5Epubgen.h \
+ $(top_srcdir)/src/H5Fpublic.h \
+ $(top_srcdir)/src/H5FDpublic.h \
+ $(top_srcdir)/src/H5FPpublic.h \
+ $(top_srcdir)/src/H5Gpublic.h \
+ $(top_srcdir)/src/H5Opublic.h \
+ $(top_srcdir)/src/H5HGpublic.h \
+ $(top_srcdir)/src/H5HLpublic.h \
+ $(top_srcdir)/src/H5MMpublic.h \
+ $(top_srcdir)/src/H5Ppublic.h \
+ $(top_srcdir)/src/H5Tpublic.h \
+ $(top_srcdir)/src/H5Zpublic.h \
+ $(top_srcdir)/src/H5Rpublic.h \
+ $(top_srcdir)/src/H5Spublic.h \
+ $(top_srcdir)/src/H5FDcore.h \
+ $(top_srcdir)/src/H5FDfamily.h \
+ $(top_srcdir)/src/H5FDgass.h \
+ $(top_srcdir)/src/H5FDlog.h \
+ $(top_srcdir)/src/H5FDmpi.h \
+ $(top_srcdir)/src/H5FDfphdf5.h \
+ $(top_srcdir)/src/H5FDmpio.h \
+ $(top_srcdir)/src/H5FDmpiposix.h \
+ $(top_srcdir)/src/H5FDmulti.h \
+ $(top_srcdir)/src/H5FDsec2.h \
+ $(top_srcdir)/src/H5FDsrb.h \
+ $(top_srcdir)/src/H5FDstdio.h \
+ $(top_srcdir)/src/H5FDstream.h \
+ $(top_srcdir)/tools/lib/h5tools_utils.h
+h5unjam.lo: \
+ $(top_srcdir)/tools/h5jam/h5unjam.c \
+ $(top_srcdir)/src/hdf5.h \
+ $(top_srcdir)/src/H5public.h \
+ $(top_builddir)/src/H5pubconf.h \
+ $(top_srcdir)/src/H5api_adpt.h \
+ $(top_srcdir)/src/H5Apublic.h \
+ $(top_srcdir)/src/H5Ipublic.h \
+ $(top_srcdir)/src/H5ACpublic.h \
+ $(top_srcdir)/src/H5Bpublic.h \
+ $(top_srcdir)/src/H5Dpublic.h \
+ $(top_srcdir)/src/H5Epublic.h \
+ $(top_srcdir)/src/H5Epubgen.h \
+ $(top_srcdir)/src/H5Fpublic.h \
+ $(top_srcdir)/src/H5FDpublic.h \
+ $(top_srcdir)/src/H5FPpublic.h \
+ $(top_srcdir)/src/H5Gpublic.h \
+ $(top_srcdir)/src/H5Opublic.h \
+ $(top_srcdir)/src/H5HGpublic.h \
+ $(top_srcdir)/src/H5HLpublic.h \
+ $(top_srcdir)/src/H5MMpublic.h \
+ $(top_srcdir)/src/H5Ppublic.h \
+ $(top_srcdir)/src/H5Tpublic.h \
+ $(top_srcdir)/src/H5Zpublic.h \
+ $(top_srcdir)/src/H5Rpublic.h \
+ $(top_srcdir)/src/H5Spublic.h \
+ $(top_srcdir)/src/H5FDcore.h \
+ $(top_srcdir)/src/H5FDfamily.h \
+ $(top_srcdir)/src/H5FDgass.h \
+ $(top_srcdir)/src/H5FDlog.h \
+ $(top_srcdir)/src/H5FDmpi.h \
+ $(top_srcdir)/src/H5FDfphdf5.h \
+ $(top_srcdir)/src/H5FDmpio.h \
+ $(top_srcdir)/src/H5FDmpiposix.h \
+ $(top_srcdir)/src/H5FDmulti.h \
+ $(top_srcdir)/src/H5FDsec2.h \
+ $(top_srcdir)/src/H5FDsrb.h \
+ $(top_srcdir)/src/H5FDstdio.h \
+ $(top_srcdir)/src/H5FDstream.h \
+ $(top_srcdir)/tools/lib/h5tools_utils.h
diff --git a/tools/h5jam/Makefile.in b/tools/h5jam/Makefile.in
new file mode 100644
index 0000000..ccb2018
--- /dev/null
+++ b/tools/h5jam/Makefile.in
@@ -0,0 +1,96 @@
+## HDF5 Library Makefile(.in)
+##
+## Copyright by the Board of Trustees of the University of Illinois.
+## All rights reserved.
+##
+## This file is part of HDF5. The full HDF5 copyright notice, including
+## terms governing use, modification, and redistribution, is contained in
+## the files COPYING and Copyright.html. COPYING can be found at the root
+## of the source code distribution tree; Copyright.html can be found at the
+## root level of an installed copy of the electronic HDF5 document set and
+## is linked from the top-level documents page. It can also be found at
+## http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have
+## access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu.
+##
+top_srcdir=@top_srcdir@
+top_builddir=../..
+srcdir=@srcdir@
+@COMMENCE@
+
+## Add include directory to the C preprocessor flags, add -lh5tools and
+## -lhdf5 to the list of libraries.
+##
+CPPFLAGS=-I. -I$(srcdir) -I$(top_builddir)/src -I$(top_srcdir)/src \
+ -I$(top_srcdir)/tools/lib @CPPFLAGS@
+
+## Test programs and scripts.
+##
+TEST_PROGS=
+TEST_SCRIPTS=./testh5jam.sh
+
+OTHER_PROGS=tellub h5jamgentest getub
+## These are our main targets: library and tools.
+##
+LIBTOOLS=../lib/libh5tools.la
+LIBHDF5=$(top_builddir)/src/libhdf5.la
+
+PUB_PROGS=h5jam h5unjam
+
+PROGS=$(PUB_PROGS) $(TEST_PROGS) $(OTHER_PROGS)
+
+## Source and object files for the library; do not install
+##
+LIB_SRC=
+LIB_OBJ=$(LIB_SRC:.c=.lo)
+PUB_LIB=
+
+## Temporary files. *.h5 are generated by jamgentest. They should
+## copied to the testfiles/ directory if update is required.
+MOSTLYCLEAN=*.h5 *.txt
+CLEAN=
+DISTCLEAN=testh5jam.sh
+
+#### FIX AFTER HERE
+
+## Source and object files for programs...
+##
+PROG_SRC=h5jam.c h5unjam.c
+PROG_OBJ=$(PROG_SRC:.c=.lo)
+
+PRIVATE_HDR=
+
+OTHER_SRC=tellub.c h5jamgentest.c getub.c
+OTHER_OBJ=$(OTHER_SRC:.c=.lo)
+
+## Source and object files for the tests (to be cleaned up)
+##
+TEST_SRC=
+TEST_OBJ=$(TEST_SRC:.c=.lo) $(OTHER_OBJ)
+
+## Programs have to be built before they can be tested!
+##
+check test _test: $(PROGS)
+
+## How to build the programs...They all depend on the hdf5 library and
+## the tools library compiled in this directory.
+##
+$(PROGS): $(LIBTOOLS) $(LIBHDF5)
+
+h5jam: h5jam.lo
+ @$(LT_LINK_EXE) $(CFLAGS) -o $@ h5jam.lo $(LIBTOOLS) $(LIBHDF5) $(LDFLAGS) $(LIBS)
+
+h5unjam: h5unjam.lo
+ @$(LT_LINK_EXE) $(CFLAGS) -o $@ h5unjam.lo $(LIBTOOLS) $(LIBHDF5) $(LDFLAGS) $(LIBS)
+
+h5jamgentest: h5jamgentest.lo
+ @$(LT_LINK_EXE) $(CFLAGS) -o $@ h5jamgentest.lo $(LIBTOOLS) $(LIBHDF5) $(LDFLAGS) $(LIBS)
+
+tellub: tellub.lo
+ @$(LT_LINK_EXE) $(CFLAGS) -o $@ tellub.lo $(LIBTOOLS) $(LIBHDF5) $(LDFLAGS) $(LIBS)
+
+getub: getub.lo
+ @$(LT_LINK_EXE) $(CFLAGS) -o $@ getub.lo $(LIBTOOLS) $(LIBHDF5) $(LDFLAGS) $(LIBS)
+
+check-all: check
+
+@CONCLUDE@
diff --git a/tools/h5jam/getub.c b/tools/h5jam/getub.c
new file mode 100644
index 0000000..58e9fe8
--- /dev/null
+++ b/tools/h5jam/getub.c
@@ -0,0 +1,170 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifdef H5_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "H5private.h"
+#include "h5tools_utils.h"
+
+void parse_command_line (int argc, const char *argv[]);
+
+#define TRUE 1
+#define FALSE 0
+
+static char *progname="getub";
+char *nbytes = NULL;
+
+static const char *s_opts = "c:"; /* add more later ? */
+static struct long_options l_opts[] = {
+ {"c", require_arg, 'c'}, /* input file */
+ {NULL, 0, '\0'}
+};
+
+/*-------------------------------------------------------------------------
+ * Function: usage
+ *
+ * Purpose: Print the usage message
+ *
+ * Return: void
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+usage (const char *prog)
+{
+ fflush (stdout);
+ fprintf (stdout, "usage: %s -c nb file] \n", prog);
+ fprintf (stdout, " print first 'nb' byts of file to stdoug.\n");
+}
+
+/*-------------------------------------------------------------------------
+ * Function: parse_command_line
+ *
+ * Purpose: Parse the command line for the h5dumper.
+ *
+ * Return: Success:
+ *
+ * Failure: Exits program with EXIT_FAILURE value.
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+void
+parse_command_line (int argc, const char *argv[])
+{
+ int opt = FALSE;
+
+ /* parse command line options */
+ while ((opt = get_option (argc, argv, s_opts, l_opts)) != EOF)
+ {
+ switch ((char) opt)
+ {
+ case 'c':
+ nbytes = strdup (opt_arg);
+ break;
+ case '?':
+ default:
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ if (argc <= opt_ind)
+ {
+ error_msg (progname, "missing file name\n");
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+}
+
+int
+main (int argc, const char *argv[])
+{
+ int fd;
+ unsigned int size;
+ char *filename;
+ long res;
+ char *buf;
+
+ parse_command_line (argc, argv);
+
+ if (nbytes == NULL)
+ {
+ /* missing arg */
+ error_msg (progname, "missing size\n");
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+ if (argc <= (opt_ind))
+ {
+ error_msg (progname, "missing file name\n");
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+ filename = strdup (argv[opt_ind]);
+
+ size = 0;
+ res = sscanf (nbytes, "%u", &size);
+ if (res == EOF)
+ {
+ /* fail */
+ error_msg (progname, "missing file name\n");
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+
+ fd = HDopen (filename, O_RDONLY, 0);
+ if (fd < 0)
+ {
+ error_msg (progname, "can't open file %s\n", filename);
+ exit (EXIT_FAILURE);
+ }
+
+ buf = malloc ((unsigned)(size + 1));
+ if (buf == NULL)
+ {
+ close (fd);
+ exit (EXIT_FAILURE);
+ }
+
+ res = HDread (fd, buf, (unsigned)size);
+
+ if (res < size)
+ {
+ if (buf)
+ free (buf);
+ close (fd);
+ exit (EXIT_FAILURE);
+ }
+
+ HDwrite (1, buf, (unsigned)size);
+
+ if (buf)
+ free (buf);
+ close (fd);
+ return (EXIT_SUCCESS);
+}
diff --git a/tools/h5jam/h5jam.c b/tools/h5jam/h5jam.c
new file mode 100644
index 0000000..d78e28c
--- /dev/null
+++ b/tools/h5jam/h5jam.c
@@ -0,0 +1,538 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifdef H5_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "hdf5.h"
+#include "H5private.h"
+#include "h5tools_utils.h"
+
+#define TRUE 1
+#define FALSE 0
+
+hsize_t write_pad (int, hsize_t);
+hsize_t compute_user_block_size (hsize_t);
+hsize_t copy_some_to_file (int, int, hsize_t, hsize_t, ssize_t);
+void parse_command_line (int, const char *[]);
+
+const char *progname = "jam";
+int d_status = EXIT_SUCCESS;
+int do_clobber = FALSE;
+char *output_file = NULL;
+char *input_file = NULL;
+char *ub_file = NULL;
+
+/*
+ * Command-line options: The user can specify short or long-named
+ * parameters. The long-named ones can be partially spelled. When
+ * adding more, make sure that they don't clash with each other.
+ */
+static const char *s_opts = "hi:u:o:c"; /* add more later ? */
+static struct long_options l_opts[] = {
+ {"help", no_arg, 'h'},
+ {"hel", no_arg, 'h'},
+ {"i", require_arg, 'i'}, /* input file */
+ {"u", require_arg, 'u'}, /* user block file */
+ {"o", require_arg, 'o'}, /* output file */
+ {"clobber", no_arg, 'c'}, /* clobber existing UB */
+ {"clobbe", no_arg, 'c'},
+ {"clobb", no_arg, 'c'},
+ {"clob", no_arg, 'c'},
+ {"clo", no_arg, 'c'},
+ {"cl", no_arg, 'c'},
+ {NULL, 0, '\0'}
+};
+
+/*-------------------------------------------------------------------------
+ * Function: usage
+ *
+ * Purpose: Print the usage message
+ *
+ * Return: void
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+usage (const char *prog)
+{
+ fflush (stdout);
+ fprintf (stdout,
+ "usage: %s -u user_block_file -i h5_file [-o ofile | --clobber] \n",
+ prog);
+ fprintf (stdout, " Add 'user_block_file' to front of \n");
+ fprintf (stdout,
+ " 'h5_file', pad so 'h5_file' starts on proper\n");
+ fprintf (stdout, " byte.\n");
+ fprintf (stdout, "\n");
+ fprintf (stdout, " %s -h \n", prog);
+ fprintf (stdout, " Print a usage message and exit\n");
+}
+
+/*-------------------------------------------------------------------------
+ * Function: parse_command_line
+ *
+ * Purpose: Parse the command line for the h5dumper.
+ *
+ * Return: Success:
+ *
+ * Failure: Exits program with EXIT_FAILURE value.
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+void
+parse_command_line (int argc, const char *argv[])
+{
+ int opt = FALSE;
+
+ /* parse command line options */
+ while ((opt = get_option (argc, argv, s_opts, l_opts)) != EOF)
+ {
+ switch ((char) opt)
+ {
+ case 'o':
+ output_file = strdup (opt_arg);
+ break;
+ case 'i':
+ input_file = strdup (opt_arg);
+ break;
+ case 'u':
+ ub_file = strdup (opt_arg);
+ break;
+ case 'c':
+ do_clobber = TRUE;
+ break;
+ case 'h':
+ usage (progname);
+ exit (EXIT_SUCCESS);
+ case '?':
+ default:
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: HDF5 user block jammer
+ *
+ * Return: Success: 0
+ * Failure: 1
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main (int argc, const char *argv[])
+{
+ int ufid;
+ int h5fid;
+ int ofid;
+ void *edata;
+ H5E_auto_stack_t func;
+ hid_t ifile;
+ hid_t plist;
+ herr_t status;
+ htri_t testval;
+ hsize_t usize;
+ hsize_t h5fsize;
+ hsize_t startub;
+ hsize_t where;
+ hsize_t newubsize;
+ off_t fsize;
+ struct stat sbuf;
+ struct stat sbuf2;
+ int res;
+
+ /* Disable error reporting */
+ H5Eget_auto_stack (H5E_DEFAULT, &func, &edata);
+ H5Eset_auto_stack (H5E_DEFAULT, NULL, NULL);
+
+ parse_command_line (argc, argv);
+
+ if (ub_file == NULL)
+ {
+ /* no user block */
+ error_msg (progname, "no user block file name\n");
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+
+ if (input_file == NULL)
+ {
+ /* no user block */
+ error_msg (progname, "no HDF5 file\n");
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+
+ testval = H5Fis_hdf5 (input_file);
+
+ if (testval <= 0)
+ {
+ error_msg (progname, "Input HDF5 file is not HDF \"%s\"\n", input_file);
+ exit (EXIT_FAILURE);
+ }
+
+ ifile = H5Fopen (input_file, H5F_ACC_RDONLY, H5P_DEFAULT);
+
+ if (ifile < 0)
+ {
+ error_msg (progname, "Can't open input HDF5 file \"%s\"\n", input_file);
+ exit (EXIT_FAILURE);
+ }
+
+ plist = H5Fget_create_plist (ifile);
+ if (plist < 0)
+ {
+ error_msg (progname, "Can't get file creation plist for file \"%s\"\n",
+ input_file);
+ exit (EXIT_FAILURE);
+ }
+
+ status = H5Pget_userblock (plist, &usize);
+ if (status < 0)
+ {
+ error_msg (progname, "Can't get user block for file \"%s\"\n",
+ input_file);
+ exit (EXIT_FAILURE);
+ }
+
+ H5Pclose (plist);
+ H5Fclose (ifile);
+
+ ufid = HDopen (ub_file, O_RDONLY, 0);
+
+ if (ufid < 0)
+ {
+ error_msg (progname, "unable to open user block file \"%s\"\n",
+ ub_file);
+ exit (EXIT_FAILURE);
+ }
+
+ res = stat (ub_file, &sbuf);
+
+ if (res < 0)
+ {
+ error_msg (progname, "Can't stat file \"%s\"\n", ub_file);
+ exit (EXIT_FAILURE);
+ }
+
+ fsize = sbuf.st_size;
+
+ h5fid = HDopen (input_file, O_RDONLY, 0);
+
+ if (h5fid < 0)
+ {
+ error_msg (progname, "unable to open HDF5 file for read \"%s\"\n",
+ input_file);
+ exit (EXIT_FAILURE);
+ }
+
+ res = stat (input_file, &sbuf2);
+
+ if (res < 0)
+ {
+ error_msg (progname, "Can't stat file \"%s\"\n", input_file);
+ exit (EXIT_FAILURE);
+ }
+
+ h5fsize = sbuf2.st_size;
+
+ if (output_file == NULL)
+ {
+ ofid = HDopen (input_file, O_WRONLY, 0);
+
+ if (ofid < 0)
+ {
+ error_msg (progname, "unable to open output file \"%s\"\n",
+ output_file);
+ exit (EXIT_FAILURE);
+ }
+ }
+ else
+ {
+ ofid = HDopen (output_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+
+ if (ofid < 0)
+ {
+ error_msg (progname, "unable to create output file \"%s\"\n",
+ output_file);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ newubsize = compute_user_block_size ((hsize_t) fsize);
+
+ startub = usize;
+
+ if (usize > 0)
+ {
+ if (do_clobber == TRUE)
+ {
+ /* where is max of the current size or the new UB */
+ if (usize > newubsize)
+ {
+ newubsize = usize;
+ }
+ startub = 0; /*blast the old */
+ }
+ else
+ {
+ /* add new ub to current ublock, pad to new offset */
+ newubsize += usize;
+ newubsize = compute_user_block_size ((hsize_t) newubsize);
+ }
+ }
+
+ /* copy the HDF5 from starting at usize to starting at newubsize:
+ * makes room at 'from' for new ub */
+ /* if no current ub, usize is 0 */
+ copy_some_to_file (h5fid, ofid, usize, newubsize,
+ (ssize_t) (h5fsize - usize));
+
+ /* copy the old ub to the beginning of the new file */
+ if (!do_clobber)
+ {
+ where =
+ copy_some_to_file (h5fid, ofid, (hsize_t) 0, (hsize_t) 0,
+ (ssize_t) usize);
+ }
+
+ /* copy the new ub to the end of the ub */
+ where = copy_some_to_file (ufid, ofid, (hsize_t) 0, startub, (ssize_t) - 1);
+
+ /* pad the ub */
+ where = write_pad (ofid, where);
+
+
+ close (ufid);
+ close (h5fid);
+ close (ofid);
+
+ return d_status;
+}
+
+/*-------------------------------------------------------------------------
+ * Function: copy_some_to_file
+ *
+ * Purpose: Copy part of the input file to output.
+ * infid: fd of file to read
+ * outfid: fd of file to write
+ * startin: offset of where to read from infid
+ * startout: offset of where to write to outfid
+ * limit: bytes to read/write
+ *
+ * If limit is < 0, the entire input file is copied.
+ *
+ * Note: this routine can be used to copy within
+ * the same file, i.e., infid and outfid can be the
+ * same file.
+ *
+ * Return: Success: last byte written in the output.
+ * Failure: Exits program with EXIT_FAILURE value.
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+copy_some_to_file (int infid, int outfid, hsize_t startin, hsize_t startout,
+ ssize_t limit)
+{
+ char buf[1024];
+ struct stat sbuf;
+ int res;
+ ssize_t tot = 0;
+ ssize_t howmuch = 0;
+ ssize_t nchars = -1;
+/* used in assertion check
+ ssize_t ncw = -1;
+*/
+ ssize_t to;
+ ssize_t from;
+ ssize_t toend;
+ ssize_t fromend;
+
+ if (startin > startout)
+ {
+ /* this case is prohibited */
+ error_msg (progname, "copy_some_to_file: panic: startin > startout?\n");
+ exit (EXIT_FAILURE);
+ }
+
+ if (limit < 0)
+ {
+ res = fstat (infid, &sbuf);
+
+ if (res < 0)
+ {
+ error_msg (progname, "Can't stat file \n");
+ exit (EXIT_FAILURE);
+ }
+
+ howmuch = sbuf.st_size;
+ }
+ else
+ {
+ howmuch = limit;
+ }
+
+ if (howmuch == 0)
+ {
+ return 0;
+ }
+
+ /* assert (howmuch > 0) */
+
+ toend = (ssize_t) startout + howmuch;
+ fromend = (ssize_t) startin + howmuch;
+
+ if (howmuch > 512)
+ {
+ to = toend - 512;
+ from = fromend - 512;
+ }
+ else
+ {
+ to = toend - howmuch;
+ from = fromend - howmuch;
+ }
+
+ while (howmuch > 0)
+ {
+ HDlseek (outfid, (off_t) to, SEEK_SET);
+ HDlseek (infid, (off_t) from, SEEK_SET);
+
+ if (howmuch > 512)
+ {
+ nchars = HDread (infid, buf, (unsigned) 512);
+ }
+ else
+ {
+ nchars = HDread (infid, buf, howmuch);
+ }
+
+ if (nchars <= 0)
+ {
+ printf ("huh? \n");
+ exit (1);
+ }
+ /*ncw = */ HDwrite (outfid, buf, (unsigned) nchars);
+
+ /* assert (ncw == nchars) */
+
+ tot += nchars;
+ howmuch -= nchars;
+ if (howmuch > 512)
+ {
+ to -= nchars;
+ from -= nchars;
+ }
+ else
+ {
+ to -= howmuch;
+ from -= howmuch;
+ }
+ }
+
+ /* assert howmuch == 0 */
+ /* assert tot == limit */
+
+ return ((hsize_t) tot + (hsize_t) startout);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: compute_user_block_size
+ *
+ * Purpose: Find the offset of the HDF5 header after the user block:
+ * align at 0, 512, 1024, etc.
+ * ublock_size: the size of the user block (bytes).
+ *
+ * Return: Success: the location of the header == the size of the
+ * padded user block.
+ * Failure: none
+ *
+ * Return: Success: last byte written in the output.
+ * Failure: Exits program with EXIT_FAILURE value.
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hsize_t
+compute_user_block_size (hsize_t ublock_size)
+{
+ ssize_t where = 512;
+
+ if (ublock_size == 0)
+ return 0;
+
+ while (where < ublock_size)
+ {
+ where *= 2;
+ }
+
+ return (where);
+}
+
+/*
+ * Write zeroes to fill the file from 'where' to 512, 1024, etc. bytes.
+ *
+ * Returns the size of the padded file.
+ */
+hsize_t
+write_pad (int ofile, hsize_t where)
+{
+ unsigned int i;
+ char buf[1];
+ hsize_t psize;
+
+ buf[0] = '\0';
+
+ HDlseek (ofile, (off_t) where, SEEK_SET);
+
+ psize = compute_user_block_size (where);
+ psize -= where;
+
+ for (i = 0; i < psize; i++)
+ {
+ HDwrite (ofile, buf, 1);
+ }
+ return (where + psize); /* the new size of the file. */
+}
diff --git a/tools/h5jam/h5jamgentest.c b/tools/h5jam/h5jamgentest.c
new file mode 100644
index 0000000..7f6342f
--- /dev/null
+++ b/tools/h5jam/h5jamgentest.c
@@ -0,0 +1,639 @@
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Generate the binary hdf5 files and user block data for the jam/unjam tests.
+ * Usage: just execute the program without any arguments will
+ * generate all the files in the local directory.
+ *
+ * If you regenerate the test files (e.g., changing some code,
+ * trying it on a new platform, ...), you need to verify the correctness
+ * of the expected output and update the corresponding *.ddl files.
+ */
+#include <limits.h>
+
+#include "hdf5.h"
+#include "H5private.h"
+
+#define UBTXT1 "u0.txt"
+#define UBTXT2 "u10.txt"
+#define UBTXT3 "u511.txt"
+#define UBTXT4 "u512.txt"
+#define UBTXT5 "u513.txt"
+/* not used yet
+#define UBTXT6 "u1023.txt"
+#define UBTXT7 "u1024.txt"
+#define UBTXT8 "u1025.txt"
+#define UBTXT9 "u2047.txt"
+#define UBTXT10 "u2048.txt"
+#define UBTXT11 "u2049.txt"
+#define UBBIN1 "u0.dat"
+#define UBBIN2 "u10.dat"
+#define UBBIN3 "u511.dat"
+#define UBBIN4 "u512.dat"
+#define UBBIN5 "u513.dat"
+*/
+
+/* not used yet
+#define FILE1 "tnull.h5"
+#define FILE2 "tnullwithub.h5"
+*/
+/* tall is same as dumper test */
+#define FILE7 "tall.h5"
+#define FILE8 "twithub.h5"
+#define FILE9 "twithub513.h5"
+
+/*
+ * This pattern is used to fill text files
+ */
+char pattern[11] = "abcdefghij";
+
+/*-------------------------------------------------------------------------
+ * prototypes
+ *-------------------------------------------------------------------------
+ */
+
+
+#define LENSTR 50
+#define LENSTR2 11
+
+#define SPACE2_RANK 2
+#define SPACE2_DIM1 10
+#define SPACE2_DIM2 10
+
+#define SPACE1_RANK 1
+#define SPACE1_DIM1 4
+
+#define DIM1 20
+#define DIM2 10
+#define CDIM1 DIM1/2
+#define CDIM2 DIM2/2
+#define RANK 2
+
+/* Element selection information */
+#define POINT1_NPOINTS 10
+
+typedef enum{
+ RED,
+ GREEN,
+ BLUE,
+ WHITE,
+ BLACK
+} enumtype;
+
+/* Compound datatype */
+typedef struct s1_t {
+ unsigned int a;
+ unsigned int b;
+ float c;
+} s1_t;
+
+
+/* 1-D array datatype */
+#define ARRAY1_RANK 1
+#define ARRAY1_DIM1 4
+
+/* 3-D array datatype */
+#define ARRAY2_RANK 3
+#define ARRAY2_DIM1 3
+#define ARRAY2_DIM2 4
+#define ARRAY2_DIM3 5
+
+/* 2-D array datatype */
+#define ARRAY3_RANK 2
+#define ARRAY3_DIM1 6
+#define ARRAY3_DIM2 3
+
+/* VL string datatype name */
+#define VLSTR_TYPE "vl_string_type"
+
+
+/*
+
+/ : g1 g2 attr1 attr2
+g1 : g1.1 g1.2
+g1.1 : dset1.1.1(attr1, attr2) dset1.1.2
+g1.2 : g1.2.1
+g1.2.1 : slink
+g2 : dset2.1 dset2.2
+
+*/
+
+
+static void gent_all(void) {
+hid_t fid, group, attr, dataset, space;
+hsize_t dims[2];
+int data[2][2], dset1[10][10], dset2[20];
+char buf[60];
+int i, j;
+float dset2_1[10], dset2_2[3][5];
+
+ fid = H5Fcreate(FILE7, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
+
+ /* create groups */
+ group = H5Gcreate (fid, "/g1", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g2", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g1/g1.1", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g1/g1.2", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g1/g1.2/g1.2.1", 0);
+ H5Gclose(group);
+
+ /* root attributes */
+ group = H5Gopen (fid, "/");
+
+ dims[0] = 10;
+ space = H5Screate_simple(1, dims, NULL);
+ attr = H5Acreate (group, "attr1", H5T_STD_I8BE, space, H5P_DEFAULT);
+ sprintf(buf, "abcdefghi");
+ H5Awrite(attr, H5T_NATIVE_SCHAR, buf);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ dims[0] = 2; dims[1] = 2;
+ space = H5Screate_simple(2, dims, NULL);
+ attr = H5Acreate (group, "attr2", H5T_STD_I32BE, space, H5P_DEFAULT);
+ data[0][0] = 0; data[0][1] = 1; data[1][0] = 2; data[1][1] = 3;
+ H5Awrite(attr, H5T_NATIVE_INT, data);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ H5Gclose(group);
+
+ group = H5Gopen (fid, "/g1/g1.1");
+
+ /* dset1.1.1 */
+ dims[0] = 10; dims[1] = 10;
+ space = H5Screate_simple(2, dims, NULL);
+ dataset = H5Dcreate(group, "dset1.1.1", H5T_STD_I32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 10; i++)
+ for (j = 0; j < 10; j++)
+ dset1[i][j] = j*i;
+ H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset1);
+ H5Sclose(space);
+
+ /* attributes of dset1.1.1 */
+ dims[0] = 27;
+ space = H5Screate_simple(1, dims, NULL);
+ attr = H5Acreate (dataset, "attr1", H5T_STD_I8BE, space, H5P_DEFAULT);
+ sprintf(buf, "1st attribute of dset1.1.1");
+ H5Awrite(attr, H5T_NATIVE_SCHAR, buf);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ dims[0] = 27;
+ space = H5Screate_simple(1, dims, NULL);
+ attr = H5Acreate (dataset, "attr2", H5T_STD_I8BE, space, H5P_DEFAULT);
+ sprintf(buf, "2nd attribute of dset1.1.1");
+ H5Awrite(attr, H5T_NATIVE_SCHAR, buf);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ H5Dclose(dataset);
+
+ /* dset1.1.2 */
+ dims[0] = 20;
+ space = H5Screate_simple(1, dims, NULL);
+ dataset = H5Dcreate(group, "dset1.1.2", H5T_STD_I32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 20; i++)
+ dset2[i] = i;
+ H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset2);
+ H5Sclose(space);
+ H5Dclose(dataset);
+
+ H5Gclose(group);
+
+ /* soft link */
+ group = H5Gopen (fid, "/g1/g1.2/g1.2.1");
+ H5Glink (group, H5G_LINK_SOFT, "somevalue", "slink");
+ H5Gclose(group);
+
+ group = H5Gopen (fid, "/g2");
+
+ /* dset2.1 */
+ dims[0] = 10;
+ space = H5Screate_simple(1, dims, NULL);
+ dataset = H5Dcreate(group, "dset2.1", H5T_IEEE_F32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 10; i++)
+ dset2_1[i] = (float)(i*0.1+1);
+ H5Dwrite(dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset2_1);
+ H5Sclose(space);
+ H5Dclose(dataset);
+
+ /* dset2.2 */
+ dims[0] = 3; dims[1] = 5;
+ space = H5Screate_simple(2, dims, NULL);
+ dataset = H5Dcreate(group, "dset2.2", H5T_IEEE_F32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 5; j++)
+ dset2_2[i][j] = (float)((i+1)*j*0.1);
+ H5Dwrite(dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset2_2);
+ H5Sclose(space);
+ H5Dclose(dataset);
+
+ H5Gclose(group);
+
+ H5Fclose(fid);
+
+}
+
+static void gent_withub(void) {
+hid_t fid, group, attr, dataset, space;
+hid_t create_plist;
+hsize_t dims[2];
+int data[2][2], dset1[10][10], dset2[20];
+char buf[512];
+int i, j;
+float dset2_1[10], dset2_2[3][5];
+int fd;
+char *bp;
+
+ create_plist = H5Pcreate(H5P_FILE_CREATE);
+ H5Pset_userblock(create_plist,512);
+ fid = H5Fcreate(FILE8, H5F_ACC_TRUNC, create_plist, H5P_DEFAULT);
+
+ /* create groups */
+ group = H5Gcreate (fid, "/g1", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g2", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g1/g1.1", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g1/g1.2", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g1/g1.2/g1.2.1", 0);
+ H5Gclose(group);
+
+ /* root attributes */
+ group = H5Gopen (fid, "/");
+
+ dims[0] = 10;
+ space = H5Screate_simple(1, dims, NULL);
+ attr = H5Acreate (group, "attr1", H5T_STD_I8BE, space, H5P_DEFAULT);
+ sprintf(buf, "abcdefghi");
+ H5Awrite(attr, H5T_NATIVE_SCHAR, buf);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ dims[0] = 2; dims[1] = 2;
+ space = H5Screate_simple(2, dims, NULL);
+ attr = H5Acreate (group, "attr2", H5T_STD_I32BE, space, H5P_DEFAULT);
+ data[0][0] = 0; data[0][1] = 1; data[1][0] = 2; data[1][1] = 3;
+ H5Awrite(attr, H5T_NATIVE_INT, data);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ H5Gclose(group);
+
+ group = H5Gopen (fid, "/g1/g1.1");
+
+ /* dset1.1.1 */
+ dims[0] = 10; dims[1] = 10;
+ space = H5Screate_simple(2, dims, NULL);
+ dataset = H5Dcreate(group, "dset1.1.1", H5T_STD_I32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 10; i++)
+ for (j = 0; j < 10; j++)
+ dset1[i][j] = j*i;
+ H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset1);
+ H5Sclose(space);
+
+ /* attributes of dset1.1.1 */
+ dims[0] = 27;
+ space = H5Screate_simple(1, dims, NULL);
+ attr = H5Acreate (dataset, "attr1", H5T_STD_I8BE, space, H5P_DEFAULT);
+ sprintf(buf, "1st attribute of dset1.1.1");
+ H5Awrite(attr, H5T_NATIVE_SCHAR, buf);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ dims[0] = 27;
+ space = H5Screate_simple(1, dims, NULL);
+ attr = H5Acreate (dataset, "attr2", H5T_STD_I8BE, space, H5P_DEFAULT);
+ sprintf(buf, "2nd attribute of dset1.1.1");
+ H5Awrite(attr, H5T_NATIVE_SCHAR, buf);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ H5Dclose(dataset);
+
+ /* dset1.1.2 */
+ dims[0] = 20;
+ space = H5Screate_simple(1, dims, NULL);
+ dataset = H5Dcreate(group, "dset1.1.2", H5T_STD_I32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 20; i++)
+ dset2[i] = i;
+ H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset2);
+ H5Sclose(space);
+ H5Dclose(dataset);
+
+ H5Gclose(group);
+
+ /* soft link */
+ group = H5Gopen (fid, "/g1/g1.2/g1.2.1");
+ H5Glink (group, H5G_LINK_SOFT, "somevalue", "slink");
+ H5Gclose(group);
+
+ group = H5Gopen (fid, "/g2");
+
+ /* dset2.1 */
+ dims[0] = 10;
+ space = H5Screate_simple(1, dims, NULL);
+ dataset = H5Dcreate(group, "dset2.1", H5T_IEEE_F32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 10; i++)
+ dset2_1[i] = (float)(i*0.1+1);
+ H5Dwrite(dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset2_1);
+ H5Sclose(space);
+ H5Dclose(dataset);
+
+ /* dset2.2 */
+ dims[0] = 3; dims[1] = 5;
+ space = H5Screate_simple(2, dims, NULL);
+ dataset = H5Dcreate(group, "dset2.2", H5T_IEEE_F32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 5; j++)
+ dset2_2[i][j] = (float)((i+1)*j*0.1);
+ H5Dwrite(dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset2_2);
+ H5Sclose(space);
+ H5Dclose(dataset);
+
+ H5Gclose(group);
+
+ H5Fclose(fid);
+
+
+ fd = HDopen(FILE8,O_RDWR, 0);
+ if (fd < 0) {
+ /* panic */
+ }
+ /* fill buf with pattern */
+ memset(buf,'\0',512);
+ bp = buf;
+ for (i = 0; i < strlen(pattern); i++) {
+ *bp++ = pattern[i%10];
+ }
+
+ HDwrite(fd,buf,512);
+
+ close(fd);
+}
+
+static void gent_withub513(void) {
+hid_t fid, group, attr, dataset, space;
+hid_t create_plist;
+hsize_t dims[2];
+int data[2][2], dset1[10][10], dset2[20];
+char buf[1023];
+int i, j;
+float dset2_1[10], dset2_2[3][5];
+int fd;
+char *bp;
+
+ create_plist = H5Pcreate(H5P_FILE_CREATE);
+ H5Pset_userblock(create_plist,1024);
+ fid = H5Fcreate(FILE9, H5F_ACC_TRUNC, create_plist, H5P_DEFAULT);
+
+ /* create groups */
+ group = H5Gcreate (fid, "/g1", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g2", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g1/g1.1", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g1/g1.2", 0);
+ H5Gclose(group);
+
+ group = H5Gcreate (fid, "/g1/g1.2/g1.2.1", 0);
+ H5Gclose(group);
+
+ /* root attributes */
+ group = H5Gopen (fid, "/");
+
+ dims[0] = 10;
+ space = H5Screate_simple(1, dims, NULL);
+ attr = H5Acreate (group, "attr1", H5T_STD_I8BE, space, H5P_DEFAULT);
+ sprintf(buf, "abcdefghi");
+ H5Awrite(attr, H5T_NATIVE_SCHAR, buf);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ dims[0] = 2; dims[1] = 2;
+ space = H5Screate_simple(2, dims, NULL);
+ attr = H5Acreate (group, "attr2", H5T_STD_I32BE, space, H5P_DEFAULT);
+ data[0][0] = 0; data[0][1] = 1; data[1][0] = 2; data[1][1] = 3;
+ H5Awrite(attr, H5T_NATIVE_INT, data);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ H5Gclose(group);
+
+ group = H5Gopen (fid, "/g1/g1.1");
+
+ /* dset1.1.1 */
+ dims[0] = 10; dims[1] = 10;
+ space = H5Screate_simple(2, dims, NULL);
+ dataset = H5Dcreate(group, "dset1.1.1", H5T_STD_I32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 10; i++)
+ for (j = 0; j < 10; j++)
+ dset1[i][j] = j*i;
+ H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset1);
+ H5Sclose(space);
+
+ /* attributes of dset1.1.1 */
+ dims[0] = 27;
+ space = H5Screate_simple(1, dims, NULL);
+ attr = H5Acreate (dataset, "attr1", H5T_STD_I8BE, space, H5P_DEFAULT);
+ sprintf(buf, "1st attribute of dset1.1.1");
+ H5Awrite(attr, H5T_NATIVE_SCHAR, buf);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ dims[0] = 27;
+ space = H5Screate_simple(1, dims, NULL);
+ attr = H5Acreate (dataset, "attr2", H5T_STD_I8BE, space, H5P_DEFAULT);
+ sprintf(buf, "2nd attribute of dset1.1.1");
+ H5Awrite(attr, H5T_NATIVE_SCHAR, buf);
+ H5Sclose(space);
+ H5Aclose(attr);
+
+ H5Dclose(dataset);
+
+ /* dset1.1.2 */
+ dims[0] = 20;
+ space = H5Screate_simple(1, dims, NULL);
+ dataset = H5Dcreate(group, "dset1.1.2", H5T_STD_I32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 20; i++)
+ dset2[i] = i;
+ H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset2);
+ H5Sclose(space);
+ H5Dclose(dataset);
+
+ H5Gclose(group);
+
+ /* soft link */
+ group = H5Gopen (fid, "/g1/g1.2/g1.2.1");
+ H5Glink (group, H5G_LINK_SOFT, "somevalue", "slink");
+ H5Gclose(group);
+
+ group = H5Gopen (fid, "/g2");
+
+ /* dset2.1 */
+ dims[0] = 10;
+ space = H5Screate_simple(1, dims, NULL);
+ dataset = H5Dcreate(group, "dset2.1", H5T_IEEE_F32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 10; i++)
+ dset2_1[i] = (float)(i*0.1+1);
+ H5Dwrite(dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset2_1);
+ H5Sclose(space);
+ H5Dclose(dataset);
+
+ /* dset2.2 */
+ dims[0] = 3; dims[1] = 5;
+ space = H5Screate_simple(2, dims, NULL);
+ dataset = H5Dcreate(group, "dset2.2", H5T_IEEE_F32BE, space, H5P_DEFAULT);
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 5; j++)
+ dset2_2[i][j] = (float)((i+1)*j*0.1);
+ H5Dwrite(dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset2_2);
+ H5Sclose(space);
+ H5Dclose(dataset);
+
+ H5Gclose(group);
+
+ H5Fclose(fid);
+
+
+ fd = HDopen(FILE9,O_RDWR, 0);
+ if (fd < 0) {
+ /* panic */
+ }
+ /* fill buf with pattern */
+ memset(buf,'\0',1024);
+ bp = buf;
+ for (i = 0; i < 513; i++) {
+ *bp++ = pattern[i%10];
+ }
+
+ HDwrite(fd,buf,1024);
+
+ close(fd);
+}
+
+void
+create_textfile(char *name, off_t size) {
+char *buf;
+int fd;
+int i;
+char *bp;
+
+ fd = creat(name,0777);
+ if (fd < 0) {
+ /* panic */
+ }
+ buf = calloc(size,1);
+ if (buf == NULL) {
+ /* panic */
+ }
+ /* fill buf with pattern */
+ bp = buf;
+ for (i = 0; i < size; i++) {
+ *bp++ = pattern[i%10];
+ }
+
+
+ HDwrite(fd,buf,size);
+
+ close(fd);
+}
+
+#ifdef notdef
+/* not used yet */
+void
+create_binfile(char *name, off_t size) {
+char *buf;
+int fd;
+int i;
+char *bp;
+
+ fd = creat(name,0777);
+ if (fd < 0) {
+ /* panic */
+ }
+ buf = calloc(size,1);
+ if (buf == NULL) {
+ /* panic */
+ }
+ /* fill buf with pattern */
+ bp = buf;
+ for (i = 0; i < size; i++) {
+ *bp++ = (char) i & 0xff;
+ }
+
+ HDwrite(fd,buf,size);
+
+ close(fd);
+}
+#endif
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+int main(void)
+{
+
+/*
+create_textfile(UBTXT1,0);
+*/
+create_textfile(UBTXT2,10);
+create_textfile(UBTXT3,511);
+create_textfile(UBTXT4,512);
+create_textfile(UBTXT5,513);
+/*
+create_textfile(UBTXT6,1023);
+create_textfile(UBTXT7,1024);
+create_textfile(UBTXT8,1025);
+create_textfile(UBTXT9,2047);
+create_textfile(UBTXT10,2048);
+create_textfile(UBTXT11,2049);
+
+create_binfile(UBBIN1,0);
+create_binfile(UBBIN2,10);
+create_binfile(UBBIN3,511);
+create_binfile(UBBIN4,512);
+create_binfile(UBBIN5,513);
+
+*/
+ gent_all();
+ gent_withub();
+ gent_withub513();
+
+ return 0;
+}
diff --git a/tools/h5jam/h5unjam.c b/tools/h5jam/h5unjam.c
new file mode 100644
index 0000000..20378e5
--- /dev/null
+++ b/tools/h5jam/h5unjam.c
@@ -0,0 +1,317 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifdef H5_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "hdf5.h"
+#include "H5private.h"
+#include "h5tools_utils.h"
+
+#define TRUE 1
+#define FALSE 0
+
+hsize_t write_pad( int , hsize_t );
+hsize_t compute_pad( hsize_t );
+hsize_t copy_to_file( int , int , ssize_t, ssize_t );
+
+const char *progname = "unjam";
+int d_status = EXIT_SUCCESS;
+int do_delete = FALSE;
+char *output_file = NULL;
+char *input_file = NULL;
+char *ub_file = NULL;
+
+/*
+ * Command-line options: The user can specify short or long-named
+ * parameters. The long-named ones can be partially spelled. When
+ * adding more, make sure that they don't clash with each other.
+ */
+static const char *s_opts = "hu:i:o:d";
+static struct long_options l_opts[] = {
+ { "help", no_arg, 'h' },
+ { "hel", no_arg, 'h' },
+ {"i", require_arg, 'i'}, /* input file */
+ {"u", require_arg, 'u'}, /* user block file */
+ {"o", require_arg, 'o'}, /* output file */
+ {"delete", no_arg, 'd'}, /* delete ub */
+ {"delet", no_arg, 'd'},
+ {"dele", no_arg, 'd'},
+ {"del", no_arg, 'd'},
+ {"de", no_arg, 'd'},
+ { NULL, 0, '\0' }
+};
+
+/*-------------------------------------------------------------------------
+ * Function: usage
+ *
+ * Purpose: Print the usage message
+ *
+ * Return: void
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+usage(const char *prog)
+{
+ fflush(stdout);
+ fprintf(stdout, "usage: %s -i h5_file -o user_block_file_out -o h5_file_out [-d | --delete]\n", prog);
+ fprintf(stdout, " Extract user block from 'h5_file' into 'user_block_file'\n");
+ fprintf(stdout, " and HDF5 file into 'h5_file_out'\n");
+
+ fprintf(stdout, " %s -h\n",prog);
+ fprintf(stdout, " Print a usage message and exit\n");
+}
+
+/*-------------------------------------------------------------------------
+ * Function: parse_command_line
+ *
+ * Purpose: Parse the command line for the h5dumper.
+ *
+ * Return: Success:
+ *
+ * Failure: Exits program with EXIT_FAILURE value.
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+void
+parse_command_line(int argc, const char *argv[])
+{
+ int opt = FALSE;
+
+ /* parse command line options */
+ while ((opt = get_option(argc, argv, s_opts, l_opts)) != EOF) {
+ switch ((char)opt) {
+ case 'o':
+ output_file = strdup (opt_arg);
+ break;
+ case 'i':
+ input_file = strdup (opt_arg);
+ break;
+ case 'u':
+ ub_file = strdup (opt_arg);
+ break;
+ case 'd':
+ do_delete = TRUE;
+ break;
+ case 'h':
+ usage(progname);
+ exit(EXIT_SUCCESS);
+ case '?':
+ default:
+ usage(progname);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* check for file name to be processed */
+/*
+ if (argc <= opt_ind+2) {
+ error_msg(progname, "missing file name\n");
+ usage(progname);
+ exit(EXIT_FAILURE);
+ }
+*/
+}
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: HDF5 user block unjammer
+ *
+ * Return: Success: 0
+ * Failure: 1
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main(int argc, const char *argv[])
+{
+ int ifid;
+ int ufid;
+ int h5fid;
+ void *edata;
+ H5E_auto_stack_t func;
+ hid_t ifile;
+ off_t fsize;
+ hsize_t usize;
+ htri_t testval;
+ herr_t status;
+ hid_t plist;
+ int res;
+ struct stat sbuf;
+
+ /* Disable error reporting */
+ H5Eget_auto_stack(H5E_DEFAULT, &func, &edata);
+ H5Eset_auto_stack(H5E_DEFAULT, NULL, NULL);
+
+ parse_command_line(argc, argv);
+
+ testval = H5Fis_hdf5(input_file);
+
+ if (testval <= 0) {
+ error_msg(progname, "Input HDF5 file is not HDF \"%s\"\n", input_file);
+ exit(EXIT_FAILURE);
+ }
+
+ ifile = H5Fopen(input_file, H5F_ACC_RDONLY , H5P_DEFAULT);
+
+ if (ifile < 0) {
+ error_msg(progname, "Can't open input HDF5 file \"%s\"\n", input_file);
+ exit(EXIT_FAILURE);
+ }
+
+ plist = H5Fget_create_plist(ifile);
+ if (plist < 0) {
+ error_msg(progname, "Can't get file creation plist for file \"%s\"\n", input_file);
+ exit(EXIT_FAILURE);
+ }
+
+ status = H5Pget_userblock(plist, & usize );
+ if (status < 0) {
+ error_msg(progname, "Can't get user block for file \"%s\"\n", input_file);
+ exit(EXIT_FAILURE);
+ }
+
+ if (usize == 0) {
+ /* no user block to remove: message? */
+ error_msg(progname, "\"%s\" has no user block: no change to file\n", input_file);
+ exit(EXIT_SUCCESS);
+
+ }
+
+ res = stat(input_file, &sbuf);
+
+ if (res < 0) {
+ error_msg(progname, "Can't stat file \"%s\"\n", input_file);
+ exit(EXIT_FAILURE);
+ }
+
+ fsize = sbuf.st_size;
+
+ ifid = HDopen(input_file,O_RDONLY,0);
+
+ if (ifid < 0) {
+ error_msg(progname, "unable to open input HDF5 file \"%s\"\n", input_file);
+ exit(EXIT_FAILURE);
+ }
+
+ if (do_delete && (ub_file != NULL)) {
+ error_msg(progname, "??\"%s\"\n", ub_file);
+ exit(EXIT_FAILURE);
+ }
+
+ if (ub_file == NULL) {
+ /* write to sdtout */
+ ufid = dup(1);
+ } else {
+ ufid = HDopen(ub_file,O_WRONLY|O_CREAT|O_TRUNC, 0644 );
+
+ if (ufid < 0) {
+ error_msg(progname, "unable to open user block file for output\"%s\"\n", ub_file);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (output_file == NULL) {
+ h5fid = HDopen(input_file,O_WRONLY, 0);
+
+ if (h5fid < 0) {
+ error_msg(progname, "unable to open output HDF5 file \"%s\"\n", input_file);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ h5fid = open(output_file,O_WRONLY|O_CREAT|O_TRUNC, 0644 );
+
+ if (h5fid < 0) {
+ error_msg(progname, "unable to open output HDF5 file \"%s\"\n", output_file);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+
+ /* copy from 0 to 'usize - 1' into ufid */
+ if (!do_delete) {
+ copy_to_file( ifid, ufid, 0, (ssize_t) usize);
+ }
+
+ /* copy from usize to end of file into h5fid,
+ * starting at end of user block if present
+ */
+ copy_to_file( ifid, h5fid, (ssize_t) usize, (fsize - (ssize_t)usize) );
+
+
+ close(ufid);
+ close(h5fid);
+ close(ifid);
+
+ return d_status;
+}
+
+/*
+ * Copy 'how_much' bytes from the input file to the output file,
+ * starting at byte 'where' in the input file.
+ *
+ * Returns the size of the output file.
+ */
+hsize_t
+copy_to_file( int infid, int ofid, ssize_t where, ssize_t how_much ) {
+ char buf[1024];
+ off_t to;
+ off_t from;
+ ssize_t nchars = -1;
+
+
+ if (how_much <= 0) {
+ /* nothing to copy */
+ return(where);
+ }
+ from = where;
+ to = 0;
+
+ while( how_much > 0) {
+ HDlseek(infid,from,SEEK_SET);
+ if (how_much > 512) {
+ nchars = HDread(infid,buf,(unsigned)512);
+ } else {
+ nchars = HDread(infid,buf,(unsigned)how_much);
+ }
+ HDlseek(ofid,to,SEEK_SET);
+ HDwrite(ofid,buf,(unsigned)nchars);
+ how_much -= nchars;
+ from += nchars;
+ to += nchars;
+ }
+
+ return (where+how_much);
+}
diff --git a/tools/h5jam/tellub.c b/tools/h5jam/tellub.c
new file mode 100644
index 0000000..ab88f4d
--- /dev/null
+++ b/tools/h5jam/tellub.c
@@ -0,0 +1,189 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include <stdio.h>
+
+#ifdef H5_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "hdf5.h"
+#include "H5private.h"
+#include "h5tools_utils.h"
+
+#define TRUE 1
+#define FALSE 0
+
+const char *progname = "tellub";
+
+/*
+ * Command-line options: The user can specify short or long-named
+ * parameters. The long-named ones can be partially spelled. When
+ * adding more, make sure that they don't clash with each other.
+ */
+static const char *s_opts = "h";
+static struct long_options l_opts[] = {
+ {"help", no_arg, 'h'},
+ {"hel", no_arg, 'h'},
+ {NULL, 0, '\0'}
+};
+
+/*-------------------------------------------------------------------------
+ * Function: usage
+ *
+ * Purpose: Print the usage message
+ *
+ * Return: void
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+usage (const char *prog)
+{
+ fflush (stdout);
+ fprintf (stdout, "usage: %s h5_file\n", prog);
+ fprintf (stdout,
+ " Check that h5_fil is HDF5 file and print size of user block \n");
+ fprintf (stdout, " %s -h\n", prog);
+ fprintf (stdout, " Print a usage message and exit\n");
+}
+
+/*-------------------------------------------------------------------------
+ * Function: parse_command_line
+ *
+ * Purpose: Parse the command line for the h5dumper.
+ *
+ * Return: Success:
+ *
+ * Failure: Exits program with EXIT_FAILURE value.
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+void
+parse_command_line (int argc, const char *argv[])
+{
+ int opt = FALSE;
+
+ /* parse command line options */
+ while ((opt = get_option (argc, argv, s_opts, l_opts)) != EOF)
+ {
+ switch ((char) opt)
+ {
+ case 'h':
+ usage (progname);
+ exit (EXIT_SUCCESS);
+ case '?':
+ default:
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ /* check for file name to be processed */
+ if (argc <= opt_ind)
+ {
+ error_msg (progname, "missing file name\n");
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+}
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: HDF5 user block unjammer
+ *
+ * Return: Success: 0
+ * Failure: 1
+ *
+ * Programmer:
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+main (int argc, const char *argv[])
+{
+ char *ifname;
+ void *edata;
+ H5E_auto_stack_t func;
+ hid_t ifile;
+ hsize_t usize;
+ htri_t testval;
+ herr_t status;
+ hid_t plist;
+
+ /* Disable error reporting */
+ H5Eget_auto_stack(H5E_DEFAULT, &func, &edata);
+ H5Eset_auto_stack(H5E_DEFAULT, NULL, NULL);
+
+ parse_command_line (argc, argv);
+
+ if (argc <= (opt_ind))
+ {
+ error_msg (progname, "missing file name\n");
+ usage (progname);
+ exit (EXIT_FAILURE);
+ }
+
+ ifname = strdup (argv[opt_ind]);
+
+ testval = H5Fis_hdf5 (ifname);
+
+ if (testval <= 0)
+ {
+ error_msg (progname, "Input HDF5 file is not HDF \"%s\"\n", ifname);
+ exit (EXIT_FAILURE);
+ }
+
+ ifile = H5Fopen (ifname, H5F_ACC_RDONLY, H5P_DEFAULT);
+
+ if (ifile < 0)
+ {
+ error_msg (progname, "Can't open input HDF5 file \"%s\"\n", ifname);
+ exit (EXIT_FAILURE);
+ }
+
+ plist = H5Fget_create_plist (ifile);
+ if (plist < 0)
+ {
+ error_msg (progname, "Can't get file creation plist for file \"%s\"\n",
+ ifname);
+ exit (EXIT_FAILURE);
+ }
+
+ status = H5Pget_userblock (plist, &usize);
+ if (status < 0)
+ {
+ error_msg (progname, "Can't get user block for file \"%s\"\n", ifname);
+ exit (EXIT_FAILURE);
+ }
+
+ printf ("%ld\n", (long) usize);
+
+ H5Pclose (plist);
+ H5Fclose (ifile);
+
+ exit (EXIT_SUCCESS);
+}
diff --git a/tools/h5jam/testh5jam.sh.in b/tools/h5jam/testh5jam.sh.in
new file mode 100644
index 0000000..88e9a7c
--- /dev/null
+++ b/tools/h5jam/testh5jam.sh.in
@@ -0,0 +1,527 @@
+#! /bin/sh
+#
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the files COPYING and Copyright.html. COPYING can be found at the root
+# of the source code distribution tree; Copyright.html can be found at the
+# root level of an installed copy of the electronic HDF5 document set and
+# is linked from the top-level documents page. It can also be found at
+# http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have
+# access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu.
+#
+# Tests for the h5dump tool
+
+# Determine which filters are available
+USE_FILTER_SZIP="@USE_FILTER_SZIP@"
+USE_FILTER_DEFLATE="@USE_FILTER_DEFLATE@"
+USE_FILTER_SHUFFLE="@USE_FILTER_SHUFFLE@"
+USE_FILTER_FLETCHER32="@USE_FILTER_FLETCHER32@"
+
+DUMPER=h5dump # The dumper to use
+DUMPER_BIN=`pwd`/../$DUMPER # The path of the dumper binary
+JAM=h5jam # Tool to test
+UNJAM=h5unjam # Tool to test
+JAM_BIN=`pwd` # The path of the jam binary
+UNJAM_BIN=`pwd` # The path of the jam binary
+
+CMP='cmp -s'
+DIFF='diff -c'
+AWK='awk'
+
+nerrors=0
+verbose=yes
+
+# The build (current) directory might be different than the source directory.
+if test -z "$srcdir"; then
+ srcdir=.
+fi
+TESTFILES="$srcdir/../testfiles"
+
+#test -d ../testfiles || mkdir ../testfiles
+
+# Print a line-line message left justified in a field of 70 characters
+# beginning with the word "Testing".
+#
+TESTING() {
+ SPACES=" "
+ echo "Testing $* $SPACES" | cut -c1-70 | tr -d '\012'
+}
+
+# Print a line-line message left justified in a field of 70 characters
+# beginning with the word "Compare".
+#
+COMPARE() {
+ SPACES=" "
+ echo "Compare $* $SPACES" | cut -c1-70 | tr -d '\012'
+}
+
+# Print a "SKIP" message
+SKIP() {
+ TESTING $JAM $@
+ echo " -SKIP-"
+}
+
+#
+# COMPARE_FILES a.h5 b.h5
+# Compare two files, skipping the first line. This is used to
+# compare the output of the dumper, skipping the file name which
+# is different.
+# The result is stored in 'compval'.
+#
+cmpval=0;
+COMPARE_FILES() {
+ $AWK 'NR > 1' $1 > $1.cmp
+ $AWK 'NR > 1' $2 > $2.cmp
+ $CMP $1.cmp $2.cmp
+ cmpval=$?
+ rm -f $1.cmp $2.cmp
+}
+
+# CLEANUP files
+# Clean up named files.
+CLEANUP() {
+ if test -z "$HDF5_NOCLEANUP"; then
+ for i in $*
+ do
+ rm -f $i
+ done
+ fi
+}
+
+# SETUP file tocopy
+# Clone a standard input file in the test directory
+#
+SETUP() {
+ cp $1 $2
+}
+
+#
+# CHECKFILE orig.h5 compar.h5
+# Check that the test file is the same as an original.
+# The two files are dumped with the dumper, and the output
+# compared with COMPARE_FILES.
+# If the files are the same, the test reports " PASSED",
+# otherwise, it reports "*FAILED*"
+CHECKFILE() {
+ expected="`dirname $2`/`basename $2 .h5`.out"
+ expected_err="`dirname $2`/`basename $2 .h5`.err"
+ actual="`basename $1 .h5`.out"
+ actual_err="`basename $1 .h5`.err"
+
+ $RUNSERIAL $DUMPER_BIN/$DUMPER $1 >$expected 2>$expected_err
+ cat $expected_err >> $expected
+
+ # dump the test file
+ COMPARE $2 to $1
+ $RUNSERIAL $DUMPER_BIN/$DUMPER $2 >$actual 2>$actual_err
+ cat $actual_err >> $actual
+
+ # compare the two files (ignore line 1)
+ COMPARE_FILES $actual $expected
+ if [ "$cmpval" = 0 ] ; then
+ echo " PASSED"
+ else
+ echo "*FAILED*"
+ echo " Expected result (*.ddl) differs from actual result (*.out)"
+ nerrors="`expr $nerrors + 1`"
+ test yes = "$verbose" && $DIFF $expected $actual |sed 's/^/ /'
+ fi
+
+ # Clean up output files
+ if test -z "$HDF5_NOCLEANUP"; then
+ rm -f $actual $actual_err
+ rm -f $expected $expected_err
+ fi
+}
+
+#
+# CHECK_UB file.h5 user_block_file origfile.h5
+#
+# Check the user block in 'file.h5' is the same as
+# 'user_block' (allowing for padding).
+#
+# If the original file had a user block before the test
+# then 'compare.h5' is passed. The user block must be extracted
+# and the test file compared to:
+# cat compare_ub user_block_file.
+#
+# This test uses './getub' to extract the user block from
+# 'file.h5', which is compared to the file described above.
+#
+# The result is set in variable 'result1'.
+#
+result1=0;
+CHECK_UB_1() {
+ hfile="$1"
+ ufile="$2"
+
+ # check for third argument (the original file)
+ origfile="";
+ if [ -n "$3" ];
+ then
+ origfile="$3"
+ fi
+
+ # find the length of the user block to check
+ s1=`cat $ufile | wc -c | sed -e 's/ //g'`
+ if [ "$s1" = "0" ];
+ then
+ echo "File "$ufile" is empty"
+ result1=1;
+ fi
+
+ # Get the size of the original user block, if any.
+ if [ -n "$origfile" ];
+ then
+ # 'tellub' calls H5Fget_user_block to get the size
+ # of the user block
+ s2=`$JAM_BIN/tellub $origfile`
+ if [ "$s2" = "0" ];
+ then
+ size=$s1;
+ cmpfile=$ufile
+ else
+ cmpfile="tt2"
+ size=`expr $s2 + $s1`
+ ./getub -c $s2 $origfile > $cmpfile
+ cat $ufile >> $cmpfile
+ fi
+ else
+ # assume no user block
+ s2="0"
+ size=$s1;
+ cmpfile=$ufile
+ fi
+
+ # Extract 'size' bytes from the front of 'hfile'
+ # Compare to 'cmpfile', result is set in result1
+ tfile="tt1"
+ ./getub -c $size $hfile > $tfile
+ res=`cmp $cmpfile $tfile`
+ if [ "$?" != "0" ];
+ then
+ echo $res
+ result1=1;
+ else
+ result1=0;
+ fi
+
+ # clean up
+ rm -f $tfile
+ if [ "$s2" != "0" ] ;
+ then
+ rm -f $cmpfile
+ fi
+}
+
+
+# CHECK_NOUB file.h5
+#
+# Check that 'file.h5' has no user block.
+# Setst result2 to 1 if there is a user block (fail), 0 if none (pass)
+
+result2=0;
+
+CHECK_NOUB() {
+ hfile="$1"
+
+ # call 'ubsize' to get the size of the user block
+ ubsize=`$JAM_BIN/tellub $hfile`
+
+ if [ "$?" != "0" ];
+ then
+ # error
+ result2=1;
+ else
+ if [ "$ubsize" = "0" ];
+ then
+ # pass
+ result2=0;
+ else
+ # fail
+ result2=1;
+ fi
+ fi
+}
+
+# JAMTEST user_block file.h5 [--clobber] [ofile.h5]
+#
+# Test the 'jam' tool:
+# 1. figure out the input and output, and the comparision
+# that will be done.
+# 2. call 'jam' with the appropriate arguments
+# 3. check the user block is correct in the output (Check_UB)
+# If the user block is correct, print "PASSED", else "*FAILED*"
+JAMTEST() {
+ ufile="$1"
+ ifile="$2"
+ compare_test="" # the file to test
+ compare_orig="" # the comparison to test against
+ cleanup=""
+
+ # sort out the arguments for the test and the check
+ do_clobber="no"
+ if [ "$3" = "--clobber" ];
+ then
+ # clobber overwrites any existing user block
+ do_clobber="yes"
+ clobber="--clobber"
+ compare_orig=""
+ if [ -z "$4" ];
+ then
+ # output goes to infile, compare ubfile to infile
+ ofile=""
+ compare_test="$ifile"
+ else
+ # output goes to $4, compare ofile to ubfile
+ ofile="$4"
+ compare_test="$ofile"
+ fi
+ else
+ clobber=""
+ # add user block to existing ub, if any
+ if [ -z "$3" ];
+ then
+ # output goes to infile, compare ubfile to infile
+ ofile=""
+ compare_test="$ifile"
+ cp $ifile xxofile.h5
+ compare_orig="xxofile.h5"
+ cleanup="$cleanup $compare_orig"
+ else
+ # output goes to $4, compare ofile to ubfile
+ ofile="$3"
+ compare_test="$ofile"
+ compare_orig="$ifile"
+ fi
+ fi
+
+ # call 'jam' with the appropriate arguments
+ if [ -n "$ofile" ];
+ then
+ TESTING h5jam -u `basename $ufile` -i `basename $ifile` -o `basename $ofile` $clobber
+ $JAM_BIN/$JAM -u $ufile -i $ifile -o $ofile $clobber
+ else
+ TESTING jam -u `basename $ufile` -i `basename $ifile` $clobber
+ $JAM_BIN/$JAM -u $ufile -i $ifile $clobber
+ fi
+
+ #echo "CHECK_UB_1 $compare_test $ufile $compare_orig"
+ CHECK_UB_1 $compare_test $ufile $compare_orig
+
+ if [ "$result1" = "0" ] ;
+ then
+ echo " PASSED"
+ else
+ echo " *FAILED*"
+ nerrors="`expr $nerrors + 1`"
+ fi
+ CLEANUP $cleanup
+}
+
+# UNJAMTEST file.h5 [- | --delete] ofile
+#
+# Test the 'unjam' tool
+#
+###fix the working directory here and in jamtest
+UNJAMTEST () {
+ infile="$1"
+ ofile="$3"
+ if [ "$2" = "-" ];
+ then
+ uofile="uofile"
+ TESTING h5unjam -i `basename $infile` -o `basename $ofile` "> "`basename $uofile`
+ $JAM_BIN/$UNJAM -i $infile -o $ofile > $uofile
+ else
+ if [ "$2" = "--delete" ];
+ then
+ uofile="none"
+ TESTING h5unjam -i `basename $infile` -o `basename $ofile` --delete
+ $JAM_BIN/$UNJAM -i $infile -o $ofile --delete
+
+ else
+ uofile="$2"
+ TESTING h5unjam -i `basename $infile` -u `basename $uofile` -o `basename $ofile`
+ $JAM_BIN/$UNJAM -i $infile -u $uofile -o $ofile
+ fi
+ fi
+
+ result1=0
+ result2=0
+ cleanup=""
+ if [ "$uofile" != "none" ];
+ then
+ # sets result1
+ CHECK_UB_1 $infile $uofile
+ CLEANUP $uofile
+ fi
+
+ # sets result2
+ CHECK_NOUB $ofile
+
+ if [ "$result1" = "0" -a "$result2" = "0" ];
+ then
+ echo " PASSED"
+ else
+ echo " *FAILED*"
+ nerrors="`expr $nerrors + 1`"
+ fi
+}
+
+
+##############################################################################
+##############################################################################
+### T H E T E S T S ###
+##############################################################################
+##############################################################################
+
+JAMTEST $TESTFILES/u10.txt $TESTFILES/tall.h5 ta2.h5
+CHECKFILE $TESTFILES/tall.h5 ta2.h5
+CLEANUP ta2.h5
+JAMTEST $TESTFILES/u511.txt $TESTFILES/tall.h5 ta3.h5
+CHECKFILE $TESTFILES/tall.h5 ta3.h5
+CLEANUP ta3.h5
+JAMTEST $TESTFILES/u512.txt $TESTFILES/tall.h5 ta4.h5
+CHECKFILE $TESTFILES/tall.h5 ta4.h5
+CLEANUP ta4.h5
+JAMTEST $TESTFILES/u513.txt $TESTFILES/tall.h5 ta5.h5
+CHECKFILE $TESTFILES/tall.h5 ta5.h5
+CLEANUP ta5.h5
+
+SETUP $TESTFILES/tall.h5 ta.h5
+JAMTEST $TESTFILES/u10.txt ta.h5
+CHECKFILE $TESTFILES/tall.h5 ta.h5
+SETUP $TESTFILES/tall.h5 ta.h5
+JAMTEST $TESTFILES/u511.txt ta.h5
+CHECKFILE $TESTFILES/tall.h5 ta.h5
+SETUP $TESTFILES/tall.h5 ta.h5
+JAMTEST $TESTFILES/u512.txt ta.h5
+CHECKFILE $TESTFILES/tall.h5 ta.h5
+SETUP $TESTFILES/tall.h5 ta.h5
+JAMTEST $TESTFILES/u513.txt ta.h5
+CHECKFILE $TESTFILES/tall.h5 ta.h5
+CLEANUP ta.h5
+
+JAMTEST $TESTFILES/u10.txt $TESTFILES/twithub.h5 tax2.h5
+CHECKFILE $TESTFILES/tall.h5 tax2.h5
+CLEANUP tax2.h5
+JAMTEST $TESTFILES/u511.txt $TESTFILES/twithub.h5 tax3.h5
+CHECKFILE $TESTFILES/tall.h5 tax3.h5
+CLEANUP tax3.h5
+JAMTEST $TESTFILES/u512.txt $TESTFILES/twithub.h5 tax4.h5
+CHECKFILE $TESTFILES/tall.h5 tax4.h5
+CLEANUP tax4.h5
+JAMTEST $TESTFILES/u513.txt $TESTFILES/twithub.h5 tax5.h5
+CHECKFILE $TESTFILES/tall.h5 tax5.h5
+CLEANUP tax5.h5
+
+JAMTEST $TESTFILES/u10.txt $TESTFILES/twithub513.h5 tax6.h5
+CHECKFILE $TESTFILES/tall.h5 tax6.h5
+CLEANUP tax6.h5
+JAMTEST $TESTFILES/u511.txt $TESTFILES/twithub513.h5 tax7.h5
+CHECKFILE $TESTFILES/tall.h5 tax7.h5
+CLEANUP tax7.h5
+JAMTEST $TESTFILES/u512.txt $TESTFILES/twithub513.h5 tax8.h5
+CHECKFILE $TESTFILES/tall.h5 tax8.h5
+CLEANUP tax8.h5
+JAMTEST $TESTFILES/u513.txt $TESTFILES/twithub513.h5 tax9.h5
+CHECKFILE $TESTFILES/tall.h5 tax9.h5
+CLEANUP tax9.h5
+
+JAMTEST $TESTFILES/u10.txt $TESTFILES/twithub.h5 --clobber taz2.h5
+CHECKFILE $TESTFILES/tall.h5 taz2.h5
+CLEANUP taz2.h5
+JAMTEST $TESTFILES/u511.txt $TESTFILES/twithub.h5 --clobber taz3.h5
+CHECKFILE $TESTFILES/tall.h5 taz3.h5
+CLEANUP taz3.h5
+JAMTEST $TESTFILES/u512.txt $TESTFILES/twithub.h5 --clobber taz4.h5
+CHECKFILE $TESTFILES/tall.h5 taz4.h5
+CLEANUP taz4.h5
+JAMTEST $TESTFILES/u513.txt $TESTFILES/twithub.h5 --clobber taz5.h5
+CHECKFILE $TESTFILES/tall.h5 taz5.h5
+CLEANUP taz5.h5
+
+JAMTEST $TESTFILES/u10.txt $TESTFILES/twithub513.h5 --clobber taz6.h5
+CHECKFILE $TESTFILES/tall.h5 taz6.h5
+CLEANUP taz6.h5
+JAMTEST $TESTFILES/u511.txt $TESTFILES/twithub513.h5 --clobber taz7.h5
+CHECKFILE $TESTFILES/tall.h5 taz7.h5
+CLEANUP taz7.h5
+JAMTEST $TESTFILES/u512.txt $TESTFILES/twithub513.h5 --clobber taz8.h5
+CHECKFILE $TESTFILES/tall.h5 taz8.h5
+CLEANUP taz8.h5
+JAMTEST $TESTFILES/u513.txt $TESTFILES/twithub513.h5 --clobber taz9.h5
+CHECKFILE $TESTFILES/tall.h5 taz9.h5
+CLEANUP taz9.h5
+
+SETUP $TESTFILES/twithub.h5 tay2.h5
+JAMTEST $TESTFILES/u10.txt tay2.h5 --clobber
+CHECKFILE $TESTFILES/tall.h5 tay2.h5
+CLEANUP tay2.h5
+SETUP $TESTFILES/twithub.h5 tay3.h5
+JAMTEST $TESTFILES/u511.txt tay3.h5 --clobber
+CHECKFILE $TESTFILES/tall.h5 tay3.h5
+CLEANUP tay3.h5
+SETUP $TESTFILES/twithub.h5 tay4.h5
+JAMTEST $TESTFILES/u512.txt tay4.h5 --clobber
+CHECKFILE $TESTFILES/tall.h5 tay4.h5
+CLEANUP tay4.h5
+SETUP $TESTFILES/twithub.h5 tay5.h5
+JAMTEST $TESTFILES/u513.txt tay5.h5 --clobber
+CHECKFILE $TESTFILES/tall.h5 tay5.h5
+CLEANUP tay5.h5
+
+SETUP $TESTFILES/twithub513.h5 tay6.h5
+JAMTEST $TESTFILES/u10.txt tay6.h5 --clobber
+CHECKFILE $TESTFILES/tall.h5 tay6.h5
+CLEANUP tay6.h5
+SETUP $TESTFILES/twithub513.h5 tay7.h5
+JAMTEST $TESTFILES/u511.txt tay7.h5 --clobber
+CHECKFILE $TESTFILES/tall.h5 tay7.h5
+CLEANUP tay7.h5
+SETUP $TESTFILES/twithub513.h5 tay8.h5
+JAMTEST $TESTFILES/u512.txt tay8.h5 --clobber
+CHECKFILE $TESTFILES/tall.h5 tay8.h5
+CLEANUP tay8.h5
+SETUP $TESTFILES/twithub513.h5 tay9.h5
+JAMTEST $TESTFILES/u513.txt tay9.h5 --clobber
+CHECKFILE $TESTFILES/tall.h5 tay9.h5
+CLEANUP tay9.h5
+
+SETUP $TESTFILES/twithub.h5 tai1.h5
+UNJAMTEST tai1.h5 o10.txt taa1.h5
+CHECKFILE $TESTFILES/tall.h5 taa1.h5
+CLEANUP taa1.h5 tai1.h5 o10.txt
+SETUP $TESTFILES/twithub513.h5 tai2.h5
+UNJAMTEST tai2.h5 o512.txt taa2.h5
+CHECKFILE $TESTFILES/tall.h5 taa2.h5
+CLEANUP taa2.h5 tai2.h5 o512.txt
+
+SETUP $TESTFILES/twithub.h5 tai3.h5
+UNJAMTEST tai3.h5 - taa3.h5
+CHECKFILE $TESTFILES/tall.h5 taa3.h5
+CLEANUP taa3.h5 tai3.h5
+SETUP $TESTFILES/twithub513.h5 tai4.h5
+UNJAMTEST tai4.h5 - taa4.h5
+CHECKFILE $TESTFILES/tall.h5 taa4.h5
+CLEANUP taa4.h5 tai4.h5
+
+SETUP $TESTFILES/twithub.h5 taj2.h5
+UNJAMTEST taj2.h5 --delete tac2.h5
+CHECKFILE $TESTFILES/tall.h5 tac2.h5
+CLEANUP tac2.h5 taj2.h5
+SETUP $TESTFILES/twithub513.h5 taj3.h5
+UNJAMTEST taj3.h5 --delete tac3.h5
+CHECKFILE $TESTFILES/tall.h5 tac3.h5
+CLEANUP tac3.h5 taj3.h5
+
+
+
+if test $nerrors -eq 0 ; then
+ echo "All $JAM tests passed."
+fi
+
+exit $nerrors
diff --git a/tools/testfiles/twithub.h5 b/tools/testfiles/twithub.h5
new file mode 100644
index 0000000..105319f
--- /dev/null
+++ b/tools/testfiles/twithub.h5
Binary files differ
diff --git a/tools/testfiles/twithub513.h5 b/tools/testfiles/twithub513.h5
new file mode 100644
index 0000000..8b6a2e2
--- /dev/null
+++ b/tools/testfiles/twithub513.h5
Binary files differ
diff --git a/tools/testfiles/u10.txt b/tools/testfiles/u10.txt
new file mode 100755
index 0000000..c76a964
--- /dev/null
+++ b/tools/testfiles/u10.txt
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tools/testfiles/u511.txt b/tools/testfiles/u511.txt
new file mode 100755
index 0000000..bff1736
--- /dev/null
+++ b/tools/testfiles/u511.txt
@@ -0,0 +1 @@
+abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghija \ No newline at end of file
diff --git a/tools/testfiles/u512.txt b/tools/testfiles/u512.txt
new file mode 100755
index 0000000..33a36c9
--- /dev/null
+++ b/tools/testfiles/u512.txt
@@ -0,0 +1 @@
+abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijab \ No newline at end of file
diff --git a/tools/testfiles/u513.txt b/tools/testfiles/u513.txt
new file mode 100755
index 0000000..6b46ebf
--- /dev/null
+++ b/tools/testfiles/u513.txt
@@ -0,0 +1 @@
+abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabc \ No newline at end of file