diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/H5A.c | 19 | ||||
-rw-r--r-- | src/H5AC2.c | 425 | ||||
-rw-r--r-- | src/H5AC2private.h | 40 | ||||
-rw-r--r-- | src/H5AC2public.h | 66 | ||||
-rw-r--r-- | src/H5ACprivate.h | 12 | ||||
-rw-r--r-- | src/H5ACpublic.h | 20 | ||||
-rw-r--r-- | src/H5Adeprec.c | 3 | ||||
-rw-r--r-- | src/H5C2.c | 2780 | ||||
-rw-r--r-- | src/H5C2journal.c | 1025 | ||||
-rw-r--r-- | src/H5C2pkg.h | 3271 | ||||
-rw-r--r-- | src/H5C2private.h | 118 | ||||
-rw-r--r-- | src/H5D.c | 9 | ||||
-rw-r--r-- | src/H5Ddeprec.c | 5 | ||||
-rw-r--r-- | src/H5Dio.c | 3 | ||||
-rw-r--r-- | src/H5F.c | 38 | ||||
-rw-r--r-- | src/H5FDpublic.h | 15 | ||||
-rw-r--r-- | src/H5Fmount.c | 15 | ||||
-rw-r--r-- | src/H5G.c | 8 | ||||
-rw-r--r-- | src/H5Gdeprec.c | 15 | ||||
-rw-r--r-- | src/H5I.c | 5 | ||||
-rw-r--r-- | src/H5L.c | 15 | ||||
-rw-r--r-- | src/H5Lexternal.c | 5 | ||||
-rw-r--r-- | src/H5O.c | 16 | ||||
-rw-r--r-- | src/H5Ocopy.c | 4 | ||||
-rw-r--r-- | src/H5R.c | 3 | ||||
-rw-r--r-- | src/H5T.c | 3 | ||||
-rw-r--r-- | src/H5Tcommit.c | 5 | ||||
-rw-r--r-- | src/H5Tdeprec.c | 3 | ||||
-rw-r--r-- | src/H5private.h | 25 |
29 files changed, 5321 insertions, 2650 deletions
@@ -36,6 +36,7 @@ #include "H5MMprivate.h" /* Memory management */ #include "H5Sprivate.h" /* Dataspace functions */ #include "H5SMprivate.h" /* Shared Object Header Messages */ +#include "H5AC2private.h" /* Metadata cache */ /****************/ /* Local Macros */ @@ -222,7 +223,7 @@ H5Acreate2(hid_t loc_id, const char *attr_name, hid_t type_id, hid_t space_id, H5S_t *space; /* Dataspace to use for attribute */ hid_t ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Acreate2, FAIL) + FUNC_ENTER_API_META(H5Acreate2, loc_id, FAIL) H5TRACE6("i", "i*siiii", loc_id, attr_name, type_id, space_id, acpl_id, aapl_id); /* check arguments */ @@ -293,7 +294,7 @@ H5Acreate_by_name(hid_t loc_id, const char *obj_name, const char *attr_name, H5S_t *space; /* Dataspace to use for attribute */ hid_t ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Acreate_by_name, FAIL) + FUNC_ENTER_API_META(H5Acreate_by_name, loc_id, FAIL) H5TRACE8("i", "i*s*siiiii", loc_id, obj_name, attr_name, type_id, space_id, acpl_id, aapl_id, lapl_id); @@ -904,7 +905,7 @@ H5Awrite(hid_t attr_id, hid_t dtype_id, const void *buf) const H5T_t *mem_type = NULL; herr_t ret_value; - FUNC_ENTER_API_META(H5Awrite, FAIL) + FUNC_ENTER_API_META(H5Awrite, attr_id, FAIL) H5TRACE3("e", "ii*x", attr_id, dtype_id, buf); /* check arguments */ @@ -1724,7 +1725,7 @@ H5Arename(hid_t loc_id, const char *old_name, const char *new_name) H5G_loc_t loc; /* Object location */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Arename, FAIL) + FUNC_ENTER_API_META(H5Arename, loc_id, FAIL) H5TRACE3("e", "i*s*s", loc_id, old_name, new_name); /* check arguments */ @@ -1770,7 +1771,7 @@ H5Arename_by_name(hid_t loc_id, const char *obj_name, const char *old_attr_name, hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Arename_by_name, FAIL) + FUNC_ENTER_API_META(H5Arename_by_name, loc_id, FAIL) H5TRACE5("e", "i*s*s*si", loc_id, obj_name, old_attr_name, new_attr_name, lapl_id); @@ -2036,7 +2037,7 @@ H5Adelete(hid_t loc_id, const char *name) H5G_loc_t loc; /* Object location */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Adelete, FAIL) + FUNC_ENTER_API_META(H5Adelete, loc_id, FAIL) H5TRACE2("e", "i*s", loc_id, name); /* check arguments */ @@ -2083,7 +2084,7 @@ H5Adelete_by_name(hid_t loc_id, const char *obj_name, const char *attr_name, hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Adelete_by_name, FAIL) + FUNC_ENTER_API_META(H5Adelete_by_name, loc_id, FAIL) H5TRACE4("e", "i*s*si", loc_id, obj_name, attr_name, lapl_id); /* check arguments */ @@ -2159,7 +2160,7 @@ H5Adelete_by_idx(hid_t loc_id, const char *obj_name, H5_index_t idx_type, hbool_t loc_found = FALSE; /* Entry at 'obj_name' found */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Adelete_by_idx, FAIL) + FUNC_ENTER_API_META(H5Adelete_by_idx, loc_id, FAIL) H5TRACE6("e", "i*sIiIohi", loc_id, obj_name, idx_type, order, n, lapl_id); /* check arguments */ @@ -2222,7 +2223,7 @@ H5Aclose(hid_t attr_id) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Aclose, FAIL) + FUNC_ENTER_API_META(H5Aclose, attr_id, FAIL) H5TRACE1("e", "i", attr_id); /* check arguments */ diff --git a/src/H5AC2.c b/src/H5AC2.c index 4a63c7c..adda9b1 100644 --- a/src/H5AC2.c +++ b/src/H5AC2.c @@ -481,6 +481,10 @@ H5AC2_term_interface(void) * API. * JRM - 10/18/07 * + * Added the dxpl_id parameter, and updated for parameter + * list changes in H5C2_create(). + * JRM - 3/26/08 + * *------------------------------------------------------------------------- */ @@ -505,8 +509,9 @@ static const char * H5AC2_entry_type_names[H5AC2_NTYPES] = }; herr_t -H5AC2_create(const H5F_t *f, - H5AC2_cache_config_t *config_ptr) +H5AC2_create(H5F_t * f, + hid_t dxpl_id, + H5AC2_cache_config_t *config_ptr) { herr_t ret_value = SUCCEED; /* Return value */ herr_t result; @@ -617,18 +622,23 @@ H5AC2_create(const H5F_t *f, if ( aux_ptr->mpi_rank == 0 ) { - f->shared->cache2 = H5C2_create(H5AC2__DEFAULT_MAX_CACHE_SIZE, + f->shared->cache2 = H5C2_create(f, + dxpl_id, + H5AC2__DEFAULT_MAX_CACHE_SIZE, H5AC2__DEFAULT_MIN_CLEAN_SIZE, (H5AC2_NTYPES - 1), (const char **)H5AC2_entry_type_names, H5AC2_check_if_write_permitted, TRUE, H5AC2_log_flushed_entry, - (void *)aux_ptr); + (void *)aux_ptr, + config_ptr->journal_recovered); } else { - f->shared->cache2 = H5C2_create(H5AC2__DEFAULT_MAX_CACHE_SIZE, + f->shared->cache2 = H5C2_create(f, + dxpl_id, + H5AC2__DEFAULT_MAX_CACHE_SIZE, H5AC2__DEFAULT_MIN_CLEAN_SIZE, (H5AC2_NTYPES - 1), (const char **)H5AC2_entry_type_names, @@ -639,19 +649,23 @@ H5AC2_create(const H5F_t *f, #else /* JRM */ NULL, #endif /* JRM */ - (void *)aux_ptr); + (void *)aux_ptr, + config_ptr->journal_recovered); } } else { - f->shared->cache2 = H5C2_create(H5AC2__DEFAULT_MAX_CACHE_SIZE, + f->shared->cache2 = H5C2_create(f, + dxpl_id, + H5AC2__DEFAULT_MAX_CACHE_SIZE, H5AC2__DEFAULT_MIN_CLEAN_SIZE, (H5AC2_NTYPES - 1), (const char **)H5AC2_entry_type_names, H5AC2_check_if_write_permitted, TRUE, NULL, - NULL); + NULL, + config_ptr->journal_recovered); } } else { #endif /* H5_HAVE_PARALLEL */ @@ -660,14 +674,17 @@ H5AC2_create(const H5F_t *f, * -- JRM */ - f->shared->cache2 = H5C2_create(H5AC2__DEFAULT_MAX_CACHE_SIZE, + f->shared->cache2 = H5C2_create(f, + dxpl_id, + H5AC2__DEFAULT_MAX_CACHE_SIZE, H5AC2__DEFAULT_MIN_CLEAN_SIZE, (H5AC2_NTYPES - 1), (const char **)H5AC2_entry_type_names, H5AC2_check_if_write_permitted, TRUE, NULL, - NULL); + NULL, + config_ptr->journal_recovered); #ifdef H5_HAVE_PARALLEL } #endif /* H5_HAVE_PARALLEL */ @@ -690,7 +707,9 @@ H5AC2_create(const H5F_t *f, } #endif /* H5_HAVE_PARALLEL */ - result = H5AC2_set_cache_auto_resize_config(f, config_ptr); + result = H5AC2_set_cache_auto_resize_config(f, + dxpl_id, + config_ptr); if ( result != SUCCEED ) { @@ -833,6 +852,258 @@ done: /*------------------------------------------------------------------------- + * Function: H5AC2_begin_transaction() + * + * Purpose: Mark the beginning of a transaction. + * + * This function is just a wrapper for H5C2_begin_transaction(). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 4/12/08 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_begin_transaction(hid_t id, + hbool_t * do_transaction_ptr, + H5O_loc_t * id_oloc_ptr, + hbool_t * id_oloc_open_ptr, + hbool_t * transaction_begun_ptr, + uint64_t * trans_num_ptr, + const char * api_call_name) +{ + herr_t result; + H5G_loc_t id_loc; + H5F_t * f = NULL; + H5AC2_t * cache_ptr = NULL; + herr_t ret_value = SUCCEED; /* Return value */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[256] = ""; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_begin_transaction, FAIL) + + HDassert( do_transaction_ptr != NULL ); + HDassert( id_oloc_ptr != NULL ); + HDassert( id_oloc_open_ptr != NULL ); + HDassert( transaction_begun_ptr != NULL ); + HDassert( trans_num_ptr != NULL ); + HDassert( api_call_name != NULL ); + +#if H5AC2__TRACE_FILE_ENABLED + /* For the begin transaction call, only the transaction number and the + * api call name. Write the return value to catch occult errors. + */ + if ( ( cache_ptr != NULL ) && + ( H5C2_get_trace_file_ptr(cache_ptr, &trace_file_ptr) >= 0 ) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_begin_transaction %s", api_call_name); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + *id_oloc_open_ptr = FALSE; + *transaction_begun_ptr = FALSE; + + switch ( H5I_get_type(id) ) + { + case H5I_DATASPACE: + case H5I_ERROR_CLASS: + case H5I_ERROR_MSG: + case H5I_ERROR_STACK: + case H5I_GENPROP_CLS: + case H5I_GENPROP_LST: + *do_transaction_ptr = FALSE; + break; + + case H5I_DATATYPE: + { + H5T_t *dt = H5I_object(id); + if( ( dt == NULL ) || ( ! H5T_committed(dt) ) ) { + *do_transaction_ptr = FALSE; + } + } + break; + + case H5I_BADID: + *do_transaction_ptr = FALSE; + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, \ + "H5I_get_type() reports bad id") + break; + + default: + *do_transaction_ptr = TRUE; + } + + if ( *do_transaction_ptr ) { + + if ((H5G_loc((id), &id_loc) < 0) || (id_loc.oloc == NULL)) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "H5G_loc() failed"); + } + + *id_oloc_ptr = *(id_loc.oloc); + + if ( H5O_open(id_oloc_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, "H5O_open() failed."); + } + + *id_oloc_open_ptr = TRUE; + + f = id_oloc_ptr->file; + + if ( ( f == NULL ) || + ( f->shared == NULL ) || + ( f->shared->cache2 == NULL ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, "can't get cache_ptr."); + } + + cache_ptr = f->shared->cache2; + + result = H5C2_begin_transaction(cache_ptr, trans_num_ptr, api_call_name); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_begin_transaction() failed.") + } + + *transaction_begun_ptr = TRUE; + } + +done: + + *trans_num_ptr = 1; + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %llu %d\n", trace, + *trans_num_ptr, (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_begin_transaction() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_end_transaction() + * + * Purpose: Mark the end of a transaction. + * + * This function is just a wrapper for H5C2_end_transaction(). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 4/12/08 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_end_transaction(hbool_t do_transaction, + H5O_loc_t * id_oloc_ptr, + hbool_t id_oloc_open, + hbool_t transaction_begun, + uint64_t trans_num, + const char * api_call_name) +{ + herr_t result; + herr_t ret_value=SUCCEED; /* Return value */ + H5F_t * f = NULL; + H5AC2_t * cache_ptr = NULL; +#if H5AC2__TRACE_FILE_ENABLED + char trace[256] = ""; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_end_transaction, FAIL) + + HDassert( id_oloc_ptr != NULL ); + HDassert( api_call_name != NULL ); + +#if H5AC2__TRACE_FILE_ENABLED + /* For the end transaction call, only the transaction number and the + * api call name are really needed. Write the return value to catch + * occult errors. + */ + if ( ( cache_ptr != NULL ) && + ( H5C2_get_trace_file_ptr(cache_ptr, &trace_file_ptr) >= 0 ) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_end_transaction %s %llu", api_call_name, trans_num); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + if ( do_transaction ) { + + if ( transaction_begun ) { + + f = id_oloc_ptr->file; + + if ( ( f == NULL ) || + ( f->shared == NULL ) || + ( f->shared->cache2 == NULL ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "can't get cache_ptr."); + } + + cache_ptr = f->shared->cache2; + + result = H5C2_end_transaction(f, cache_ptr, trans_num, api_call_name); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_end_transaction() failed.") + } + } + + if ( id_oloc_open ) { + + result = H5O_close(id_oloc_ptr); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5O_close() failed."); + } + } + } + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_end_transaction() */ + + +/*------------------------------------------------------------------------- * Function: H5AC2_expunge_entry * * Purpose: Expunge the target entry from the cache without writing it @@ -1013,6 +1284,7 @@ H5AC2_flush(H5F_t *f, hid_t dxpl_id, unsigned flags) FUNC_ENTER_NOAPI(H5AC2_flush, FAIL) HDassert(f); + HDassert(f->shared); HDassert(f->shared->cache2); #if H5AC2__TRACE_FILE_ENABLED @@ -1164,7 +1436,9 @@ H5AC2_get_entry_status(H5F_t * f, FUNC_ENTER_NOAPI(H5AC2_get_entry_status, FAIL) - if ( ( f->shared->cache2 == NULL ) || + if ( ( f == NULL ) || + ( f->shared == NULL ) || + ( f->shared->cache2 == NULL ) || ( f->shared->cache2->magic != H5C2__H5C2_T_MAGIC ) || ( ! H5F_addr_defined(addr) ) || ( status_ptr == NULL ) ) { @@ -1290,6 +1564,7 @@ H5AC2_set(H5F_t *f, hid_t dxpl_id, const H5AC2_class_t *type, haddr_t addr, size FUNC_ENTER_NOAPI(H5AC2_set, FAIL) HDassert(f); + HDassert(f->shared); HDassert(f->shared->cache2); HDassert(type); HDassert(type->serialize); @@ -1426,7 +1701,7 @@ H5AC2_mark_pinned_entry_dirty(H5F_t * f, size_t new_size) { #ifdef H5_HAVE_PARALLEL - H5C2_t *cache_ptr = f->shared->cache2; + H5C2_t *cache_ptr; #endif /* H5_HAVE_PARALLEL */ herr_t result; herr_t ret_value = SUCCEED; /* Return value */ @@ -1437,6 +1712,10 @@ H5AC2_mark_pinned_entry_dirty(H5F_t * f, FUNC_ENTER_NOAPI(H5AC2_mark_pinned_entry_dirty, FAIL) + HDassert( f ); + HDassert( f->shared ); + HDassert( f->shared->cache2 ); + #if H5AC2__TRACE_FILE_ENABLED /* For the mark pinned entry dirty call, only the addr, size_changed, * and new_size are really necessary in the trace file. Write the result @@ -1457,6 +1736,8 @@ H5AC2_mark_pinned_entry_dirty(H5F_t * f, #ifdef H5_HAVE_PARALLEL + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( thing ); @@ -1549,7 +1830,7 @@ H5AC2_mark_pinned_or_protected_entry_dirty(H5F_t * f, void * thing) { #ifdef H5_HAVE_PARALLEL - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; H5AC2_info_t * info_ptr; #endif /* H5_HAVE_PARALLEL */ herr_t result; @@ -1560,6 +1841,10 @@ H5AC2_mark_pinned_or_protected_entry_dirty(H5F_t * f, #endif /* H5AC2__TRACE_FILE_ENABLED */ FUNC_ENTER_NOAPI(H5AC2_mark_pinned_or_protected_entry_dirty, FAIL) + + HDassert( f ); + HDassert( f->shared ); + HDassert( f->shared->cache2 ); #if H5AC2__TRACE_FILE_ENABLED /* For the mark pinned or protected entry dirty call, only the addr @@ -1579,6 +1864,8 @@ H5AC2_mark_pinned_or_protected_entry_dirty(H5F_t * f, #ifdef H5_HAVE_PARALLEL + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( thing ); @@ -2054,7 +2341,7 @@ H5AC2_resize_pinned_entry(H5F_t * f, size_t new_size) { #ifdef H5_HAVE_PARALLEL - H5C2_t *cache_ptr = f->shared->cache2; + H5C2_t *cache_ptr; #endif /* H5_HAVE_PARALLEL */ herr_t result; herr_t ret_value = SUCCEED; /* Return value */ @@ -2065,6 +2352,10 @@ H5AC2_resize_pinned_entry(H5F_t * f, FUNC_ENTER_NOAPI(H5AC2_resize_pinned_entry, FAIL) + HDassert( f ); + HDassert( f->shared ); + HDassert( f->shared->cache2 ); + #if H5AC2__TRACE_FILE_ENABLED /* For the resize pinned entry call, only the addr, and new_size are * really necessary in the trace file. Write the result to catch @@ -2084,6 +2375,8 @@ H5AC2_resize_pinned_entry(H5F_t * f, #ifdef H5_HAVE_PARALLEL + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( thing ); @@ -2334,6 +2627,7 @@ H5AC2_unprotect(H5F_t *f, hid_t dxpl_id, const H5AC2_class_t *type, FUNC_ENTER_NOAPI(H5AC2_unprotect, FAIL) HDassert(f); + HDassert(f->shared); HDassert(f->shared->cache2); HDassert(type); HDassert(type->deserialize); @@ -2536,6 +2830,7 @@ H5AC2_stats(const H5F_t *f) FUNC_ENTER_NOAPI(H5AC2_stats, FAIL) HDassert(f); + HDassert(f->shared); HDassert(f->shared->cache2); /* at present, this can't fail */ @@ -2586,6 +2881,9 @@ done: * Added support for the new flash cache increment related * fields. * + * JRM -- 4/12/08 + * Added support for the new journaling control fields. + * *------------------------------------------------------------------------- */ @@ -2692,6 +2990,32 @@ H5AC2_get_cache_auto_resize_config(H5AC2_t * cache_ptr, } #endif /* H5_HAVE_PARALLEL */ + /* get the current journal configuration. Start by setting defaults, + * which may be changed shortly. + */ + + config_ptr->enable_journaling = FALSE; + config_ptr->journal_file_path[0] = '\0'; + config_ptr->journal_recovered = FALSE; + config_ptr->jbrb_buf_size = 4096; + config_ptr->jbrb_num_bufs = 1; + config_ptr->jbrb_use_aio = FALSE; + config_ptr->jbrb_human_readable = FALSE; + + result = H5C2_get_journal_config(cache_ptr, + &(config_ptr->enable_journaling), + &(config_ptr->journal_file_path[0]), + &(config_ptr->jbrb_buf_size), + &(config_ptr->jbrb_num_bufs), + &(config_ptr->jbrb_use_aio), + &(config_ptr->jbrb_human_readable)); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_get_journal_config() failed.") + } + done: FUNC_LEAVE_NOAPI(ret_value) @@ -2874,17 +3198,23 @@ done: * Updated trace file code to record the new flash cache * size increase related fields. * + * John Mainzer -- 4/13/08 + * Added code to allow control of metadata journaling. + * This required the addition of the dxpl_id parameter. + * *------------------------------------------------------------------------- */ herr_t H5AC2_set_cache_auto_resize_config(const H5F_t * f, + hid_t dxpl_id, H5AC2_cache_config_t *config_ptr) { /* const char * fcn_name = "H5AC2_set_cache_auto_resize_config"; */ - H5AC2_t * cache_ptr = (H5AC2_t *)f->shared->cache2; + H5AC2_t * cache_ptr; herr_t result; herr_t ret_value = SUCCEED; /* Return value */ + hbool_t mdj_enabled = FALSE; H5C2_auto_size_ctl_t internal_config; #if H5AC2__TRACE_FILE_ENABLED H5AC2_cache_config_t trace_config = H5AC2__DEFAULT_CACHE_CONFIG; @@ -2893,6 +3223,12 @@ H5AC2_set_cache_auto_resize_config(const H5F_t * f, FUNC_ENTER_NOAPI(H5AC2_set_cache_auto_resize_config, FAIL) + HDassert( f ); + HDassert( f->shared ); + HDassert( f->shared->cache2 ); + + cache_ptr = (H5AC2_t *)f->shared->cache2; + #if H5AC2__TRACE_FILE_ENABLED /* Make note of the new configuration. Don't look up the trace file * pointer, as that may change before we use it. @@ -3008,6 +3344,47 @@ H5AC2_set_cache_auto_resize_config(const H5F_t * f, "H5C2_set_evictions_enabled() failed.") } + result = H5C2_get_journal_config((H5C2_t *)cache_ptr, &mdj_enabled, + NULL, NULL, NULL, NULL, NULL); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_get_journal_config() failed.") + } + + if ( config_ptr->enable_journaling != mdj_enabled ) { + + /* we have work to do -- start or stop journaling as requested */ + + if ( config_ptr->enable_journaling ) { + + result = H5C2_begin_journaling(f, + dxpl_id, + cache_ptr, + &(config_ptr->journal_file_path[0]), + config_ptr->jbrb_buf_size, + config_ptr->jbrb_num_bufs, + config_ptr->jbrb_use_aio, + config_ptr->jbrb_human_readable); + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_begin_journaling() failed.") + } + } else { + + result = H5C2_end_journaling(f, dxpl_id, cache_ptr); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_end_journaling() failed.") + } + } + } + + #ifdef H5_HAVE_PARALLEL if ( cache_ptr->aux_ptr != NULL ) { @@ -3028,7 +3405,7 @@ done: ( trace_file_ptr != NULL ) ) { HDfprintf(trace_file_ptr, - "%s %d %d %d %d \"%s\" %d %d %d %f %d %d %ld %d %f %f %d %d %d %f %f %d %f %f %d %d %d %d %f %d %d\n", + "%s %d %d %d %d \"%s\" %d %d %d %f %d %d %ld %d %f %f %d %d %d %f %f %d %f %f %d %d %d %d %f %d %d \"%s\" %d %d %d %d %d %d\n", "H5AC2_set_cache_auto_resize_config", trace_config.version, (int)(trace_config.rpt_fcn_enabled), @@ -3059,6 +3436,13 @@ done: (int)(trace_config.apply_empty_reserve), trace_config.empty_reserve, trace_config.dirty_bytes_threshold, + (int)(config_ptr->enable_journaling), + config_ptr->journal_file_path, + (int)(config_ptr->journal_recovered), + (int)(config_ptr->jbrb_buf_size), + config_ptr->jbrb_num_bufs, + (int)(config_ptr->jbrb_use_aio), + (int)(config_ptr->jbrb_human_readable), (int)ret_value); } #endif /* H5AC2__TRACE_FILE_ENABLED */ @@ -4334,7 +4718,7 @@ H5AC2_log_renamed_entry(H5F_t * f, haddr_t new_addr) { herr_t ret_value = SUCCEED; /* Return value */ - H5AC2_t * cache_ptr = (H5AC2_t *)f->shared->cache2; + H5AC2_t * cache_ptr; hbool_t entry_in_cache; hbool_t entry_dirty; size_t entry_size; @@ -4343,6 +4727,11 @@ H5AC2_log_renamed_entry(H5F_t * f, FUNC_ENTER_NOAPI(H5AC2_log_renamed_entry, FAIL) + HDassert( f != NULL ); + HDassert( f->shared != NULL ); + + cache_ptr = (H5AC2_t *)f->shared->cache2; + HDassert( cache_ptr != NULL ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); diff --git a/src/H5AC2private.h b/src/H5AC2private.h index 6676d7e..520900b 100644 --- a/src/H5AC2private.h +++ b/src/H5AC2private.h @@ -41,6 +41,7 @@ /* Pivate headers needed by this header */ #include "H5private.h" /* Generic Functions */ +#include "H5Oprivate.h" /* Object headers */ #include "H5Fprivate.h" /* File access */ #include "H5C2private.h" /* cache */ @@ -215,7 +216,14 @@ extern hid_t H5AC2_ind_dxpl_id; /* int epochs_before_eviction = */ 3, \ /* hbool_t apply_empty_reserve = */ TRUE, \ /* double empty_reserve = */ 0.1, \ - /* int dirty_bytes_threshold = */ (256 * 1024) \ + /* int dirty_bytes_threshold = */ (256 * 1024), \ + /* hbool_t enable_journaling = */ FALSE, \ + /* char journal_file_path[] = */ "", \ + /* hbool_t journal_recovered = */ FALSE, \ + /* size_t jbrb_buf_size = */ (8 * 1024), \ + /* int jbrb_num_bufs = */ 2, \ + /* hbool_t jbrb_use_aio = */ FALSE, \ + /* hbool_t jbrb_human_readable = */ TRUE \ } @@ -254,7 +262,32 @@ extern hid_t H5AC2_ind_dxpl_id; /* external function declarations: */ H5_DLL herr_t H5AC2_init(void); -H5_DLL herr_t H5AC2_create(const H5F_t *f, H5AC2_cache_config_t *config_ptr); +H5_DLL herr_t H5AC2_create(H5F_t *f, + hid_t dxpl_id, + H5AC2_cache_config_t *config_ptr); +#if 1 /* new version */ +H5_DLL herr_t H5AC2_begin_transaction(hid_t id, + hbool_t * do_transaction_ptr, + H5O_loc_t * id_oloc_ptr, + hbool_t * id_oloc_open_ptr, + hbool_t * transaction_begun_ptr, + uint64_t * trans_num_ptr, + const char * api_call_name); + +H5_DLL herr_t H5AC2_end_transaction(hbool_t do_transaction, + H5O_loc_t * id_oloc_ptr, + hbool_t id_oloc_open, + hbool_t transaction_begun, + uint64_t trans_num, + const char * api_call_name); +#else /* old version */ +H5_DLL herr_t H5AC2_begin_transaction(H5F_t * f, + uint64_t * trans_num_ptr, + const char * api_call_name); +H5_DLL herr_t H5AC2_end_transaction(H5F_t * f, + uint64_t trans_num, + const char * api_call_name); +#endif /* old version */ H5_DLL herr_t H5AC2_get_entry_status(H5F_t * f, haddr_t addr, unsigned * status_ptr); H5_DLL herr_t H5AC2_set(H5F_t *f, hid_t dxpl_id, const H5AC2_class_t *type, @@ -306,7 +339,8 @@ H5_DLL herr_t H5AC2_get_cache_hit_rate(H5AC2_t * cache_ptr, H5_DLL herr_t H5AC2_reset_cache_hit_rate_stats(H5AC2_t * cache_ptr); H5_DLL herr_t H5AC2_set_cache_auto_resize_config(const H5F_t * f, - H5AC2_cache_config_t *config_ptr); + hid_t dxpl_id, + H5AC2_cache_config_t *config_ptr); H5_DLL herr_t H5AC2_validate_config(H5AC2_cache_config_t * config_ptr); diff --git a/src/H5AC2public.h b/src/H5AC2public.h index a16ad2a..57c65b9 100644 --- a/src/H5AC2public.h +++ b/src/H5AC2public.h @@ -36,7 +36,8 @@ extern "C" { #endif -#define H5AC2__MAX_TRACE_FILE_NAME_LEN 1024 +#define H5AC2__MAX_TRACE_FILE_NAME_LEN 1024 +#define H5AC2__MAX_JOURNAL_FILE_NAME_LEN 1024 /**************************************************************************** * @@ -380,6 +381,58 @@ extern "C" { * file. This field is ignored unless HDF5 has been compiled for * parallel. * + * + * Journal Configuration Fields: + * + * The journaling fields allow enabling of metadata journaling, specification + * of the journal file, and marking a file as recovered. + * + * Note that the fields with the "jbrb_" prefix are used to configure the + * journal buffer ring buffer -- a ring buffer of buffers used to buffer + * output of journal messages. + * + * At least to begin with, these fields may only be used at file open/create + * time -- i.e. in the FAPL. + * + * enable_journaling: Boolean flag that is set to TRUE if journaling is + * to be enabled, and to FALSE otherwise. + * + * When the cache configuration is reported, this field is TRUE iff + * journaling is enabled. + * + * journal_file_path: Full path of the file to be used to store the + * metadata journal. This field is only defined if enable_journaling + * is TRUE. + * + * At present, the length of the journal file path is restricted to + * no more than H5AC2__MAX_JOURNAL_FILE_NAME_LEN. + * + * journal_recovered: Boolean flag use to indicate that we are opening + * a journaled file that was not closed correctly, and on which the + * journal recovery tool has been run. + * + * Unless you are the writer of a new journal recovery tool, you + * should always set this field to FALSE. + * + * jbrb_buf_size: size_t containing the size of each individual buffer + * in the journal buffer ring buffer. This size should be chosen + * to be some multiple of the block size used by the file system + * on which the journal file will be written. + * + * jbrb_num_bufs: Integer containing the number of buffers in the journal + * buffer ring buffer. If synchronous I/O is used, one or two buffers + * is sufficient. If asynchronous I/O is used, the number of buffers + * should be sufficiently large that a write on buffer is likely to + * complete before that buffer is needed again. + * + * jbrb_use_aio: Boolean flag indicating whether we should use + * asynchronous I/O for journal entry writes. + * + * jbrb_human_readable: Boolean flag which determines whether the journal + * file will be written in human readable form. In general, this + * field should be set to false, as the human readable journal + * file is at least twice a large as the machine readable version. + * ****************************************************************************/ #define H5AC2__CURR_CACHE_CONFIG_VERSION 1 @@ -442,6 +495,17 @@ typedef struct H5AC2_cache_config_t /* parallel configuration fields: */ int dirty_bytes_threshold; + + /* metadata journaling configuration fields: */ + hbool_t enable_journaling; + char journal_file_path[ + H5AC2__MAX_JOURNAL_FILE_NAME_LEN]; + hbool_t journal_recovered; + size_t jbrb_buf_size; + int jbrb_num_bufs; + hbool_t jbrb_use_aio; + hbool_t jbrb_human_readable; + } H5AC2_cache_config_t; diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h index bbbcf11..40ab9ab 100644 --- a/src/H5ACprivate.h +++ b/src/H5ACprivate.h @@ -225,7 +225,17 @@ extern hid_t H5AC_ind_dxpl_id; /* int epochs_before_eviction = */ 3, \ /* hbool_t apply_empty_reserve = */ TRUE, \ /* double empty_reserve = */ 0.1, \ - /* int dirty_bytes_threshold = */ (256 * 1024) \ + /* int dirty_bytes_threshold = */ (256 * 1024), \ + /* The following fields are not used by H5AC or H5C -- they exist here */ \ + /* because they are used by H5AC2 and H5C2, and including them here */ \ + /* us to avoid duplicating the user level cache configuration code. */ \ + /* hbool_t enable_journaling = */ FALSE, \ + /* char journal_file_path[] = */ "", \ + /* hbool_t journal_recovered = */ FALSE, \ + /* size_t jbrb_buf_size = */ (8 * 1024), \ + /* int jbrb_num_bufs = */ 2, \ + /* hbool_t jbrb_use_aio = */ FALSE, \ + /* hbool_t jbrb_human_readable = */ TRUE \ } diff --git a/src/H5ACpublic.h b/src/H5ACpublic.h index 0e75117..6539a64 100644 --- a/src/H5ACpublic.h +++ b/src/H5ACpublic.h @@ -37,6 +37,7 @@ extern "C" { #endif #define H5AC__MAX_TRACE_FILE_NAME_LEN 1024 +#define H5AC__MAX_JOURNAL_FILE_NAME_LEN 1024 /**************************************************************************** * @@ -443,6 +444,25 @@ typedef struct H5AC_cache_config_t /* parallel configuration fields: */ int dirty_bytes_threshold; + /* The following fields are not used in H5AC or H5C. They are + * added because they are used in H5AC2 and H5C2, and putting + * them here allows us to avoid duplicating the functions involved + * in metadata cache configuration at the user API level. + * + * The old H5AC and H5C code simply ignores them. + * + * -- JRM + */ + /* metadata journaling configuration fields: */ + hbool_t enable_journaling; + char journal_file_path[ + H5AC__MAX_JOURNAL_FILE_NAME_LEN]; + hbool_t journal_recovered; + size_t jbrb_buf_size; + int jbrb_num_bufs; + hbool_t jbrb_use_aio; + hbool_t jbrb_human_readable; + } H5AC_cache_config_t; diff --git a/src/H5Adeprec.c b/src/H5Adeprec.c index 1e22493..f2c63e9 100644 --- a/src/H5Adeprec.c +++ b/src/H5Adeprec.c @@ -47,6 +47,7 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5Iprivate.h" /* IDs */ #include "H5Opkg.h" /* Object headers */ +#include "H5AC2private.h" /* Metadata cache */ /****************/ @@ -143,7 +144,7 @@ H5Acreate1(hid_t loc_id, const char *name, hid_t type_id, hid_t space_id, H5S_t *space; /* Dataspace to use for attribute */ hid_t ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Acreate1, FAIL) + FUNC_ENTER_API_META(H5Acreate1, loc_id, FAIL) H5TRACE5("i", "i*siii", loc_id, name, type_id, space_id, plist_id); /* check arguments */ @@ -112,2447 +112,6 @@ #include "H5SLprivate.h" /* Skip lists */ -/**************************************************************************** - * - * We maintain doubly linked lists of instances of H5C2_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 H5C2_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 H5C2_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 - * - * Changes: - * - * - Removed the line: - * - * ( ( (Size) == (entry_ptr)->size ) && ( (len) != 1 ) ) || - * - * from the H5C2__DLL_PRE_REMOVE_SC macro. With the addition of the - * epoch markers used in the age out based cache size reduction algorithm, - * this invarient need not hold, as the epoch markers are of size 0. - * - * One could argue that I should have given the epoch markers a positive - * size, but this would break the index_size = LRU_list_size + pl_size - * + pel_size invarient. - * - * Alternatively, I could pass the current decr_mode in to the macro, - * and just skip the check whenever epoch markers may be in use. - * - * However, any size errors should be caught when the cache is flushed - * and destroyed. Until we are tracking such an error, this should be - * good enough. - * JRM - 12/9/04 - * - * - * - In the H5C2__DLL_PRE_INSERT_SC macro, replaced the lines: - * - * ( ( (len) == 1 ) && - * ( ( (head_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) || - * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) - * ) - * ) || - * - * with: - * - * ( ( (len) == 1 ) && - * ( ( (head_ptr) != (tail_ptr) ) || - * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) - * ) - * ) || - * - * Epoch markers have size 0, so we can now have a non-empty list with - * zero size. Hence the "( (Size) <= 0 )" clause cause false failures - * in the sanity check. Since "Size" is typically a size_t, it can't - * take on negative values, and thus the revised clause "( (Size) < 0 )" - * caused compiler warnings. - * JRM - 12/22/04 - * - * - In the H5C2__DLL_SC macro, replaced the lines: - * - * ( ( (len) == 1 ) && - * ( ( (head_ptr) != (tail_ptr) ) || ( (cache_ptr)->size <= 0 ) || - * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) - * ) - * ) || - * - * with - * - * ( ( (len) == 1 ) && - * ( ( (head_ptr) != (tail_ptr) ) || - * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) - * ) - * ) || - * - * Epoch markers have size 0, so we can now have a non-empty list with - * zero size. Hence the "( (Size) <= 0 )" clause cause false failures - * in the sanity check. Since "Size" is typically a size_t, it can't - * take on negative values, and thus the revised clause "( (Size) < 0 )" - * caused compiler warnings. - * JRM - 1/10/05 - * - * - Added the H5C2__DLL_UPDATE_FOR_SIZE_CHANGE macro and the associated - * sanity checking macros. These macro are used to update the size of - * a DLL when one of its entries changes size. - * - * JRM - 9/8/05 - * - ****************************************************************************/ - -#if H5C2_DO_SANITY_CHECKS - -#define H5C2__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 ) || \ - ( ( (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 H5C2__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) ) || \ - ( (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 H5C2__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) ) || \ - ( (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") \ -} - -#define H5C2__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) \ -if ( ( (dll_len) <= 0 ) || \ - ( (dll_size) <= 0 ) || \ - ( (old_size) <= 0 ) || \ - ( (old_size) > (dll_size) ) || \ - ( (new_size) <= 0 ) || \ - ( ( (dll_len) == 1 ) && ( (old_size) != (dll_size) ) ) ) { \ - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "DLL pre size update SC failed") \ -} - -#define H5C2__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) \ -if ( ( (new_size) > (dll_size) ) || \ - ( ( (dll_len) == 1 ) && ( (new_size) != (dll_size) ) ) ) { \ - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "DLL post size update SC failed") \ -} - -#else /* H5C2_DO_SANITY_CHECKS */ - -#define H5C2__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) -#define H5C2__DLL_SC(head_ptr, tail_ptr, len, Size, fv) -#define H5C2__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) -#define H5C2__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) -#define H5C2__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) - -#endif /* H5C2_DO_SANITY_CHECKS */ - - -#define H5C2__DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \ - H5C2__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 H5C2__DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \ - H5C2__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 H5C2__DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \ - H5C2__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; \ - } - -#define H5C2__DLL_UPDATE_FOR_SIZE_CHANGE(dll_len, dll_size, old_size, new_size) \ - H5C2__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) \ - (dll_size) -= (old_size); \ - (dll_size) += (new_size); \ - H5C2__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) - -#if H5C2_DO_SANITY_CHECKS - -#define H5C2__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 H5C2__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 H5C2__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 /* H5C2_DO_SANITY_CHECKS */ - -#define H5C2__AUX_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) -#define H5C2__AUX_DLL_SC(head_ptr, tail_ptr, len, Size, fv) -#define H5C2__AUX_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) - -#endif /* H5C2_DO_SANITY_CHECKS */ - - -#define H5C2__AUX_DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val)\ - H5C2__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 H5C2__AUX_DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \ - H5C2__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 H5C2__AUX_DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \ - H5C2__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. - * - * The sole exception to this rule is - * H5C2__UPDATE_CACHE_HIT_RATE_STATS(), which is always active as - * the cache hit rate stats are always collected and available. - * - * Changes: - * - * JRM -- 3/21/06 - * Added / updated macros for pinned entry related stats. - * - * JRM -- 8/9/06 - * More pinned entry stats related updates. - * - * JRM -- 3/31/07 - * Updated H5C2__UPDATE_STATS_FOR_PROTECT() to keep stats on - * read and write protects. - * - ***********************************************************************/ - -#define H5C2__UPDATE_CACHE_HIT_RATE_STATS(cache_ptr, hit) \ - (cache_ptr->cache_accesses)++; \ - if ( hit ) { \ - (cache_ptr->cache_hits)++; \ - } \ - -#if H5C2_COLLECT_CACHE_STATS - -#define H5C2__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr) \ - (((cache_ptr)->dirty_pins)[(entry_ptr)->type->id])++; - -#define H5C2__UPDATE_STATS_FOR_UNPROTECT(cache_ptr) \ - if ( (cache_ptr)->slist_len > (cache_ptr)->max_slist_len ) \ - (cache_ptr)->max_slist_len = (cache_ptr)->slist_len; \ - if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \ - (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; \ - if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \ - (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \ - if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ - (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; - -#define H5C2__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr) \ - if ( cache_ptr->flush_in_progress ) { \ - ((cache_ptr)->cache_flush_renames[(entry_ptr)->type->id])++; \ - } \ - if ( entry_ptr->flush_in_progress ) { \ - ((cache_ptr)->entry_flush_renames[(entry_ptr)->type->id])++; \ - } \ - (((cache_ptr)->renames)[(entry_ptr)->type->id])++; - -#define H5C2__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size)\ - if ( cache_ptr->flush_in_progress ) { \ - ((cache_ptr)->cache_flush_size_changes[(entry_ptr)->type->id])++; \ - } \ - if ( entry_ptr->flush_in_progress ) { \ - ((cache_ptr)->entry_flush_size_changes[(entry_ptr)->type->id])++; \ - } \ - if ( (entry_ptr)->size < (new_size) ) { \ - ((cache_ptr)->size_increases[(entry_ptr)->type->id])++; \ - if ( (cache_ptr)->index_size > (cache_ptr)->max_index_size ) \ - (cache_ptr)->max_index_size = (cache_ptr)->index_size; \ - if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \ - (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; \ - if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size ) \ - (cache_ptr)->max_pl_size = (cache_ptr)->pl_size; \ - } else if ( (entry_ptr)->size > (new_size) ) { \ - ((cache_ptr)->size_decreases[(entry_ptr)->type->id])++; \ - } - -#define H5C2__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) \ - (cache_ptr)->total_ht_insertions++; - -#define H5C2__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) \ - (cache_ptr)->total_ht_deletions++; - -#define H5C2__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; \ - } - -#define H5C2__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr) \ - ((cache_ptr)->unpins)[(entry_ptr)->type->id]++; - -#if H5C2_COLLECT_CACHE_ENTRY_STATS - -#define H5C2__RESET_CACHE_ENTRY_STATS(entry_ptr) \ - (entry_ptr)->accesses = 0; \ - (entry_ptr)->clears = 0; \ - (entry_ptr)->flushes = 0; \ - (entry_ptr)->pins = 0; - -#define H5C2__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) \ - (((cache_ptr)->clears)[(entry_ptr)->type->id])++; \ - if ( (entry_ptr)->is_pinned ) { \ - (((cache_ptr)->pinned_clears)[(entry_ptr)->type->id])++; \ - } \ - ((entry_ptr)->clears)++; - -#define H5C2__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) \ - (((cache_ptr)->flushes)[(entry_ptr)->type->id])++; \ - if ( (entry_ptr)->is_pinned ) { \ - (((cache_ptr)->pinned_flushes)[(entry_ptr)->type->id])++; \ - } \ - ((entry_ptr)->flushes)++; - -#define H5C2__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; \ - } \ - if ( (entry_ptr)->pins > \ - ((cache_ptr)->max_pins)[(entry_ptr)->type->id] ) { \ - ((cache_ptr)->max_pins)[(entry_ptr)->type->id] \ - = (entry_ptr)->pins; \ - } - -#define H5C2__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) \ - (((cache_ptr)->insertions)[(entry_ptr)->type->id])++; \ - if ( (entry_ptr)->is_pinned ) { \ - (((cache_ptr)->pinned_insertions)[(entry_ptr)->type->id])++; \ - ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \ - (entry_ptr)->pins++; \ - if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \ - (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \ - if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ - (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; \ - } \ - 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)->slist_len > (cache_ptr)->max_slist_len ) \ - (cache_ptr)->max_slist_len = (cache_ptr)->slist_len; \ - if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \ - (cache_ptr)->max_slist_size = (cache_ptr)->slist_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 H5C2__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 ( ! ((entry_ptr)->is_read_only) ) { \ - ((cache_ptr)->write_protects)[(entry_ptr)->type->id]++; \ - } else { \ - ((cache_ptr)->read_protects)[(entry_ptr)->type->id]++; \ - if ( ((entry_ptr)->ro_ref_count) > \ - ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] ) { \ - ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] = \ - ((entry_ptr)->ro_ref_count); \ - } \ - } \ - 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)++; - -#define H5C2__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr) \ - ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \ - (entry_ptr)->pins++; \ - if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \ - (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \ - if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ - (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; - -#else /* H5C2_COLLECT_CACHE_ENTRY_STATS */ - -#define H5C2__RESET_CACHE_ENTRY_STATS(entry_ptr) - -#define H5C2__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) \ - if ( (entry_ptr)->is_pinned ) { \ - (((cache_ptr)->pinned_clears)[(entry_ptr)->type->id])++; \ - } \ - (((cache_ptr)->clears)[(entry_ptr)->type->id])++; - -#define H5C2__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) \ - (((cache_ptr)->flushes)[(entry_ptr)->type->id])++; \ - if ( (entry_ptr)->is_pinned ) { \ - (((cache_ptr)->pinned_flushes)[(entry_ptr)->type->id])++; \ - } - -#define H5C2__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) \ - (((cache_ptr)->evictions)[(entry_ptr)->type->id])++; - -#define H5C2__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) \ - (((cache_ptr)->insertions)[(entry_ptr)->type->id])++; \ - if ( (entry_ptr)->is_pinned ) { \ - (((cache_ptr)->pinned_insertions)[(entry_ptr)->type->id])++; \ - ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \ - if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \ - (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \ - if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ - (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; \ - } \ - 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)->slist_len > (cache_ptr)->max_slist_len ) \ - (cache_ptr)->max_slist_len = (cache_ptr)->slist_len; \ - if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \ - (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; - -#define H5C2__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 ( ! ((entry_ptr)->is_read_only) ) { \ - ((cache_ptr)->write_protects)[(entry_ptr)->type->id]++; \ - } else { \ - ((cache_ptr)->read_protects)[(entry_ptr)->type->id]++; \ - if ( ((entry_ptr)->ro_ref_count) > \ - ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] ) { \ - ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] = \ - ((entry_ptr)->ro_ref_count); \ - } \ - } \ - 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; - -#define H5C2__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr) \ - ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \ - if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \ - (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \ - if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ - (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; - -#endif /* H5C2_COLLECT_CACHE_ENTRY_STATS */ - -#else /* H5C2_COLLECT_CACHE_STATS */ - -#define H5C2__RESET_CACHE_ENTRY_STATS(entry_ptr) -#define H5C2__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr) -#define H5C2__UPDATE_STATS_FOR_UNPROTECT(cache_ptr) -#define H5C2__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr) -#define H5C2__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size) -#define H5C2__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) -#define H5C2__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) -#define H5C2__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, success, depth) -#define H5C2__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) -#define H5C2__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) -#define H5C2__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) -#define H5C2__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) -#define H5C2__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit) -#define H5C2__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr) -#define H5C2__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr) - -#endif /* H5C2_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 - * - ***********************************************************************/ - -/* H5C2__HASH_TABLE_LEN is defined in H5C2pkg.h. It mut be a power of two. */ - -#define H5C2__HASH_MASK ((size_t)(H5C2__HASH_TABLE_LEN - 1) << 3) - -#define H5C2__HASH_FCN(x) (int)(((x) & H5C2__HASH_MASK) >> 3) - -#if H5C2_DO_SANITY_CHECKS - -#define H5C2__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \ -if ( ( (cache_ptr) == NULL ) || \ - ( (cache_ptr)->magic != H5C2__H5C2_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 = H5C2__HASH_FCN((entry_ptr)->addr)) < 0 ) || \ - ( k >= H5C2__HASH_TABLE_LEN ) ) { \ - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, \ - "Pre HT insert SC failed") \ -} - -#define H5C2__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) \ -if ( ( (cache_ptr) == NULL ) || \ - ( (cache_ptr)->magic != H5C2__H5C2_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 ) || \ - ( H5C2__HASH_FCN((entry_ptr)->addr) < 0 ) || \ - ( H5C2__HASH_FCN((entry_ptr)->addr) >= H5C2__HASH_TABLE_LEN ) || \ - ( ((cache_ptr)->index)[(H5C2__HASH_FCN((entry_ptr)->addr))] \ - == NULL ) || \ - ( ( ((cache_ptr)->index)[(H5C2__HASH_FCN((entry_ptr)->addr))] \ - != (entry_ptr) ) && \ - ( (entry_ptr)->ht_prev == NULL ) ) || \ - ( ( ((cache_ptr)->index)[(H5C2__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 H5C2__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \ -if ( ( (cache_ptr) == NULL ) || \ - ( (cache_ptr)->magic != H5C2__H5C2_T_MAGIC ) || \ - ( ! H5F_addr_defined(Addr) ) || \ - ( H5C2__HASH_FCN(Addr) < 0 ) || \ - ( H5C2__HASH_FCN(Addr) >= H5C2__HASH_TABLE_LEN ) ) { \ - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, "Pre HT search SC failed") \ -} - -#define H5C2__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val) \ -if ( ( (cache_ptr) == NULL ) || \ - ( (cache_ptr)->magic != H5C2__H5C2_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 H5C2__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") \ -} - -#define H5C2__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) \ -if ( ( (cache_ptr) == NULL ) || \ - ( (cache_ptr)->index_len <= 0 ) || \ - ( (cache_ptr)->index_size <= 0 ) || \ - ( (new_size) <= 0 ) || \ - ( (old_size) > (cache_ptr)->index_size ) || \ - ( (new_size) <= 0 ) || \ - ( ( (cache_ptr)->index_len == 1 ) && \ - ( (cache_ptr)->index_size != (old_size) ) ) ) { \ - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "Pre HT entry size change SC failed") \ -} - -#define H5C2__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) \ -if ( ( (cache_ptr) == NULL ) || \ - ( (cache_ptr)->index_len <= 0 ) || \ - ( (cache_ptr)->index_size <= 0 ) || \ - ( (new_size) > (cache_ptr)->index_size ) || \ - ( ( (cache_ptr)->index_len == 1 ) && \ - ( (cache_ptr)->index_size != (new_size) ) ) ) { \ - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "Post HT entry size change SC failed") \ -} - -#else /* H5C2_DO_SANITY_CHECKS */ - -#define H5C2__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) -#define H5C2__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) -#define H5C2__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) -#define H5C2__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val) -#define H5C2__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) -#define H5C2__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) -#define H5C2__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) - -#endif /* H5C2_DO_SANITY_CHECKS */ - - -#define H5C2__INSERT_IN_INDEX(cache_ptr, entry_ptr, fail_val) \ -{ \ - int k; \ - H5C2__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \ - k = H5C2__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; \ - H5C2__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) \ -} - -#define H5C2__DELETE_FROM_INDEX(cache_ptr, entry_ptr) \ -{ \ - int k; \ - H5C2__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) \ - k = H5C2__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; \ - H5C2__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) \ -} - -#define H5C2__SEARCH_INDEX(cache_ptr, Addr, entry_ptr, fail_val) \ -{ \ - int k; \ - int depth = 0; \ - H5C2__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \ - k = H5C2__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 ) \ - { \ - H5C2__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); \ - H5C2__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) \ - } \ - } \ - H5C2__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, (entry_ptr != NULL), depth) \ -} - -#define H5C2__SEARCH_INDEX_NO_STATS(cache_ptr, Addr, entry_ptr, fail_val) \ -{ \ - int k; \ - int depth = 0; \ - H5C2__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \ - k = H5C2__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 ) \ - { \ - H5C2__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); \ - H5C2__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) \ - } \ - } \ -} - -#define H5C2__UPDATE_INDEX_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \ -{ \ - H5C2__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) \ - (cache_ptr)->index_size -= old_size; \ - (cache_ptr)->index_size += new_size; \ - H5C2__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) \ -} - - -/************************************************************************** - * - * Skip list insertion and deletion macros: - * - * These used to be functions, but I converted them to macros to avoid some - * function call overhead. - * - **************************************************************************/ - -/*------------------------------------------------------------------------- - * - * Macro: H5C2__INSERT_ENTRY_IN_SLIST - * - * Purpose: Insert the specified instance of H5C2_cache_entry_t into - * the skip list in the specified instance of H5C2_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 H5C2_insert_entry_in_tree() into - * the macro H5C2__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, H5SL_insert() will fail. - * - * QAK -- 11/27/04 - * Switched over to using skip list routines. - * - * JRM -- 6/27/06 - * Added fail_val parameter. - * - * JRM -- 8/25/06 - * Added the H5C2_DO_SANITY_CHECKS version of the macro. - * - * This version maintains the slist_len_increase and - * slist_size_increase fields that are used in sanity - * checks in the flush routines. - * - * All this is needed as the fractal heap needs to be - * able to dirty, resize and/or rename entries during the - * flush. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_DO_SANITY_CHECKS - -#define H5C2__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( (entry_ptr)->size > 0 ); \ - HDassert( H5F_addr_defined((entry_ptr)->addr) ); \ - HDassert( !((entry_ptr)->in_slist) ); \ - \ - if ( H5SL_insert((cache_ptr)->slist_ptr, entry_ptr, &(entry_ptr)->addr) \ - < 0 ) \ - HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, (fail_val), \ - "Can't insert entry in skip list") \ - \ - (entry_ptr)->in_slist = TRUE; \ - (cache_ptr)->slist_len++; \ - (cache_ptr)->slist_size += (entry_ptr)->size; \ - (cache_ptr)->slist_len_increase++; \ - (cache_ptr)->slist_size_increase += (entry_ptr)->size; \ - \ - HDassert( (cache_ptr)->slist_len > 0 ); \ - HDassert( (cache_ptr)->slist_size > 0 ); \ - \ -} /* H5C2__INSERT_ENTRY_IN_SLIST */ - -#else /* H5C2_DO_SANITY_CHECKS */ - -#define H5C2__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( (entry_ptr)->size > 0 ); \ - HDassert( H5F_addr_defined((entry_ptr)->addr) ); \ - HDassert( !((entry_ptr)->in_slist) ); \ - \ - if ( H5SL_insert((cache_ptr)->slist_ptr, entry_ptr, &(entry_ptr)->addr) \ - < 0 ) \ - HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, (fail_val), \ - "Can't insert entry in skip list") \ - \ - (entry_ptr)->in_slist = TRUE; \ - (cache_ptr)->slist_len++; \ - (cache_ptr)->slist_size += (entry_ptr)->size; \ - \ - HDassert( (cache_ptr)->slist_len > 0 ); \ - HDassert( (cache_ptr)->slist_size > 0 ); \ - \ -} /* H5C2__INSERT_ENTRY_IN_SLIST */ - -#endif /* H5C2_DO_SANITY_CHECKS */ - - -/*------------------------------------------------------------------------- - * - * Function: H5C2__REMOVE_ENTRY_FROM_SLIST - * - * Purpose: Remove the specified instance of H5C2_cache_entry_t from the - * index skip list in the specified instance of H5C2_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 H5C2_remove_entry_from_tree() - * to the macro H5C2__REMOVE_ENTRY_FROM_TREE in the hopes of - * wringing a little more performance out of the cache. - * - * QAK -- 11/27/04 - * Switched over to using skip list routines. - * - * JRM -- 3/28/07 - * Updated sanity checks for the new is_read_only and - * ro_ref_count fields in H5C2_cache_entry_t. - * - *------------------------------------------------------------------------- - */ - -#define H5C2__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - HDassert( (entry_ptr)->in_slist ); \ - HDassert( (cache_ptr)->slist_ptr ); \ - \ - if ( H5SL_remove((cache_ptr)->slist_ptr, &(entry_ptr)->addr) \ - != (entry_ptr) ) \ - \ - HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, \ - "Can't delete entry from skip list.") \ - \ - HDassert( (cache_ptr)->slist_len > 0 ); \ - (cache_ptr)->slist_len--; \ - HDassert( (cache_ptr)->slist_size >= (entry_ptr)->size ); \ - (cache_ptr)->slist_size -= (entry_ptr)->size; \ - (entry_ptr)->in_slist = FALSE; \ -} /* H5C2__REMOVE_ENTRY_FROM_SLIST */ - - -/*------------------------------------------------------------------------- - * - * Function: H5C2__UPDATE_SLIST_FOR_SIZE_CHANGE - * - * Purpose: Update cache_ptr->slist_size for a change in the size of - * and entry in the slist. - * - * Return: N/A - * - * Programmer: John Mainzer, 9/07/05 - * - * Modifications: - * - * JRM -- 8/27/06 - * Added the H5C2_DO_SANITY_CHECKS version of the macro. - * - * This version maintains the slist_size_increase field - * that are used in sanity checks in the flush routines. - * - * All this is needed as the fractal heap needs to be - * able to dirty, resize and/or rename entries during the - * flush. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_DO_SANITY_CHECKS - -#define H5C2__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (old_size) > 0 ); \ - HDassert( (new_size) > 0 ); \ - HDassert( (old_size) <= (cache_ptr)->slist_size ); \ - HDassert( (cache_ptr)->slist_len > 0 ); \ - HDassert( ((cache_ptr)->slist_len > 1) || \ - ( (cache_ptr)->slist_size == (old_size) ) ); \ - \ - (cache_ptr)->slist_size -= (old_size); \ - (cache_ptr)->slist_size += (new_size); \ - \ - (cache_ptr)->slist_size_increase -= (int64_t)(old_size); \ - (cache_ptr)->slist_size_increase += (int64_t)(new_size); \ - \ - HDassert( (new_size) <= (cache_ptr)->slist_size ); \ - HDassert( ( (cache_ptr)->slist_len > 1 ) || \ - ( (cache_ptr)->slist_size == (new_size) ) ); \ -} /* H5C2__REMOVE_ENTRY_FROM_SLIST */ - -#else /* H5C2_DO_SANITY_CHECKS */ - -#define H5C2__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (old_size) > 0 ); \ - HDassert( (new_size) > 0 ); \ - HDassert( (old_size) <= (cache_ptr)->slist_size ); \ - HDassert( (cache_ptr)->slist_len > 0 ); \ - HDassert( ((cache_ptr)->slist_len > 1) || \ - ( (cache_ptr)->slist_size == (old_size) ) ); \ - \ - (cache_ptr)->slist_size -= (old_size); \ - (cache_ptr)->slist_size += (new_size); \ - \ - HDassert( (new_size) <= (cache_ptr)->slist_size ); \ - HDassert( ( (cache_ptr)->slist_len > 1 ) || \ - ( (cache_ptr)->slist_size == (new_size) ) ); \ -} /* H5C2__REMOVE_ENTRY_FROM_SLIST */ - -#endif /* H5C2_DO_SANITY_CHECKS */ - - -/************************************************************************** - * - * Replacement policy update macros: - * - * These used to be functions, but I converted them to macros to avoid some - * function call overhead. - * - **************************************************************************/ - -/*------------------------------------------------------------------------- - * - * Macro: H5C2__FAKE_RP_FOR_MOST_RECENT_ACCESS - * - * Purpose: For efficiency, we sometimes change the order of flushes -- - * but doing so can confuse the replacement policy. This - * macro exists to allow us to specify an entry as the - * most recently touched so we can repair any such - * confusion. - * - * 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 macro - * should switch on the current policy and act accordingly. - * - * Return: N/A - * - * Programmer: John Mainzer, 10/13/05 - * - * Modifications: - * - * JRM -- 3/20/06 - * Modified macro to ignore pinned entries. Pinned entries - * do not appear in the data structures maintained by the - * replacement policy code, and thus this macro has nothing - * to do if called for such an entry. - * - * JRM -- 3/28/07 - * Added sanity checks using the new is_read_only and - * ro_ref_count fields of struct H5C2_cache_entry_t. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS - -#define H5C2__FAKE_RP_FOR_MOST_RECENT_ACCESS(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - if ( ! ((entry_ptr)->is_pinned) ) { \ - \ - /* modified LRU specific code */ \ - \ - /* remove the entry from the LRU list, and re-insert it at the head.\ - */ \ - \ - H5C2__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)) \ - \ - H5C2__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)) \ - \ - /* 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 same LRU list. \ - * \ - * At least initially, all entries should be clean. That may \ - * change, so we may as well deal with both cases now. \ - */ \ - \ - if ( (entry_ptr)->is_dirty ) { \ - H5C2__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)) \ - \ - H5C2__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 { \ - H5C2__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)) \ - \ - H5C2__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. */ \ - } \ -} /* H5C2__FAKE_RP_FOR_MOST_RECENT_ACCESS */ - -#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - -#define H5C2__FAKE_RP_FOR_MOST_RECENT_ACCESS(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - if ( ! ((entry_ptr)->is_pinned) ) { \ - \ - /* modified LRU specific code */ \ - \ - /* remove the entry from the LRU list, and re-insert it at the head \ - */ \ - \ - H5C2__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)) \ - \ - H5C2__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. */ \ - } \ -} /* H5C2__FAKE_RP_FOR_MOST_RECENT_ACCESS */ - -#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - - -/*------------------------------------------------------------------------- - * - * Macro: H5C2__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 H5C2_update_rp_for_eviction() to the - * macro H5C2__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. - * - * JRM - 3/20/06 - * Pinned entries can't be evicted, so this entry should never - * be called on a pinned entry. Added assert to verify this. - * - * JRM -- 3/28/07 - * Added sanity checks for the new is_read_only and - * ro_ref_count fields of struct H5C2_cache_entry_t. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS - -#define H5C2__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( !((entry_ptr)->is_pinned) ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - /* modified LRU specific code */ \ - \ - /* remove the entry from the LRU list. */ \ - \ - H5C2__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 ) { \ - \ - H5C2__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 { \ - H5C2__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)) \ - } \ - \ -} /* H5C2__UPDATE_RP_FOR_EVICTION */ - -#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - -#define H5C2__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( !((entry_ptr)->is_pinned) ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - /* modified LRU specific code */ \ - \ - /* remove the entry from the LRU list. */ \ - \ - H5C2__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)) \ - \ -} /* H5C2__UPDATE_RP_FOR_EVICTION */ - -#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - - -/*------------------------------------------------------------------------- - * - * Macro: H5C2__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 H5C2_update_rp_for_flush() to the - * macro H5C2__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 versions, one supporting the clean and - * dirty LRU lists, and the other not. Yet another attempt - * at optimization. - * - * JRM - 3/20/06 - * While pinned entries can be flushed, they don't reside in - * the replacement policy data structures when unprotected. - * Thus I modified this macro to do nothing if the entry is - * pinned. - * - * JRM - 3/28/07 - * Added sanity checks based on the new is_read_only and - * ro_ref_count fields of struct H5C2_cache_entry_t. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS - -#define H5C2__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - if ( ! ((entry_ptr)->is_pinned) ) { \ - \ - /* modified LRU specific code */ \ - \ - /* remove the entry from the LRU list, and re-insert it at the \ - * head. \ - */ \ - \ - H5C2__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)) \ - \ - H5C2__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 ) { \ - H5C2__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 { \ - H5C2__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)) \ - } \ - \ - H5C2__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. */ \ - } \ -} /* H5C2__UPDATE_RP_FOR_FLUSH */ - -#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - -#define H5C2__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - if ( ! ((entry_ptr)->is_pinned) ) { \ - \ - /* modified LRU specific code */ \ - \ - /* remove the entry from the LRU list, and re-insert it at the \ - * head. \ - */ \ - \ - H5C2__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)) \ - \ - H5C2__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. */ \ - } \ -} /* H5C2__UPDATE_RP_FOR_FLUSH */ - -#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - - -/*------------------------------------------------------------------------- - * - * Macro: H5C2__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 H5C2_update_rp_for_insertion() to the - * macro H5C2__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. - * - * JRM - 3/10/06 - * This macro should never be called on a pinned entry. - * Inserted an assert to verify this. - * - * JRM - 8/9/06 - * Not any more. We must now allow insertion of pinned - * entries. Updated macro to support this. - * - * JRM - 3/28/07 - * Added sanity checks using the new is_read_only and - * ro_ref_count fields of struct H5C2_cache_entry_t. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS - -#define H5C2__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - if ( (entry_ptr)->is_pinned ) { \ - \ - H5C2__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \ - (cache_ptr)->pel_tail_ptr, \ - (cache_ptr)->pel_len, \ - (cache_ptr)->pel_size, (fail_val)) \ - \ - } else { \ - \ - /* modified LRU specific code */ \ - \ - /* insert the entry at the head of the LRU list. */ \ - \ - H5C2__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 ) { \ - H5C2__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 { \ - H5C2__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 /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - -#define H5C2__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - if ( (entry_ptr)->is_pinned ) { \ - \ - H5C2__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \ - (cache_ptr)->pel_tail_ptr, \ - (cache_ptr)->pel_len, \ - (cache_ptr)->pel_size, (fail_val)) \ - \ - } else { \ - \ - /* modified LRU specific code */ \ - \ - /* insert the entry at the head of the LRU list. */ \ - \ - H5C2__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 /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - - -/*------------------------------------------------------------------------- - * - * Macro: H5C2__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 H5C2_update_rp_for_protect() to the - * macro H5C2__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. - * - * JRM - 3/17/06 - * Modified macro to attempt to remove pinned entriese from - * the pinned entry list instead of from the data structures - * maintained by the replacement policy. - * - * JRM - 3/28/07 - * Added sanity checks based on the new is_read_only and - * ro_ref_count fields of struct H5C2_cache_entry_t. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS - -#define H5C2__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - if ( (entry_ptr)->is_pinned ) { \ - \ - H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \ - (cache_ptr)->pel_tail_ptr, \ - (cache_ptr)->pel_len, \ - (cache_ptr)->pel_size, (fail_val)) \ - \ - } else { \ - \ - /* modified LRU specific code */ \ - \ - /* remove the entry from the LRU list. */ \ - \ - H5C2__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 ) { \ - \ - H5C2__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 { \ - \ - H5C2__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, or whether the entry is \ - * pinned, now add the entry to the protected list. \ - */ \ - \ - H5C2__DLL_APPEND((entry_ptr), (cache_ptr)->pl_head_ptr, \ - (cache_ptr)->pl_tail_ptr, \ - (cache_ptr)->pl_len, \ - (cache_ptr)->pl_size, (fail_val)) \ -} /* H5C2__UPDATE_RP_FOR_PROTECT */ - -#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - -#define H5C2__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - if ( (entry_ptr)->is_pinned ) { \ - \ - H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \ - (cache_ptr)->pel_tail_ptr, \ - (cache_ptr)->pel_len, \ - (cache_ptr)->pel_size, (fail_val)) \ - \ - } else { \ - \ - /* modified LRU specific code */ \ - \ - /* remove the entry from the LRU list. */ \ - \ - H5C2__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, or whether the entry is \ - * pinned, now add the entry to the protected list. \ - */ \ - \ - H5C2__DLL_APPEND((entry_ptr), (cache_ptr)->pl_head_ptr, \ - (cache_ptr)->pl_tail_ptr, \ - (cache_ptr)->pl_len, \ - (cache_ptr)->pl_size, (fail_val)) \ -} /* H5C2__UPDATE_RP_FOR_PROTECT */ - -#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - - -/*------------------------------------------------------------------------- - * - * Macro: H5C2__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 H5C2_update_rp_for_rename() to the - * macro H5C2__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. - * - * JRM - 6/23/05 - * Added the was_dirty parameter. It is possible that - * the entry was clean when it was renamed -- if so it - * it is in the clean LRU regardless of the current - * value of the is_dirty field. - * - * At present, all renamed entries are forced to be - * dirty. This macro is a bit more general that that, - * to allow it to function correctly should that policy - * be relaxed in the future. - * - * JRM - 3/17/06 - * Modified macro to do nothing if the entry is pinned. - * In this case, the entry is on the pinned entry list, not - * in the replacement policy data structures, so there is - * nothing to be done. - * - * JRM - 3/28/07 - * Added sanity checks using the new is_read_only and - * ro_ref_count fields of struct H5C2_cache_entry_t. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS - -#define H5C2__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, was_dirty, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - if ( ! ((entry_ptr)->is_pinned) ) { \ - \ - /* modified LRU specific code */ \ - \ - /* remove the entry from the LRU list, and re-insert it at the head. \ - */ \ - \ - H5C2__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)) \ - \ - H5C2__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)) \ - \ - /* remove the entry from either the clean or dirty LUR list as \ - * indicated by the was_dirty parameter \ - */ \ - if ( was_dirty ) { \ - \ - H5C2__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 { \ - \ - H5C2__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)) \ - } \ - \ - /* insert the entry at the head of either the clean or dirty LRU \ - * list as appropriate. \ - */ \ - \ - if ( (entry_ptr)->is_dirty ) { \ - \ - H5C2__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 { \ - \ - H5C2__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. */ \ - } \ -} /* H5C2__UPDATE_RP_FOR_RENAME */ - -#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - -#define H5C2__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, was_dirty, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - if ( ! ((entry_ptr)->is_pinned) ) { \ - \ - /* modified LRU specific code */ \ - \ - /* remove the entry from the LRU list, and re-insert it at the head. \ - */ \ - \ - H5C2__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)) \ - \ - H5C2__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. */ \ - } \ -} /* H5C2__UPDATE_RP_FOR_RENAME */ - -#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - - -/*------------------------------------------------------------------------- - * - * Macro: H5C2__UPDATE_RP_FOR_SIZE_CHANGE - * - * Purpose: Update the replacement policy data structures for a - * size change of the specified cache entry. - * - * To do this, determine if the entry is pinned. If it is, - * update the size of the pinned entry list. - * - * If it isn't pinned, the entry must handled by the - * replacement policy. Update the appropriate replacement - * policy data structures. - * - * At present, we only support the modified LRU policy, so - * this function deals with that case unconditionally. If - * we ever support other replacement policies, the function - * should switch on the current policy and act accordingly. - * - * Return: N/A - * - * Programmer: John Mainzer, 8/23/06 - * - * Modifications: - * - * JRM -- 3/28/07 - * Added sanity checks based on the new is_read_only and - * ro_ref_count fields of struct H5C2_cache_entry_t. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS - -#define H5C2__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_size) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - HDassert( new_size > 0 ); \ - \ - if ( (entry_ptr)->is_pinned ) { \ - \ - H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->pel_len, \ - (cache_ptr)->pel_size, \ - (entry_ptr)->size, \ - (new_size)); \ - \ - } else { \ - \ - /* modified LRU specific code */ \ - \ - /* Update the size of the LRU list */ \ - \ - H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->LRU_list_len, \ - (cache_ptr)->LRU_list_size, \ - (entry_ptr)->size, \ - (new_size)); \ - \ - /* Similarly, update the size of the clean or dirty LRU list as \ - * appropriate. At present, the entry must be clean, but that \ - * could change. \ - */ \ - \ - if ( (entry_ptr)->is_dirty ) { \ - \ - H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->dLRU_list_len, \ - (cache_ptr)->dLRU_list_size, \ - (entry_ptr)->size, \ - (new_size)); \ - \ - } else { \ - \ - H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->cLRU_list_len, \ - (cache_ptr)->cLRU_list_size, \ - (entry_ptr)->size, \ - (new_size)); \ - } \ - \ - /* End modified LRU specific code. */ \ - } \ - \ -} /* H5C2__UPDATE_RP_FOR_SIZE_CHANGE */ - -#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - -#define H5C2__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_size) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->size > 0 ); \ - HDassert( new_size > 0 ); \ - \ - if ( (entry_ptr)->is_pinned ) { \ - \ - H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->pel_len, \ - (cache_ptr)->pel_size, \ - (entry_ptr)->size, \ - (new_size)); \ - \ - } else { \ - \ - /* modified LRU specific code */ \ - \ - /* Update the size of the LRU list */ \ - \ - H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->LRU_list_len, \ - (cache_ptr)->LRU_list_size, \ - (entry_ptr)->size, \ - (new_size)); \ - \ - /* End modified LRU specific code. */ \ - } \ - \ -} /* H5C2__UPDATE_RP_FOR_SIZE_CHANGE */ - -#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - - -/*------------------------------------------------------------------------- - * - * Macro: H5C2__UPDATE_RP_FOR_UNPIN - * - * Purpose: Update the replacement policy data structures for an - * unpin of the specified cache entry. - * - * To do this, unlink the specified entry from the protected - * entry 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 macro - * should switch on the current policy and act accordingly. - * - * Return: N/A - * - * Programmer: John Mainzer, 3/22/06 - * - * Modifications: - * - * JRM -- 3/28/07 - * Added sanity checks based on the new is_read_only and - * ro_ref_count fields of struct H5C2_cache_entry_t. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS - -#define H5C2__UPDATE_RP_FOR_UNPIN(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->is_pinned); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - /* Regardless of the replacement policy, remove the entry from the \ - * pinned entry list. \ - */ \ - H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \ - (cache_ptr)->pel_tail_ptr, (cache_ptr)->pel_len, \ - (cache_ptr)->pel_size, (fail_val)) \ - \ - /* modified LRU specific code */ \ - \ - /* insert the entry at the head of the LRU list. */ \ - \ - H5C2__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 ) { \ - \ - H5C2__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 { \ - \ - H5C2__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. */ \ - \ -} /* H5C2__UPDATE_RP_FOR_UNPIN */ - -#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - -#define H5C2__UPDATE_RP_FOR_UNPIN(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ - HDassert( (entry_ptr) ); \ - HDassert( !((entry_ptr)->is_protected) ); \ - HDassert( !((entry_ptr)->is_read_only) ); \ - HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ - HDassert( (entry_ptr)->is_pinned); \ - HDassert( (entry_ptr)->size > 0 ); \ - \ - /* Regardless of the replacement policy, remove the entry from the \ - * pinned entry list. \ - */ \ - H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \ - (cache_ptr)->pel_tail_ptr, (cache_ptr)->pel_len, \ - (cache_ptr)->pel_size, (fail_val)) \ - \ - /* modified LRU specific code */ \ - \ - /* insert the entry at the head of the LRU list. */ \ - \ - H5C2__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. */ \ - \ -} /* H5C2__UPDATE_RP_FOR_UNPIN */ - -#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - - -/*------------------------------------------------------------------------- - * - * Macro: H5C2__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 H5C2_update_rp_for_unprotect() to - * the macro H5C2__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. - * - * JRM - 3/17/06 - * Modified macro to put pinned entries on the pinned entry - * list instead of inserting them in the data structures - * maintained by the replacement policy. - * - *------------------------------------------------------------------------- - */ - -#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS - -#define H5C2__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_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. \ - */ \ - H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pl_head_ptr, \ - (cache_ptr)->pl_tail_ptr, (cache_ptr)->pl_len, \ - (cache_ptr)->pl_size, (fail_val)) \ - \ - if ( (entry_ptr)->is_pinned ) { \ - \ - H5C2__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \ - (cache_ptr)->pel_tail_ptr, \ - (cache_ptr)->pel_len, \ - (cache_ptr)->pel_size, (fail_val)) \ - \ - } else { \ - \ - /* modified LRU specific code */ \ - \ - /* insert the entry at the head of the LRU list. */ \ - \ - H5C2__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 ) { \ - \ - H5C2__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 { \ - \ - H5C2__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. */ \ - } \ - \ -} /* H5C2__UPDATE_RP_FOR_UNPROTECT */ - -#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - -#define H5C2__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, fail_val) \ -{ \ - HDassert( (cache_ptr) ); \ - HDassert( (cache_ptr)->magic == H5C2__H5C2_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. \ - */ \ - H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pl_head_ptr, \ - (cache_ptr)->pl_tail_ptr, (cache_ptr)->pl_len, \ - (cache_ptr)->pl_size, (fail_val)) \ - \ - if ( (entry_ptr)->is_pinned ) { \ - \ - H5C2__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \ - (cache_ptr)->pel_tail_ptr, \ - (cache_ptr)->pel_len, \ - (cache_ptr)->pel_size, (fail_val)) \ - \ - } else { \ - \ - /* modified LRU specific code */ \ - \ - /* insert the entry at the head of the LRU list. */ \ - \ - H5C2__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. */ \ - } \ -} /* H5C2__UPDATE_RP_FOR_UNPROTECT */ - -#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ - - /* * Private file-scope variables. */ @@ -2867,18 +426,27 @@ done: * Added initialization for metadata journaling related * fields in H5C2_t. * + * JRM -- 3/26/08 + * Added dxpl_id and journal_recovered parameters. Also + * added code to test to see if the file is marked as having + * journaling in progress, and fail if it does unless + * the journal_recovered parameter is TRUE. + * *------------------------------------------------------------------------- */ H5C2_t * -H5C2_create(size_t max_cache_size, +H5C2_create(H5F_t * f, + hid_t dxpl_id, + size_t max_cache_size, size_t min_clean_size, int max_type_id, const char * (* type_name_table_ptr), H5C2_write_permitted_func_t check_write_permitted, hbool_t write_permitted, H5C2_log_flush_func_t log_flush, - void * aux_ptr) + void * aux_ptr, + hbool_t journal_recovered) { int i; H5C2_t * cache_ptr = NULL; @@ -2913,8 +481,9 @@ H5C2_create(size_t max_cache_size, HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, NULL, "can't create skip list.") } - /* If we get this far, we should succeed. Go ahead and initialize all - * the fields. + /* If we get this far, we should succeed unless we detect journaling + * that was not cleaned up properly. Go ahead and initialize all + * the fields as we will need some of them for the journaling check. */ cache_ptr->magic = H5C2__H5C2_T_MAGIC; @@ -3056,12 +625,25 @@ H5C2_create(size_t max_cache_size, /* metadata journaling related fields */ cache_ptr->mdj_enabled = FALSE; + cache_ptr->trans_in_progress = FALSE; + cache_ptr->trans_api_name[0] = '\0'; + cache_ptr->trans_num = 0; + cache_ptr->last_trans_on_disk = 0; cache_ptr->mdj_file_name_ptr = NULL; cache_ptr->mdj_conf_block_addr = HADDR_UNDEF; cache_ptr->mdj_conf_block_len = 0; cache_ptr->mdj_conf_block_ptr = NULL; (cache_ptr->mdj_jbrb).magic = H5C2__H5C2_JBRB_T_MAGIC; + cache_ptr->tl_len = 0; + cache_ptr->tl_size = 0; + cache_ptr->tl_head_ptr = NULL; + cache_ptr->tl_tail_ptr = NULL; + cache_ptr->jwipl_len = 0; + cache_ptr->jwipl_size = 0; + cache_ptr->jwipl_head_ptr = NULL; + cache_ptr->jwipl_tail_ptr = NULL; + if ( H5C2_reset_cache_hit_rate_stats(cache_ptr) != SUCCEED ) { @@ -3076,6 +658,19 @@ H5C2_create(size_t max_cache_size, cache_ptr->skip_dxpl_id_checks = FALSE; cache_ptr->prefix[0] = '\0'; /* empty string */ + /* test to see if there is a metadata journal that must be recovered + * before we can access the file. Do this now after the cache is + * initialized, as the code for this test assumes a functional + * cache. + */ + + if ( H5C2_check_for_journaling(f, dxpl_id, cache_ptr, journal_recovered) + != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, NULL, \ + "H5C2_check_for_journaling() reports failure.") + } + /* Set return value */ ret_value = cache_ptr; @@ -3436,6 +1031,11 @@ done: * The function lost its file pointer (now passed in the * *cache_ptr), and one of the dxpl ids. * + * JRM -- 4/3/08 + * I don't think we need to do anything on an expunge + * vis-a-vis journaling. Comment is here just to make + * note of the fact that I have reviewed this function. + * *------------------------------------------------------------------------- */ @@ -3446,13 +1046,18 @@ H5C2_expunge_entry(H5F_t * f, haddr_t addr) { /* const char * fcn_name = "H5C2_expunge_entry()"; */ - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t result; herr_t ret_value = SUCCEED; /* Return value */ H5C2_cache_entry_t * entry_ptr = NULL; FUNC_ENTER_NOAPI(H5C2_expunge_entry, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( H5F_addr_defined(addr) ); HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); @@ -3638,6 +1243,9 @@ done: * but one can argue that I should just scream and die if I * ever detect the condidtion. * + * JRM -- 4/10/08 + * Added code to support journaling. + * *------------------------------------------------------------------------- */ herr_t @@ -3645,7 +1253,7 @@ H5C2_flush_cache(H5F_t *f, hid_t dxpl_id, unsigned flags) { - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t status; herr_t ret_value = SUCCEED; hbool_t destroy; @@ -3667,6 +1275,11 @@ H5C2_flush_cache(H5F_t *f, FUNC_ENTER_NOAPI(H5C2_flush_cache, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( cache_ptr->skip_file_checks || f); @@ -3686,6 +1299,17 @@ H5C2_flush_cache(H5F_t *f, HDassert( ! ( cache_ptr->flush_in_progress ) ); + if ( cache_ptr->mdj_enabled ) { + + status = H5C2_journal_pre_flush(cache_ptr); + + if ( status != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "H5C2_journal_pre_flush() failed.") + } + } + cache_ptr->flush_in_progress = TRUE; if ( destroy ) { @@ -3971,7 +1595,19 @@ H5C2_flush_cache(H5F_t *f, } #endif /* H5C2_DO_SANITY_CHECKS */ - } + } + + if ( cache_ptr->mdj_enabled ) { + + status = H5C2_journal_post_flush(cache_ptr, + (hbool_t)(flush_marked_entries == FALSE)); + + if ( status != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "H5C2_journal_post_flush() failed.") + } + } done: @@ -4044,7 +1680,7 @@ herr_t H5C2_flush_to_min_clean(H5F_t * f, hid_t dxpl_id) { - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t result; herr_t ret_value = SUCCEED; hbool_t write_permitted; @@ -4059,6 +1695,11 @@ H5C2_flush_to_min_clean(H5F_t * f, FUNC_ENTER_NOAPI(H5C2_flush_to_min_clean, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( cache_ptr->skip_file_checks || f ); @@ -4426,18 +2067,23 @@ H5C2_get_entry_status(H5F_t * f, hbool_t * is_pinned_ptr) { /* const char * fcn_name = "H5C2_get_entry_status()"; */ - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t ret_value = SUCCEED; /* Return value */ H5C2_cache_entry_t * entry_ptr = NULL; FUNC_ENTER_NOAPI(H5C2_get_entry_status, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr != NULL ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( H5F_addr_defined(addr) ); HDassert( in_cache_ptr != NULL ); - /* this test duplicates tow of the above asserts, but we need an + /* this test duplicates two of the above asserts, but we need an * invocation of HGOTO_ERROR to keep the compiler happy. */ if ( ( cache_ptr == NULL ) || ( cache_ptr->magic != H5C2__H5C2_T_MAGIC ) ) { @@ -4670,6 +2316,12 @@ done: * JRM -- 12/31/07 * Added code supporting flash cache size increases. * + * JRM -- 3/26/08 + * Added code initializing the journaling related fields. + * Also added code to set the new entries last_trans field + * to the current transaction number and insert the entry + * in the transaction list if journaling is enabled. + * *------------------------------------------------------------------------- */ @@ -4683,7 +2335,7 @@ H5C2_insert_entry(H5F_t * f, unsigned int flags) { /* const char * fcn_name = "H5C2_insert_entry()"; */ - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t result; herr_t ret_value = SUCCEED; /* Return value */ hbool_t insert_pinned; @@ -4694,9 +2346,16 @@ H5C2_insert_entry(H5F_t * f, FUNC_ENTER_NOAPI(H5C2_insert_entry, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( cache_ptr->skip_file_checks || f ); + HDassert( ( ! ( cache_ptr->mdj_enabled ) ) || + ( cache_ptr->trans_in_progress ) ); HDassert( type ); HDassert( H5F_addr_defined(addr) ); HDassert( thing ); @@ -4754,6 +2413,10 @@ H5C2_insert_entry(H5F_t * f, entry_ptr->aux_next = NULL; entry_ptr->aux_prev = NULL; + entry_ptr->last_trans = 0; + entry_ptr->trans_next = NULL; + entry_ptr->trans_prev = NULL; + H5C2__RESET_CACHE_ENTRY_STATS(entry_ptr) if ( ( cache_ptr->flash_size_increase_possible ) && @@ -4888,6 +2551,9 @@ H5C2_insert_entry(H5F_t * f, entry_ptr->flush_marker = FALSE; } + /* insert the entry in the transaction list if journaling is enabled */ + H5C2__INSERT_ENTRY_IN_TL(cache_ptr, entry_ptr, FAIL); + H5C2__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, FAIL) #if H5C2_DO_EXTREME_SANITY_CHECKS @@ -5012,6 +2678,7 @@ H5C2_mark_entries_as_clean(H5F_t * f, FUNC_ENTER_NOAPI(H5C2_mark_entries_as_clean, FAIL) HDassert( f ); + HDassert( f->shared ); cache_ptr = f->shared->cache2; HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); @@ -5264,6 +2931,15 @@ done: * appropriate. * JRM -- 1/11/08 * + * Added code to either insert the entry at the head of + * the transaction list (if it isn't in the list already), or + * move it to the head of the transaction list (if it is + * on the transaction list) if journaling is enabled. In this + * case, set the entry's last_trans field to the current + * transaction number if it isn't set to this value already. + * + * JRM -- 3/31/08 + * *------------------------------------------------------------------------- */ @@ -5273,7 +2949,7 @@ H5C2_mark_pinned_entry_dirty(H5F_t * f, hbool_t size_changed, size_t new_size) { - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t ret_value = SUCCEED; /* Return value */ herr_t result; size_t size_increase; @@ -5281,8 +2957,15 @@ H5C2_mark_pinned_entry_dirty(H5F_t * f, FUNC_ENTER_NOAPI(H5C2_mark_pinned_entry_dirty, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( ( ! ( cache_ptr->mdj_enabled ) ) || + ( cache_ptr->trans_in_progress ) ); HDassert( thing ); HDassert( ( size_changed == TRUE ) || ( size_changed == FALSE ) ); @@ -5329,7 +3012,7 @@ H5C2_mark_pinned_entry_dirty(H5F_t * f, } } - /* update the protected entry list */ + /* update the pinned entry list */ H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr->pel_len), \ (cache_ptr->pel_size), \ (entry_ptr->size), (new_size)); @@ -5345,9 +3028,15 @@ H5C2_mark_pinned_entry_dirty(H5F_t * f, (new_size)); } + /* if journaling is enabled, and the entry is already in the + * transaction list, update that list for the size change as well. + */ + H5C2__UPDATE_TL_FOR_ENTRY_SIZE_CHANGE((cache_ptr), (entry_ptr), \ + (entry_ptr->size), (new_size)); + /* update statistics just before changing the entry size */ H5C2__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE((cache_ptr), (entry_ptr), \ - (new_size)); + (new_size)); /* finally, update the entry size proper */ entry_ptr->size = new_size; @@ -5358,6 +3047,12 @@ H5C2_mark_pinned_entry_dirty(H5F_t * f, H5C2__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) } + /* if journaling is enabled, check to see if the entry is in the + * transaction list. If it isn't, insert it. If it is, move it to + * the head of the list. + */ + H5C2__UPDATE_TL_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr, FAIL) + H5C2__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr) done: @@ -5398,18 +3093,27 @@ done: * it once we deal with the problem of entries being protected * read only, and then dirtied. * + * JRM -- 3/31/08 + * Updated function to maintain the transaction list when + * journaling is enabled. + * *------------------------------------------------------------------------- */ herr_t H5C2_mark_pinned_or_protected_entry_dirty(H5F_t * f, void * thing) { - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t ret_value = SUCCEED; /* Return value */ H5C2_cache_entry_t * entry_ptr; FUNC_ENTER_NOAPI(H5C2_mark_pinned_or_protected_entry_dirty, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( thing ); @@ -5423,11 +3127,20 @@ H5C2_mark_pinned_or_protected_entry_dirty(H5F_t * f, /* set the dirtied flag */ entry_ptr->dirtied = TRUE; + /* don't do anything with the transaction list now, as the + * entry will be added to the transaction list when it is + * unprotected. + */ + } else if ( entry_ptr->is_pinned ) { /* mark the entry as dirty if it isn't already */ entry_ptr->is_dirty = TRUE; + /* If journaling is enabled, must add the entry to the transaction + * list, if it is not there already. + */ + H5C2__UPDATE_TL_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr, FAIL); if ( ! (entry_ptr->in_slist) ) { @@ -5438,8 +3151,8 @@ H5C2_mark_pinned_or_protected_entry_dirty(H5F_t * f, } else { - HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ - "Entry is neither pinned nor protected??") + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ + "Entry is neither pinned nor protected??") } done: @@ -5479,7 +3192,7 @@ done: * Updated function to support renaming of pinned entries. * * JRM -- 8/24/06 - * Updated function to refrain from alterning the index, the + * Updated function to refrain from altering the index, the * replacement policy data structures, and skip list when * the function is called within the flush callback for the * target entry and the target entry is being destroyed. @@ -5492,6 +3205,17 @@ done: * now handled by H5C2_flush_single_entry() -- hence the above * modification is now obsolete. * + * JRM -- 3/31/08 + * Updated function to check if journaling is enabled. If + * it is, the function now inserts the renamed entry in the + * transaction list (if it wasn't there already). + * + * Also added sanity checks that will scream and die if + * we attempt to rename an entry during either a destroy + * or flush if journaling is enabled. Recall that any + * rename should have already been triggered when the + * entry was serialized to construct its journal entry. + * *------------------------------------------------------------------------- */ @@ -5503,6 +3227,7 @@ H5C2_rename_entry(H5C2_t * cache_ptr, { herr_t ret_value = SUCCEED; /* Return value */ hbool_t was_dirty; + hbool_t had_jwip; H5C2_cache_entry_t * entry_ptr = NULL; H5C2_cache_entry_t * test_entry_ptr = NULL; #if H5C2_DO_SANITY_CHECKS @@ -5543,6 +3268,20 @@ H5C2_rename_entry(H5C2_t * cache_ptr, "Target entry is protected.") } + if ( ( entry_ptr->destroy_in_progress ) && + ( cache_ptr->mdj_enabled ) ) + { + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "rename on destroy when journaling is enabled.\n"); + } + + if ( ( entry_ptr->flush_in_progress ) && + ( cache_ptr->mdj_enabled ) ) + { + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "rename on flush when journaling is enabled.\n"); + } + H5C2__SEARCH_INDEX(cache_ptr, new_addr, test_entry_ptr, FAIL) if ( test_entry_ptr != NULL ) { /* we are hosed */ @@ -5629,7 +3368,19 @@ H5C2_rename_entry(H5C2_t * cache_ptr, #endif /* H5C2_DO_SANITY_CHECKS */ - H5C2__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, was_dirty, FAIL) + /* make note of whether the target entry had a journal write + * in progress -- will need this fact to update the replacement + * policy structures for the rename. + */ + had_jwip = ( entry_ptr->last_trans != 0 ); + + /* If journaling is enabled, add the entry to the transaction + * list, if it isn't there already. + */ + H5C2__UPDATE_TL_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr, FAIL); + + H5C2__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, was_dirty, \ + had_jwip, FAIL); } } @@ -5679,14 +3430,19 @@ H5C2_resize_pinned_entry(H5F_t * f, size_t new_size) { /* const char * fcn_name = "H5C2_resize_pinned_entry()"; */ - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t ret_value = SUCCEED; /* Return value */ herr_t result; H5C2_cache_entry_t * entry_ptr; - size_t size_increase; + size_t size_increase; FUNC_ENTER_NOAPI(H5C2_resize_pinned_entry, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( thing ); @@ -5818,12 +3574,17 @@ H5C2_pin_protected_entry(H5F_t UNUSED * f, void * thing) #endif { - H5C2_t *cache_ptr = f->shared->cache2; - herr_t ret_value = SUCCEED; /* Return value */ - H5C2_cache_entry_t * entry_ptr; + H5C2_t * cache_ptr; + herr_t ret_value = SUCCEED; /* Return value */ + H5C2_cache_entry_t * entry_ptr; FUNC_ENTER_NOAPI(H5C2_pin_protected_entry, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( thing ); @@ -5944,6 +3705,11 @@ done: * Added to do a flash cache size increase if appropriate * when a large entry is loaded. * + * JRM 3/31/08 + * Updated function to insert the newly protected entry in + * the transaction list if journaling is enabled and the + * entry was dirtied on load. + * *------------------------------------------------------------------------- */ @@ -5957,7 +3723,7 @@ H5C2_protect(H5F_t * f, unsigned flags) { /* const char * fcn_name = "H5C2_protect()"; */ - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; hbool_t hit; hbool_t first_flush; hbool_t have_write_permitted = FALSE; @@ -5972,6 +3738,11 @@ H5C2_protect(H5F_t * f, FUNC_ENTER_NOAPI(H5C2_protect, NULL) /* check args */ + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( cache_ptr->skip_file_checks || f ); @@ -6136,6 +3907,16 @@ H5C2_protect(H5F_t * f, H5C2__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, NULL) } + /* under rare (we hope) circumstances, the load routine will + * modify an entry as it loads it to repair corruption from + * a previous version of the library. If this happens, we must + * place the entry on the transaction list. + */ + if ( entry_ptr->is_dirty ) { + + H5C2__INSERT_ENTRY_IN_TL(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 @@ -6353,7 +4134,7 @@ H5C2_set_cache_auto_resize_config(const H5F_t * f, H5C2_auto_size_ctl_t *config_ptr) { /* const char *fcn_name = "H5C2_set_cache_auto_resize_config()"; */ - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t ret_value = SUCCEED; /* Return value */ herr_t result; size_t new_max_cache_size; @@ -6361,6 +4142,11 @@ H5C2_set_cache_auto_resize_config(const H5F_t * f, FUNC_ENTER_NOAPI(H5C2_set_cache_auto_resize_config, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + if ( ( cache_ptr == NULL ) || ( cache_ptr->magic != H5C2__H5C2_T_MAGIC ) ) { HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.") @@ -6637,11 +4423,16 @@ herr_t H5C2_set_evictions_enabled(const H5F_t * f, hbool_t evictions_enabled) { - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5C2_set_evictions_enabled, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + if ( ( cache_ptr == NULL ) || ( cache_ptr->magic != H5C2__H5C2_T_MAGIC ) ) { HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.") @@ -7384,12 +5175,17 @@ herr_t H5C2_unpin_entry(H5F_t * f, void * thing) { - H5C2_t *cache_ptr = f->shared->cache2; + H5C2_t *cache_ptr; herr_t ret_value = SUCCEED; /* Return value */ H5C2_cache_entry_t * entry_ptr; FUNC_ENTER_NOAPI(H5C2_unpin_entry, FAIL) + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( thing ); @@ -7530,7 +5326,7 @@ H5C2_unprotect(H5F_t * f, size_t new_size) { /* const char * fcn_name = "H5C2_unprotect()"; */ - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; hbool_t deleted; hbool_t dirtied; hbool_t set_flush_marker; @@ -7561,6 +5357,11 @@ H5C2_unprotect(H5F_t * f, dirtied |= size_changed; + HDassert( f ); + HDassert( f->shared ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( cache_ptr->skip_file_checks || f ); @@ -10131,6 +7932,11 @@ done: * to disk. If dirty, the entry is removed from the slist * or not as requested. * + * JRM -- 3/31/08 + * If journaling is enabled, modified function to remove + * the target entry from the transaction list on a clear. + * Also added some sanity checks. + * *------------------------------------------------------------------------- */ @@ -10439,6 +8245,18 @@ H5C2_flush_single_entry(H5F_t * f, H5C2__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, FAIL) } else { + /* If journaling is enabled, the target entry is being cleared, + * and it is on the transaction list, remove it from the transaction + * list and set its last_trans field to zero. + * + * Must do this now, as otherwise H5C2__UPDATE_RP_FOR_FLUSH may + * scream incorrectly about flushing an entry with a pending + * journal write. + */ + if ( clear_only ) { + H5C2__UPDATE_TL_FOR_ENTRY_CLEAR(cache_ptr, entry_ptr, FAIL); + } + /* We are either doing a flush or a clear. * * A clear and a flush are the same from the point of view of @@ -10484,8 +8302,6 @@ H5C2_flush_single_entry(H5F_t * f, * or a flush destroy. In either case, serialize the * entry and write it to disk. * - * If the entry is clean, we do nothing at this point. - * * If the serialize function changes the size or location * of the entry, and we are not doing a flush destroy, we * will have to touch up the cache to account for the @@ -10530,6 +8346,12 @@ H5C2_flush_single_entry(H5F_t * f, { if ( destroy ) { + if ( cache_ptr->mdj_enabled ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "rename/resize on destroy when journaling enabled."); + } + /* We have already removed the entry from the * cache's data structures, so no need to update * them for the re-size and/or rename. All we need @@ -10570,6 +8392,12 @@ H5C2_flush_single_entry(H5F_t * f, } else { + if ( cache_ptr->mdj_enabled ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "rename/resize on flush when journaling enabled."); + } + /* The entry is not being destroyed, and thus has not * been removed from the cache's data structures. * @@ -10816,6 +8644,10 @@ done: * JRM -- 10/12/07 * Added initialization for the new magic field. * + * JRM -- 3/26/08 + * Added initialization for the journaling related + * fields. + * *------------------------------------------------------------------------- */ @@ -10948,6 +8780,10 @@ H5C2_load_entry(H5F_t * f, entry_ptr->aux_next = NULL; entry_ptr->aux_prev = NULL; + entry_ptr->last_trans = 0; + entry_ptr->trans_next = NULL; + entry_ptr->trans_prev = NULL; + H5C2__RESET_CACHE_ENTRY_STATS(entry_ptr); ret_value = thing; diff --git a/src/H5C2journal.c b/src/H5C2journal.c index 27eabf7..53d0d71 100644 --- a/src/H5C2journal.c +++ b/src/H5C2journal.c @@ -46,13 +46,100 @@ #include "H5Fpkg.h" /* File access */ #include "H5C2pkg.h" /* Cache */ - + /**************************************************************************/ /************************* journaling code proper *************************/ /**************************************************************************/ /*------------------------------------------------------------------------- - * Function: H5C2__begin_transaction + * Function: H5C2_begin_journaling + * + * Purpose: Setup the metadata cache to begin journaling. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * March 26, 2008 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5C2_begin_journaling(H5F_t * f, + hid_t dxpl_id, + H5C2_t * cache_ptr, + char * journal_file_name_ptr, + size_t buf_size, + int num_bufs, + hbool_t use_aio, + hbool_t human_readable) +{ + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5C2_begin_journaling, FAIL) + + HDassert( f != NULL ); + HDassert( f->name != NULL ); + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( cache_ptr->mdj_enabled == FALSE ); + HDassert( cache_ptr->trans_in_progress == FALSE ); + HDassert( cache_ptr->trans_num == 0 ); + HDassert( cache_ptr->last_trans_on_disk == 0 ); + HDassert( cache_ptr->tl_len == 0 ); + HDassert( cache_ptr->tl_size == 0 ); + HDassert( cache_ptr->tl_head_ptr == NULL ); + HDassert( cache_ptr->tl_tail_ptr == NULL ); + HDassert( cache_ptr->jwipl_len == 0 ); + HDassert( cache_ptr->jwipl_size == 0 ); + HDassert( cache_ptr->jwipl_head_ptr == NULL ); + HDassert( cache_ptr->jwipl_tail_ptr == NULL ); + HDassert( buf_size > 0 ); + HDassert( num_bufs > 0 ); + HDassert( journal_file_name_ptr != NULL ); + + if ( cache_ptr->mdj_enabled ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "metadata journaling already enabled on entry.") + } + + result = H5C2_jb__init(&(cache_ptr->mdj_jbrb), + f->name, + journal_file_name_ptr, + buf_size, + num_bufs, + use_aio, + human_readable); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, "H5C2_jb__init() failed.") + } + + result = H5C2_mark_journaling_in_progress(f, + dxpl_id, + journal_file_name_ptr); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_mark_journaling_in_progress() failed.") + } + + cache_ptr->mdj_enabled = TRUE; + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C2_begin_journaling() */ + + +/*------------------------------------------------------------------------- + * Function: H5C2_begin_transaction * * Purpose: Handle book keeping for the beginning of a transaction, and * return the transaction ID assigned to the transaction in @@ -67,37 +154,136 @@ *------------------------------------------------------------------------- */ -/* This function is just a shell for now. -- JRM */ +herr_t +H5C2_begin_transaction(H5C2_t * cache_ptr, + uint64_t * trans_num_ptr, + const char * api_call_name) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5C2_begin_transaction, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( cache_ptr->tl_len == 0 ); + HDassert( cache_ptr->tl_size == 0 ); + HDassert( cache_ptr->tl_head_ptr == NULL ); + HDassert( cache_ptr->tl_tail_ptr == NULL ); + HDassert( trans_num_ptr != NULL ); + HDassert( api_call_name != NULL ); + HDassert( HDstrlen(api_call_name) <= H5C2__MAX_API_NAME_LEN ); + + if ( cache_ptr->mdj_enabled ) { + + if ( cache_ptr->trans_in_progress ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "transaction already in progress?.") + } + + HDstrncpy(cache_ptr->trans_api_name, api_call_name, + (size_t)H5C2__MAX_API_NAME_LEN); + cache_ptr->trans_num++; + + *trans_num_ptr = cache_ptr->trans_num; + + cache_ptr->trans_in_progress = TRUE; + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C2_begin_transaction() */ + + +/*------------------------------------------------------------------------- + * Function: H5C2_end_journaling + * + * Purpose: Shutdown metadata journaling. + * + * To do this we must: + * + * 1) Flush the cache. This will also flush and truncate the + * journal file. + * + * 2) Mark the superblock to indicate that we are no longer + * journaling. + * + * 3) Tell the journal file write code to shutdown. This will + * also cause the journal file to be deleted. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * April 12, 2008 + * + *------------------------------------------------------------------------- + */ herr_t -H5C2__begin_transaction(H5C2_t * cache_ptr, - uint64_t * trans_num_ptr) +H5C2_end_journaling(H5F_t * f, + hid_t dxpl_id, + H5C2_t * cache_ptr) { + herr_t result; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(H5C2__begin_transaction, FAIL) + FUNC_ENTER_NOAPI(H5C2_end_journaling, FAIL) + HDassert( f != NULL ); HDassert( cache_ptr != NULL ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( cache_ptr->mdj_enabled == TRUE ); + HDassert( cache_ptr->trans_in_progress == FALSE ); + HDassert( cache_ptr->tl_len == 0 ); + HDassert( cache_ptr->tl_size == 0 ); + HDassert( cache_ptr->tl_head_ptr == NULL ); + HDassert( cache_ptr->tl_tail_ptr == NULL ); + + if ( ! cache_ptr->mdj_enabled ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "metadata journaling not enabled on entry.") + } + + result = H5C2_flush_cache(f, dxpl_id, H5C2__NO_FLAGS_SET); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_flush_cache() failed.") + } - /* we need at least one error to keep the macros happy */ - if ( trans_num_ptr == NULL ) { + result = H5C2_unmark_journaling_in_progress(f, dxpl_id, cache_ptr); - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "trans_num_ptr NULL on entry.") + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_unmark_journaling_in_progress() failed.") } - *trans_num_ptr = 1024; + result = H5C2_jb__takedown(&(cache_ptr->mdj_jbrb)); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__takedown() failed.") + } + + cache_ptr->mdj_enabled = FALSE; done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5C2__begin_transaction() */ +} /* H5C2_end_journaling() */ + /*------------------------------------------------------------------------- - * Function: H5C2__end_transaction + * Function: H5C2_end_transaction * * Purpose: Handle book keeping for the end of a transaction. * @@ -110,32 +296,638 @@ done: *------------------------------------------------------------------------- */ -/* This function is just a shell for now. -- JRM */ +herr_t +H5C2_end_transaction(H5F_t * f, + H5C2_t * cache_ptr, + uint64_t trans_num, + const char * api_call_name) +{ + uint64_t new_last_trans_on_disk = 0; + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5C2_end_transaction, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( api_call_name != NULL ); + HDassert( HDstrlen(api_call_name) <= H5C2__MAX_API_NAME_LEN ); + HDassert( ( ! ( cache_ptr->mdj_enabled ) ) || + ( HDstrcmp(api_call_name, cache_ptr->trans_api_name) == 0 ) ); + + if ( cache_ptr->mdj_enabled ) { + + if ( ! ( cache_ptr->trans_in_progress ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "transaction not in progress?!?!") + } + + if ( cache_ptr->trans_num != trans_num ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "trans_num mis-match?!?!") + } + + /* if the transaction list is not empty, generate journal messages, + * and remove all entries from the transaction list. + */ + if ( cache_ptr->tl_len > 0 ) { + + result = H5C2_journal_transaction(f, cache_ptr); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_journal_transaction() failed.") + } + } + + cache_ptr->trans_in_progress = FALSE; + + /* Get the last transaction on disk. If it has changed, remove + * all entries with completed journal writes from the journal write + * in progress list. + */ + + result = H5C2_jb__get_last_transaction_on_disk(&(cache_ptr->mdj_jbrb), + &new_last_trans_on_disk); + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__get_last_transaction_on_disk() failed.") + } + + if ( cache_ptr->last_trans_on_disk < new_last_trans_on_disk ) { + + result = H5C2_update_for_new_last_trans_on_disk(cache_ptr, + new_last_trans_on_disk); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_update_for_new_last_trans_on_disk() failed.") + } + } + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C2_end_transaction() */ + + +/*------------------------------------------------------------------------- + * Function: H5C2_get_journal_config + * + * Purpose: Return the current metadata journaling status. + * + * If journaling is enabled, *journaling_enabled_ptr is + * set to TRUE, and the targets of the remaining pointer + * parameters will be set to reflect current journaling + * status if they are not NULL. + * + * If journaling is disabled, *journaling_enabled_ptr is set + * to FALSE, and the the targets of the remaining pointer + * parameters are not altered. + * + * The remaining parameters are discussed in detail below: + * + * journal_file_path_ptr is presumed to point to a buffer + * of length H5AC2__MAX_JOURNAL_FILE_NAME_LEN. If journaling + * is enabled, and the field is not null, the path to the + * journal file will be copied into this buffer to the + * extent that it fits. + * + * jbrb_buf_size_ptr is presumed to point to a size_t. If + * journaling is enabled and the field is not NULL, the size + * of the buffers used in the journal buffer ring buffer + * will be reported in *jbrb_buf_size_ptr. + * + * jbrb_num_bufs_ptr is presumed to point to an int. If + * journaling is enabled and the field is not NULL, the + * number of buffers in the ournal buffer ring buffer + * will be reported in *jbrb_num_bufs_ptr. + * + * jbrb_use_aio_ptr is presumed to point to a hbool_t. If + * journaling is enabled and the field is not NULL, + * *jbrb_use_aio_ptr will be set to true or false depending + * on whether the journal entry logging code has been + * instructed to use AIO. + * + * jbrb_human_readable_ptr is presumed to point to a hbool_t. If + * journaling is enabled and the field is not NULL, + * *jbrb_human_readable_ptr will be set to true or false depending + * on whether the journal entry logging code has been + * instructed to record the journal in human readable form. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * April 13, 2008 + * + *------------------------------------------------------------------------- + */ herr_t -H5C2__end_transaction(H5C2_t * cache_ptr, - uint64_t trans_num) +H5C2_get_journal_config(H5C2_t * cache_ptr, + hbool_t * journaling_enabled_ptr, + char * journal_file_path_ptr, + size_t * jbrb_buf_size_ptr, + int * jbrb_num_bufs_ptr, + hbool_t * jbrb_use_aio_ptr, + hbool_t * jbrb_human_readable_ptr) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(H5C2__end_transaction, FAIL) + FUNC_ENTER_NOAPI(H5C2_get_journal_config, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + + if ( journaling_enabled_ptr == NULL ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "journaling_enabled_ptr NULL on entry!?!.") + } + + + if ( cache_ptr->mdj_enabled ) { + + *journaling_enabled_ptr = TRUE; + + if ( journal_file_path_ptr != NULL ) { + + HDsnprintf(journal_file_path_ptr, + H5AC2__MAX_JOURNAL_FILE_NAME_LEN, + "%s", + cache_ptr->mdj_file_name_ptr); + } + + if ( jbrb_buf_size_ptr != NULL ) { + + *jbrb_buf_size_ptr = (cache_ptr->mdj_jbrb).buf_size; + } + + if ( jbrb_num_bufs_ptr != NULL ) { + + *jbrb_num_bufs_ptr = (cache_ptr->mdj_jbrb).num_bufs; + } + + if ( jbrb_use_aio_ptr != NULL ) { + + *jbrb_use_aio_ptr = (cache_ptr->mdj_jbrb).use_aio; + } + + if ( jbrb_human_readable_ptr ) { + + *jbrb_human_readable_ptr = (cache_ptr->mdj_jbrb).human_readable; + } + + } else { + + *journaling_enabled_ptr = FALSE; + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C2_get_journal_config() */ + + +/*------------------------------------------------------------------------- + * Function: H5C2_journal_post_flush() + * + * Purpose: Handle any journaling activities that are necessary + * after we flush the metadata cache. + * + * At present this means: + * + * 1) Verify that a transaction is still not in progress. + * + * 2) Verify that the journal write in progress list + * is still empty. + * + * 3) If the cache_is_clean parameter is true: + * + * a) Truncate the journal file + * + * b) Reset cache_ptr->trans_num and + * cache_ptr->last_trans_on_disk to zero. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * April 10, 2008 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5C2_journal_post_flush(H5C2_t * cache_ptr, + hbool_t cache_is_clean) +{ + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5C2_journal_post_flush, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( cache_ptr->mdj_enabled ); + + if ( cache_ptr->trans_in_progress ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Transaction in progress during flush?!?!?.") + } + + if ( cache_ptr->jwipl_len != 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "journal write in progress list isn't empty?!?!.") + } + + if ( cache_is_clean ) { + + result = H5C2_jb__trunc(&(cache_ptr->mdj_jbrb)); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__trunc() failed.") + } + + cache_ptr->trans_num = (uint64_t)0; + cache_ptr->last_trans_on_disk = (uint64_t)0; + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C2_journal_post_flush() */ + + +/*------------------------------------------------------------------------- + * Function: H5C2_journal_pre_flush() + * + * Purpose: Handle any journaling activities that are necessary + * before we flush the metadata cache. + * + * At present this means: + * + * 1) Verify that a transaction is not in progress. + * + * 2) Flush the journal to disk. + * + * 3) Get the ID of the last transaction on disk. + * + * 4) If the value obtained in 2) above has changed, + * remove all entries whose last transaction has + * made it to disk from the journal write in progress + * list. + * + * 5) Verify that the journal write in progress list is + * empty. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * April 10, 2008 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5C2_journal_pre_flush(H5C2_t * cache_ptr) +{ + herr_t result; + uint64_t new_last_trans_on_disk; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5C2_journal_pre_flush, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( cache_ptr->mdj_enabled ); + + if ( cache_ptr->trans_in_progress ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Transaction in progress during flush?!?!?.") + } + + result = H5C2_jb__flush(&(cache_ptr->mdj_jbrb)); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__flush() failed.") + } + + result = H5C2_jb__get_last_transaction_on_disk(&(cache_ptr->mdj_jbrb), + &new_last_trans_on_disk); + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__get_last_transaction_on_disk() failed.") + } + + if ( cache_ptr->last_trans_on_disk < new_last_trans_on_disk ) { + + result = H5C2_update_for_new_last_trans_on_disk(cache_ptr, + new_last_trans_on_disk); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_update_for_new_last_trans_on_disk() failed.") + } + } + + if ( cache_ptr->jwipl_len != 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "journal write in progress list isn't empty?!?!.") + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C2_journal_pre_flush() */ + + +/*------------------------------------------------------------------------- + * Function: H5C2_journal_transaction() + * + * Purpose: Generate journal messages for the current transaction. + * In passing, remove all entries from the transaction list. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * April 3, 2008 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5C2_journal_transaction(H5F_t * f, + H5C2_t * cache_ptr) + +{ + char buf[H5C2__MAX_API_NAME_LEN + 128]; + H5C2_cache_entry_t * entry_ptr = NULL; + unsigned serialize_flags = 0; + haddr_t new_addr; + size_t new_len; + void * new_image_ptr; + void * thing; + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5C2_journal_transaction, FAIL) + HDassert( f != NULL ); HDassert( cache_ptr != NULL ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( cache_ptr->trans_in_progress ); + HDassert( cache_ptr->tl_len > 0 ); + + HDsnprintf(buf, H5C2__MAX_API_NAME_LEN + 128, "Begin transaction on %s.", + cache_ptr->trans_api_name); + + result = H5C2_jb__comment(&(cache_ptr->mdj_jbrb), buf); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__comment() failed.") + } + + result = H5C2_jb__start_transaction(&(cache_ptr->mdj_jbrb), + cache_ptr->trans_num); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__start_transaction() failed.") + } + + entry_ptr = cache_ptr->tl_tail_ptr; + while ( entry_ptr != NULL ) + { + HDassert( entry_ptr->is_dirty ); + HDassert( entry_ptr->last_trans == cache_ptr->trans_num ); + + if ( entry_ptr->is_protected ) + { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "Protected entry in TL at transaction close.") + } + + if ( entry_ptr->image_ptr == NULL ) + { + entry_ptr->image_ptr = H5MM_malloc(entry_ptr->size); + + if ( entry_ptr->image_ptr == NULL ) + { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "memory allocation failed for on disk image buffer.") + } + } + + result = entry_ptr->type->serialize(entry_ptr->addr, + entry_ptr->size, + entry_ptr->image_ptr, + (void *)entry_ptr, + &serialize_flags, + &new_addr, + &new_len, + &new_image_ptr); + if ( result != SUCCEED ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "unable to serialize entry") + } + + if ( serialize_flags != 0 ) + { + /* if the serialize_flags are not zero, the entry has been + * modified as a result of the serialize. Pass these changes + * on to the cache, and don't bother to write a journal entry + * at this time -- the protect/unprotect/rename will move the + * entry to the head of the transaction list, where we will + * handle it later. + */ + hbool_t resized; + hbool_t renamed; + + resized = (serialize_flags & H5C2__SERIALIZE_RESIZED_FLAG) != 0; + renamed = (serialize_flags & H5C2__SERIALIZE_RENAMED_FLAG) != 0; + + if ( ( renamed ) && ( ! resized ) ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "entry renamed but not resized?!?!") + } + + if ( resized ) + { + /* in the following protect/unprotect, use default + * dxpl_id as we know that the entry is in cache, + * and thus no I/O will take place. + */ + thing = H5C2_protect(f, H5P_DATASET_XFER_DEFAULT, + entry_ptr->type, entry_ptr->addr, + entry_ptr->size, NULL, + H5C2__NO_FLAGS_SET); + + if ( thing == NULL ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_protect() failed.") + } + + result = H5C2_unprotect(f, H5P_DATASET_XFER_DEFAULT, + entry_ptr->type, entry_ptr->addr, + thing, H5C2__SIZE_CHANGED_FLAG, + new_len); + + if ( result < 0 ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_unprotect() failed.") + } + + entry_ptr->image_ptr = new_image_ptr; + } + + if ( renamed ) + { + result = H5C2_rename_entry(cache_ptr, entry_ptr->type, + entry_ptr->addr, new_addr); + + if ( result < 0 ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_rename_entr() failed.") + } + } + } + else /* generate the journal entry & remove from transaction list */ + { + result = H5C2_jb__journal_entry(&(cache_ptr->mdj_jbrb), + cache_ptr->trans_num, + entry_ptr->addr, + entry_ptr->size, + entry_ptr->image_ptr); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__journal_entry() failed.") + } + + H5C2__TRANS_DLL_REMOVE(entry_ptr, cache_ptr->tl_head_ptr, \ + cache_ptr->tl_tail_ptr, cache_ptr->tl_len, \ + cache_ptr->tl_size, FAIL); + } + entry_ptr = cache_ptr->tl_tail_ptr; + } + + result = H5C2_jb__end_transaction(&(cache_ptr->mdj_jbrb), + cache_ptr->trans_num); - /* we need at least one error to keep the macros happy */ - if ( trans_num != 1024 ) { + if ( result != SUCCEED ) { - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "unexpected transaction number.") + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__end_transaction() failed.") } done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5C2__end_transaction() */ +} /* H5C2_journal_transaction() */ + + +/*------------------------------------------------------------------------- + * Function: H5C2_update_for_new_last_trans_on_disk() + * + * Purpose: Update the journal write in progress list for a change in + * the last transaction on disk. + * + * Specifically, update the last_trans_on_disk field of + * *cache_ptr, and then scan the journal write in progress + * list for entries whose last_trans field is now less than + * or equal to cache_ptr->last_trans_on_disk. Remove all + * these entries from the journal write in progress list, + * set their last_trans fields to zero, and insert then into + * the eviction policy data structures. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * April 3, 2008 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5C2_update_for_new_last_trans_on_disk(H5C2_t * cache_ptr, + uint64_t new_last_trans_on_disk) +{ + H5C2_cache_entry_t * entry_ptr = NULL; + H5C2_cache_entry_t * prev_entry_ptr = NULL; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5C2_update_for_new_last_trans_on_disk, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( cache_ptr->mdj_enabled ); + HDassert( cache_ptr->last_trans_on_disk <= new_last_trans_on_disk ); + + if ( cache_ptr->last_trans_on_disk < new_last_trans_on_disk ) { + + cache_ptr->last_trans_on_disk = new_last_trans_on_disk; + + entry_ptr = cache_ptr->jwipl_tail_ptr; + + while ( entry_ptr != NULL ) + { + prev_entry_ptr = entry_ptr->next; + + HDassert( entry_ptr->last_trans > 0 ); + + if ( entry_ptr->last_trans <= cache_ptr->last_trans_on_disk ) { + entry_ptr->last_trans = 0; + H5C2__UPDATE_RP_FOR_JOURNAL_WRITE_COMPLETE(cache_ptr, \ + entry_ptr, \ + FAIL) + } + + entry_ptr = prev_entry_ptr; + } + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C2_update_for_new_last_trans_on_disk() */ /**************************************************************************/ @@ -143,7 +935,104 @@ done: /**************************************************************************/ /*------------------------------------------------------------------------- - * Function: H5C2__create_journal_config_block() + * Function: H5C2_check_for_journaling() + * + * Purpose: If the superblock extension of a newly opened HDF5 file + * indicates that journaling is in progress, the process + * that created the file failed to close it properly, and + * thus the file is almost certainly corrupted. + * + * The purpose of this function is to detect this condition, + * and either throw an error telling the user to run the + * recovery tool, or if so directed (presumably by the + * recovery tool) simply delete the metadata journaling + * configuration block and any reference to journaling in the + * superblock extension. + * + * JRM -- 3/26/08 + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * March 26, 2008 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5C2_check_for_journaling(H5F_t * f, + hid_t dxpl_id, + H5C2_t * cache_ptr, + hbool_t journal_recovered) +{ + const char * l0 = + "This file was last written with metadata journaling enabled and was \n"; + const char * l1 = + "not closed cleanly. To allow HDF5 to read this file, please run the \n"; + const char * l2 = + "journal recovery tool on this file. The journal was written \n"; + const char * l3 = "to \""; + const char * l4 = "\".\n"; + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5C2_check_for_journaling, FAIL) + + HDassert( f ); + HDassert( cache_ptr ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( cache_ptr->mdj_conf_block_addr == HADDR_UNDEF ); + HDassert( cache_ptr->mdj_conf_block_len == 0 ); + HDassert( cache_ptr->mdj_conf_block_ptr == NULL ); + HDassert( cache_ptr->mdj_file_name_ptr == NULL ); + + result = H5C2_get_journaling_in_progress(f, dxpl_id, cache_ptr); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_get_journaling_in_progress() failed.") + } + + if ( cache_ptr->mdj_file_name_ptr != NULL ) /* journaling was in progress */ + { + if ( journal_recovered ) { + + /* delete the metadata journaling config block and the + * superblock extenstion refering to it. + */ + + result = H5C2_unmark_journaling_in_progress(f, dxpl_id, cache_ptr); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_unmark_journaling_in_progress() failed.") + } + } else { + + /* we have to play some games here to set up an error message that + * contains the journal file path. In essence, what follows is a + * somewhat modified version of the HGOTO_ERROR() macro. + */ + (void)H5Epush2(H5E_DEFAULT, __FILE__, FUNC, __LINE__, H5E_ERR_CLS_g, + H5E_CACHE, H5E_CANTJOURNAL, "%s%s%s%s%s%s", + l0, l1, l2, l3, cache_ptr->mdj_file_name_ptr, l4); + (void)H5E_dump_api_stack((int)H5_IS_API(FUNC)); + HGOTO_DONE(FAIL) + + } + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C2_check_for_journaling() */ + +/*------------------------------------------------------------------------- + * Function: H5C2_create_journal_config_block() * * Purpose: Given a string containing a journal file name and a pointer * to the associated instance of H5C2_t, allocate a journal @@ -167,7 +1056,7 @@ H5C2_create_journal_config_block(H5F_t * f, hid_t dxpl_id, const char * journal_file_name_ptr) { - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; size_t path_len = 0; hsize_t block_len = 0; haddr_t block_addr = HADDR_UNDEF; @@ -181,6 +1070,8 @@ H5C2_create_journal_config_block(H5F_t * f, FUNC_ENTER_NOAPI(H5C2_create_journal_config_block, FAIL) HDassert( f ); + HDassert( f->shared ); + cache_ptr = f->shared->cache2; HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); @@ -192,7 +1083,7 @@ H5C2_create_journal_config_block(H5F_t * f, HDassert( journal_file_name_ptr != NULL ); - path_len = strlen(journal_file_name_ptr) + 1; + path_len = HDstrlen(journal_file_name_ptr) + 1; HDassert( path_len > 0 ); @@ -277,7 +1168,7 @@ done: /*------------------------------------------------------------------------- - * Function: H5C2__discard_journal_config_block() + * Function: H5C2_discard_journal_config_block() * * Purpose: Free the file and core space allocated to the metadata * journaling configuration block, and re-set all the associated @@ -307,12 +1198,14 @@ herr_t H5C2_discard_journal_config_block(H5F_t * f, hid_t dxpl_id) { - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5C2_discard_journal_config_block, FAIL) HDassert( f ); + HDassert( f->shared ); + cache_ptr = f->shared->cache2; HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); @@ -345,7 +1238,7 @@ done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5AC2__discard_journal_config_block() */ +} /* H5AC2_discard_journal_config_block() */ /*------------------------------------------------------------------------- @@ -381,18 +1274,17 @@ done: */ herr_t -H5C2_get_journaling_in_progress(H5F_t * f, - hid_t dxpl_id) +H5C2_get_journaling_in_progress(const H5F_t * f, + hid_t dxpl_id, + H5C2_t * cache_ptr) { - H5C2_t * cache_ptr = f->shared->cache2; herr_t result; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(H5C2_mark_journaling_in_progress, FAIL) + FUNC_ENTER_NOAPI(H5C2_get_journaling_in_progress, FAIL) HDassert( f ); HDassert( f->shared != NULL ); - HDassert( ! f->shared->mdc_jrnl_enabled ); HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( cache_ptr->mdj_conf_block_addr == HADDR_UNDEF ); @@ -401,9 +1293,13 @@ H5C2_get_journaling_in_progress(H5F_t * f, HDassert( cache_ptr->mdj_file_name_ptr == NULL ); if ( f->shared->mdc_jrnl_enabled == TRUE ) { + + cache_ptr->mdj_conf_block_addr = f->shared->mdc_jrnl_block_loc; + cache_ptr->mdj_conf_block_len = f->shared->mdc_jrnl_block_len; result = H5C2_load_journal_config_block(f, dxpl_id, + cache_ptr, cache_ptr->mdj_conf_block_addr, cache_ptr->mdj_conf_block_len); if ( result != SUCCEED ) { @@ -417,7 +1313,7 @@ done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5AC2__get_journal_config_block() */ +} /* H5C2_get_journaling_in_progress() */ /*------------------------------------------------------------------------- @@ -439,12 +1335,12 @@ done: */ herr_t -H5C2_load_journal_config_block(H5F_t * f, +H5C2_load_journal_config_block(const H5F_t * f, hid_t dxpl_id, + H5C2_t * cache_ptr, haddr_t block_addr, hsize_t block_len) { - H5C2_t * cache_ptr = f->shared->cache2; size_t path_len = 0; void * block_ptr = NULL; uint8_t version; @@ -457,6 +1353,7 @@ H5C2_load_journal_config_block(H5F_t * f, FUNC_ENTER_NOAPI(H5C2_load_journal_config_block, FAIL) HDassert( f ); + HDassert( f->shared ); HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); @@ -510,7 +1407,7 @@ H5C2_load_journal_config_block(H5F_t * f, * the journal file path. */ jfn_ptr = (char *)p; - if ( strlen(jfn_ptr) != path_len - 1 ) { + if ( HDstrlen(jfn_ptr) != path_len - 1 ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ "Bad path_len in metadata journaling configuration block.") @@ -547,7 +1444,7 @@ done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5AC2__load_journal_config_block() */ +} /* H5C2_load_journal_config_block() */ /*------------------------------------------------------------------------- @@ -577,7 +1474,7 @@ H5C2_mark_journaling_in_progress(H5F_t * f, hid_t dxpl_id, const char * journal_file_name_ptr) { - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr; herr_t result; herr_t ret_value = SUCCEED; /* Return value */ @@ -586,6 +1483,9 @@ H5C2_mark_journaling_in_progress(H5F_t * f, HDassert( f != NULL ); HDassert( f->shared != NULL ); HDassert( ! f->shared->mdc_jrnl_enabled ); + + cache_ptr = f->shared->cache2; + HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); HDassert( cache_ptr->mdj_conf_block_addr == HADDR_UNDEF ); @@ -690,11 +1590,13 @@ done: herr_t H5C2_unmark_journaling_in_progress(H5F_t * f, - hid_t dxpl_id) -{ + hid_t dxpl_id, #ifndef NDEBUG - H5C2_t * cache_ptr = f->shared->cache2; + H5C2_t * cache_ptr) +#else /* NDEBUG */ + H5C2_t UNUSED * cache_ptr) #endif /* NDEBUG */ +{ herr_t result; herr_t ret_value = SUCCEED; /* Return value */ @@ -1061,7 +1963,7 @@ H5C2_jb__write_to_buffer(H5C2_jbrb_t * struct_ptr, size_t size, const char * data, hbool_t is_end_trans, - unsigned long trans_num) + uint64_t trans_num) { herr_t ret_value = SUCCEED; unsigned long track_last_trans = 0; @@ -1436,8 +2338,8 @@ H5C2_jb__init(H5C2_jbrb_t * struct_ptr, struct_ptr->human_readable); /* Write the header message into the ring buffer */ - if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, FALSE, 0) - < 0) { + if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, FALSE, + (uint64_t)0) < 0) { HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ "H5C2_jb__write_to_buffer() failed.\n") @@ -1462,8 +2364,8 @@ done: * Wednesday, February 6, 2008 * * Purpose: Verify that there is no transaction in progress, and - * that the supplied transaction number is next in - * sequence. Then construct a start transaction message, + * that the supplied transaction number greater than + * the last. Then construct a start transaction message, * and write it to the current journal buffer. Make note * of the fact that the supplied transaction is in * progress. @@ -1474,7 +2376,7 @@ done: herr_t H5C2_jb__start_transaction(H5C2_jbrb_t * struct_ptr, - unsigned long trans_num) + uint64_t trans_num) { char temp[150]; @@ -1499,8 +2401,8 @@ H5C2_jb__start_transaction(H5C2_jbrb_t * struct_ptr, * with testing? */ - /* Verify that the supplied transaction number is next in sequence */ - if ( (struct_ptr->cur_trans + 1) != trans_num ) { + /* Verify that the supplied transaction number greater than the last */ + if ( (struct_ptr->cur_trans) >= trans_num ) { HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "New transaction out of sequence.") @@ -1531,7 +2433,7 @@ H5C2_jb__start_transaction(H5C2_jbrb_t * struct_ptr, } /* end if */ /* Write start transaction message */ - HDsnprintf(temp, (size_t)150, "1 bgn_trans %ld\n", trans_num); + HDsnprintf(temp, (size_t)150, "1 bgn_trans %llu\n", trans_num); if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, FALSE, trans_num) < 0 ) { @@ -1568,7 +2470,7 @@ done: herr_t H5C2_jb__journal_entry(H5C2_jbrb_t * struct_ptr, - unsigned long trans_num, + uint64_t trans_num, haddr_t base_addr, size_t length, const uint8_t * body) @@ -1609,7 +2511,7 @@ H5C2_jb__journal_entry(H5C2_jbrb_t * struct_ptr, /* Write journal entry */ HDsnprintf(temp, (size_t)(length + 100), - "2 trans_num %ld length %zu base_addr 0x%lx body ", + "2 trans_num %llu length %zu base_addr 0x%lx body ", trans_num, length, (unsigned long)base_addr); /* <== fix this */ @@ -1683,7 +2585,7 @@ done: *****************************************************************************/ herr_t H5C2_jb__end_transaction(H5C2_jbrb_t * struct_ptr, - unsigned long trans_num) + uint64_t trans_num) { char temp[25]; herr_t ret_value = SUCCEED; @@ -1713,7 +2615,7 @@ H5C2_jb__end_transaction(H5C2_jbrb_t * struct_ptr, /* Prepare end transaction message */ - HDsnprintf(temp, (size_t)25, "3 end_trans %ld\n", trans_num); + HDsnprintf(temp, (size_t)25, "3 end_trans %llu\n", trans_num); /* Write end transaction message */ if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, @@ -1825,7 +2727,7 @@ done: herr_t H5C2_jb__get_last_transaction_on_disk(H5C2_jbrb_t * struct_ptr, - unsigned long * trans_num_ptr) + uint64_t * trans_num_ptr) { herr_t ret_value = SUCCEED; @@ -1885,6 +2787,7 @@ herr_t H5C2_jb__trunc(H5C2_jbrb_t * struct_ptr) { + int i; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5C2_jb__trunc, FAIL) @@ -1917,6 +2820,16 @@ H5C2_jb__trunc(H5C2_jbrb_t * struct_ptr) struct_ptr->header_present = FALSE; struct_ptr->journal_is_empty = TRUE; + /* reset the transaction number fields */ + struct_ptr->cur_trans = 0; + struct_ptr->last_trans_on_disk = 0; + + /* reset the transaction tracking array */ + for (i=0; i<struct_ptr->num_bufs; i++) + { + (*struct_ptr->trans_tracking)[i] = 0; + } + if ( HDlseek(struct_ptr->journal_file_fd, (off_t)0, SEEK_SET) == (off_t)-1 ) { HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "Jounal file seek failed.") diff --git a/src/H5C2pkg.h b/src/H5C2pkg.h index 878e372..637e5e9 100644 --- a/src/H5C2pkg.h +++ b/src/H5C2pkg.h @@ -44,7 +44,7 @@ #include "H5SLprivate.h" /* Skip lists */ - /****************************************************************************** +/****************************************************************************** * * Structure: H5C2_jbrb_t * @@ -62,7 +62,7 @@ * * * magic: Unsigned 32-bit integer always set to - * H5C2__H5C2_JBRB_T_MAGIC. This field is used to validate + * H5C2__H5C2_JBRB_T_MAGIC. This field is used to validate * pointers to instances of H5C_jbrb_t. * * journal_file_fd: File Descriptor of the journal file that is being @@ -171,8 +171,8 @@ struct H5C2_jbrb_t hbool_t use_aio; hbool_t human_readable; hbool_t journal_is_empty; - unsigned long cur_trans; - unsigned long last_trans_on_disk; + uint64_t cur_trans; + uint64_t last_trans_on_disk; hbool_t trans_in_prog; const char * jname; const char * hdf5_file_name; @@ -727,11 +727,41 @@ struct H5C2_jbrb_t * be able to re-construct a HDF5 file with a consistent set of metadata * in the event of a crash. * - * mdj_enabled: Boolean flag used to indicate whether journaling is + * mdj_enabled: Boolean flag used to indicate whether journaling is * currently enabled. In general, the values of the * remaining fields in this section are undefined if * mdj_enabled is FALSE. * + * trans_in_progress Boolean flag used to indicate whether a metadata + * transaction is in progress. + * + * For purposes of metadata journaling, a transaction is a + * sequence of operations on metadata selected such that + * the HDF5 file metadata is in a consistent state both at + * the beginning and at the end of the sequence. + * + * At least to begin with, transactions will be closely tied + * to user level API calls. + * + * trans_api_name: Array of char of length H5C2__MAX_API_NAME_LEN + 1. Used + * to store the name of the API call associated with the + * current transaction. + * + * trans_num: uint64_t containing the id assigned to the current + * transaction (if trans_in_progress is TRUE), or of the + * last transaction completed (if trans_in_progress is FALSE), + * or zero if no transaction has been initiated yet. + * + * last_trans_on_disk: uint64_t containing the id assigned to the + * last transaction all of whose associated journal entries + * are on disk in the journal file. + * + * We must track this value, as to avoid messages from the + * future, we must not write a cache entry to file until + * the journal entries of all transactions in which it has + * been modified have been written to disk in the journal + * file. + * * mdj_file_name_ptr: Pointer to a string containing the path of the * journal file, or NULL if this path is undefined. * At present, the journal will always be stored in an @@ -775,6 +805,67 @@ struct H5C2_jbrb_t * mdj_jbrb: Instance of H5C2_jbrb_t used to manage logging of journal * entries to the journal file. * + * While a transaction is in progress, we must maintain a list of the + * entries that have been modified during the transaction so we can + * generate the appropriate journal entries. The following fields are + * used to maintain this list: + * + * tl_len: Number of entries currently residing on the transaction list. + * + * tl_size: Number of bytes of cache entries currently residing on the + * transaction list. + * + * tl_head_ptr: Pointer to the head of the doubly linked list of entries + * dirtied in the current transaction. Note that cache entries + * on this list are linked by their trans_next and trans_prev + * fields. + * + * This field is NULL if the list is empty. + * + * tl_tail_ptr: Pointer to the tail of the doubly linked list of entries + * dirtied in the current transaction. Note that cache entries + * on this list are linked by their trans_next and trans_prev + * fields. + * + * This field is NULL if the list is empty. + * + * When an entry is dirtied in a transaction, we must not flush it until + * all the journal entries generated by the transaction have reached disk + * in the journal file. + * + * We could just leave these entries in the LRU and skip over them when + * we scan the list for candidates for eviction. However, this will be + * costly, so we store them on the journal write in progress list instead + * until all the journal entries for the specified transaction reaches + * disk. + * + * jwipl_len: Number of entries currently residing on the journal + * entry write in progress list. + * + * jwipl_size: Number of bytes of cache entries currently residing on the + * journal entry write in progress list. + * + * jwipl_head_ptr: Pointer to the head of the doubly linked list of entries + * dirtied in some transaction n, where at least some of the + * journal entries generated in transaction n have not yet + * made it to disk in the journal file. + * + * Entries on this list are linked by their next and prev + * fields. + * + * This field is NULL if the list is empty. + * + * jwipl_tail_ptr: Pointer to the tail of the doubly linked list of entries + * dirtied in some transaction n, where at least some of the + * journal entries generated in transaction n have not yet + * made it to disk in the journal file. + * + * Entries on this list are linked by their next and prev + * fields. + * + * This field is NULL if the list is empty. + * + * * * Statistics collection fields: * @@ -1004,6 +1095,7 @@ struct H5C2_jbrb_t #define H5C2__H5C2_T_MAGIC 0x005CAC0F #define H5C2__MAX_NUM_TYPE_IDS 16 #define H5C2__PREFIX_LEN 32 +#define H5C2__MAX_API_NAME_LEN 128 #define H5C2__JOURNAL_MAGIC_LEN (size_t)4 #define H5C2__JOURNAL_CONF_MAGIC "MDJC" @@ -1097,11 +1189,23 @@ struct H5C2_t int64_t cache_accesses; hbool_t mdj_enabled; + hbool_t trans_in_progress; + char trans_api_name[H5C2__MAX_API_NAME_LEN]; + uint64_t trans_num; + uint64_t last_trans_on_disk; char * mdj_file_name_ptr; haddr_t mdj_conf_block_addr; hsize_t mdj_conf_block_len; void * mdj_conf_block_ptr; struct H5C2_jbrb_t mdj_jbrb; + int32_t tl_len; + size_t tl_size; + H5C2_cache_entry_t * tl_head_ptr; + H5C2_cache_entry_t * tl_tail_ptr; + int32_t jwipl_len; + size_t jwipl_size; + H5C2_cache_entry_t * jwipl_head_ptr; + H5C2_cache_entry_t * jwipl_tail_ptr; #if H5C2_COLLECT_CACHE_STATS @@ -1168,5 +1272,3162 @@ struct H5C2_t char prefix[H5C2__PREFIX_LEN]; }; + +/****************************************************************************/ +/***************************** Macro Definitions ****************************/ +/****************************************************************************/ + +/**************************************************************************** + * + * We maintain doubly linked lists of instances of H5C2_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 H5C2_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 H5C2_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 + * + * Changes: + * + * - Removed the line: + * + * ( ( (Size) == (entry_ptr)->size ) && ( (len) != 1 ) ) || + * + * from the H5C2__DLL_PRE_REMOVE_SC macro. With the addition of the + * epoch markers used in the age out based cache size reduction algorithm, + * this invarient need not hold, as the epoch markers are of size 0. + * + * One could argue that I should have given the epoch markers a positive + * size, but this would break the index_size = LRU_list_size + pl_size + * + pel_size invarient. + * + * Alternatively, I could pass the current decr_mode in to the macro, + * and just skip the check whenever epoch markers may be in use. + * + * However, any size errors should be caught when the cache is flushed + * and destroyed. Until we are tracking such an error, this should be + * good enough. + * JRM - 12/9/04 + * + * + * - In the H5C2__DLL_PRE_INSERT_SC macro, replaced the lines: + * + * ( ( (len) == 1 ) && + * ( ( (head_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) || + * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) + * ) + * ) || + * + * with: + * + * ( ( (len) == 1 ) && + * ( ( (head_ptr) != (tail_ptr) ) || + * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) + * ) + * ) || + * + * Epoch markers have size 0, so we can now have a non-empty list with + * zero size. Hence the "( (Size) <= 0 )" clause cause false failures + * in the sanity check. Since "Size" is typically a size_t, it can't + * take on negative values, and thus the revised clause "( (Size) < 0 )" + * caused compiler warnings. + * JRM - 12/22/04 + * + * - In the H5C2__DLL_SC macro, replaced the lines: + * + * ( ( (len) == 1 ) && + * ( ( (head_ptr) != (tail_ptr) ) || ( (cache_ptr)->size <= 0 ) || + * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) + * ) + * ) || + * + * with + * + * ( ( (len) == 1 ) && + * ( ( (head_ptr) != (tail_ptr) ) || + * ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) ) + * ) + * ) || + * + * Epoch markers have size 0, so we can now have a non-empty list with + * zero size. Hence the "( (Size) <= 0 )" clause cause false failures + * in the sanity check. Since "Size" is typically a size_t, it can't + * take on negative values, and thus the revised clause "( (Size) < 0 )" + * caused compiler warnings. + * JRM - 1/10/05 + * + * - Added the H5C2__DLL_UPDATE_FOR_SIZE_CHANGE macro and the associated + * sanity checking macros. These macro are used to update the size of + * a DLL when one of its entries changes size. + * + * JRM - 9/8/05 + * + * - Added a set of macros supporting doubly linked lists using the new + * trans_next and trans_prev fields in H5C2_cache_entry_t. These + * fields are used to maintain a list of entries that have been dirtied + * in the current transaction. At the end of the transaction, this + * list is used to generate the needed journal entries. + * + * JRM -- 3/27/08 + * + ****************************************************************************/ + +#if H5C2_DO_SANITY_CHECKS + +#define H5C2__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 ) || \ + ( ( (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 H5C2__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) ) || \ + ( (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 H5C2__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) ) || \ + ( (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") \ +} + +#define H5C2__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) \ +if ( ( (dll_len) <= 0 ) || \ + ( (dll_size) <= 0 ) || \ + ( (old_size) <= 0 ) || \ + ( (old_size) > (dll_size) ) || \ + ( (new_size) <= 0 ) || \ + ( ( (dll_len) == 1 ) && ( (old_size) != (dll_size) ) ) ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "DLL pre size update SC failed") \ +} + +#define H5C2__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) \ +if ( ( (new_size) > (dll_size) ) || \ + ( ( (dll_len) == 1 ) && ( (new_size) != (dll_size) ) ) ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "DLL post size update SC failed") \ +} + +#else /* H5C2_DO_SANITY_CHECKS */ + +#define H5C2__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) +#define H5C2__DLL_SC(head_ptr, tail_ptr, len, Size, fv) +#define H5C2__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) +#define H5C2__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) +#define H5C2__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) + +#endif /* H5C2_DO_SANITY_CHECKS */ + + +#define H5C2__DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \ + H5C2__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 H5C2__DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \ + H5C2__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 H5C2__DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \ + H5C2__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; \ + } + +#define H5C2__DLL_UPDATE_FOR_SIZE_CHANGE(dll_len, dll_size, old_size, new_size) \ + H5C2__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) \ + (dll_size) -= (old_size); \ + (dll_size) += (new_size); \ + H5C2__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size) + +#if H5C2_DO_SANITY_CHECKS + +#define H5C2__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 H5C2__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 H5C2__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 /* H5C2_DO_SANITY_CHECKS */ + +#define H5C2__AUX_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) +#define H5C2__AUX_DLL_SC(head_ptr, tail_ptr, len, Size, fv) +#define H5C2__AUX_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) + +#endif /* H5C2_DO_SANITY_CHECKS */ + + +#define H5C2__AUX_DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val)\ + H5C2__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 H5C2__AUX_DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \ + H5C2__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 H5C2__AUX_DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \ + H5C2__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; \ + } + +#if H5C2_DO_SANITY_CHECKS + +#define H5C2__TRANS_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)->trans_prev == NULL ) && ( (hd_ptr) != (entry_ptr) ) ) || \ + ( ( (entry_ptr)->trans_next == NULL ) && \ + ( (tail_ptr) != (entry_ptr) ) ) || \ + ( ( (len) == 1 ) && \ + ( ! ( ( (hd_ptr) == (entry_ptr) ) && ( (tail_ptr) == (entry_ptr) ) && \ + ( (entry_ptr)->trans_next == NULL ) && \ + ( (entry_ptr)->trans_prev == NULL ) && \ + ( (Size) == (entry_ptr)->size ) \ + ) \ + ) \ + ) \ + ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "TRANS DLL pre remove SC failed") \ +} + +#define H5C2__TRANS_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)->trans_prev != NULL ) || \ + ( (tail_ptr) == NULL ) || ( (tail_ptr)->trans_next != NULL ) \ + ) \ + ) \ + ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "TRANS DLL sanity check failed") \ +} + +#define H5C2__TRANS_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, \ + len, Size, fv) \ +if ( ( (entry_ptr) == NULL ) || \ + ( ! ((entry_ptr)->is_dirty) ) || \ + ( (entry_ptr)->trans_next != NULL ) || \ + ( (entry_ptr)->trans_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)->trans_prev != NULL ) || \ + ( (tail_ptr) == NULL ) || ( (tail_ptr)->trans_next != NULL ) \ + ) \ + ) \ + ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "TRANS DLL pre insert SC failed") \ +} + +#else /* H5C2_DO_SANITY_CHECKS */ + +#define H5C2__TRANS_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) +#define H5C2__TRANS_DLL_SC(head_ptr, tail_ptr, len, Size, fv) +#define H5C2__TRANS_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) + +#endif /* H5C2_DO_SANITY_CHECKS */ + + +#define H5C2__TRANS_DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, \ + Size, fail_val) \ + H5C2__TRANS_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)->trans_next = (entry_ptr); \ + (entry_ptr)->trans_prev = (tail_ptr); \ + (tail_ptr) = (entry_ptr); \ + } \ + (len)++; \ + (Size) += entry_ptr->size; + +#define H5C2__TRANS_DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \ + H5C2__TRANS_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)->trans_prev = (entry_ptr); \ + (entry_ptr)->trans_next = (head_ptr); \ + (head_ptr) = (entry_ptr); \ + } \ + (len)++; \ + (Size) += entry_ptr->size; + +#define H5C2__TRANS_DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \ + H5C2__TRANS_DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, \ + Size, fv) \ + { \ + if ( (head_ptr) == (entry_ptr) ) \ + { \ + (head_ptr) = (entry_ptr)->trans_next; \ + if ( (head_ptr) != NULL ) \ + { \ + (head_ptr)->trans_prev = NULL; \ + } \ + } \ + else \ + { \ + (entry_ptr)->trans_prev->trans_next = (entry_ptr)->trans_next; \ + } \ + if ( (tail_ptr) == (entry_ptr) ) \ + { \ + (tail_ptr) = (entry_ptr)->trans_prev; \ + if ( (tail_ptr) != NULL ) \ + { \ + (tail_ptr)->trans_next = NULL; \ + } \ + } \ + else \ + { \ + (entry_ptr)->trans_next->trans_prev = (entry_ptr)->trans_prev; \ + } \ + entry_ptr->trans_next = NULL; \ + entry_ptr->trans_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. + * + * The sole exception to this rule is + * H5C2__UPDATE_CACHE_HIT_RATE_STATS(), which is always active as + * the cache hit rate stats are always collected and available. + * + * Changes: + * + * JRM -- 3/21/06 + * Added / updated macros for pinned entry related stats. + * + * JRM -- 8/9/06 + * More pinned entry stats related updates. + * + * JRM -- 3/31/07 + * Updated H5C2__UPDATE_STATS_FOR_PROTECT() to keep stats on + * read and write protects. + * + ***********************************************************************/ + +#define H5C2__UPDATE_CACHE_HIT_RATE_STATS(cache_ptr, hit) \ + (cache_ptr->cache_accesses)++; \ + if ( hit ) { \ + (cache_ptr->cache_hits)++; \ + } \ + +#if H5C2_COLLECT_CACHE_STATS + +#define H5C2__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr) \ + (((cache_ptr)->dirty_pins)[(entry_ptr)->type->id])++; + +#define H5C2__UPDATE_STATS_FOR_UNPROTECT(cache_ptr) \ + if ( (cache_ptr)->slist_len > (cache_ptr)->max_slist_len ) \ + (cache_ptr)->max_slist_len = (cache_ptr)->slist_len; \ + if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \ + (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; \ + if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \ + (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \ + if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ + (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; + +#define H5C2__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr) \ + if ( cache_ptr->flush_in_progress ) { \ + ((cache_ptr)->cache_flush_renames[(entry_ptr)->type->id])++; \ + } \ + if ( entry_ptr->flush_in_progress ) { \ + ((cache_ptr)->entry_flush_renames[(entry_ptr)->type->id])++; \ + } \ + (((cache_ptr)->renames)[(entry_ptr)->type->id])++; + +#define H5C2__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size)\ + if ( cache_ptr->flush_in_progress ) { \ + ((cache_ptr)->cache_flush_size_changes[(entry_ptr)->type->id])++; \ + } \ + if ( entry_ptr->flush_in_progress ) { \ + ((cache_ptr)->entry_flush_size_changes[(entry_ptr)->type->id])++; \ + } \ + if ( (entry_ptr)->size < (new_size) ) { \ + ((cache_ptr)->size_increases[(entry_ptr)->type->id])++; \ + if ( (cache_ptr)->index_size > (cache_ptr)->max_index_size ) \ + (cache_ptr)->max_index_size = (cache_ptr)->index_size; \ + if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \ + (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; \ + if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size ) \ + (cache_ptr)->max_pl_size = (cache_ptr)->pl_size; \ + } else if ( (entry_ptr)->size > (new_size) ) { \ + ((cache_ptr)->size_decreases[(entry_ptr)->type->id])++; \ + } + +#define H5C2__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) \ + (cache_ptr)->total_ht_insertions++; + +#define H5C2__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) \ + (cache_ptr)->total_ht_deletions++; + +#define H5C2__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; \ + } + +#define H5C2__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr) \ + ((cache_ptr)->unpins)[(entry_ptr)->type->id]++; + +#if H5C2_COLLECT_CACHE_ENTRY_STATS + +#define H5C2__RESET_CACHE_ENTRY_STATS(entry_ptr) \ + (entry_ptr)->accesses = 0; \ + (entry_ptr)->clears = 0; \ + (entry_ptr)->flushes = 0; \ + (entry_ptr)->pins = 0; + +#define H5C2__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) \ + (((cache_ptr)->clears)[(entry_ptr)->type->id])++; \ + if ( (entry_ptr)->is_pinned ) { \ + (((cache_ptr)->pinned_clears)[(entry_ptr)->type->id])++; \ + } \ + ((entry_ptr)->clears)++; + +#define H5C2__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) \ + (((cache_ptr)->flushes)[(entry_ptr)->type->id])++; \ + if ( (entry_ptr)->is_pinned ) { \ + (((cache_ptr)->pinned_flushes)[(entry_ptr)->type->id])++; \ + } \ + ((entry_ptr)->flushes)++; + +#define H5C2__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; \ + } \ + if ( (entry_ptr)->pins > \ + ((cache_ptr)->max_pins)[(entry_ptr)->type->id] ) { \ + ((cache_ptr)->max_pins)[(entry_ptr)->type->id] \ + = (entry_ptr)->pins; \ + } + +#define H5C2__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) \ + (((cache_ptr)->insertions)[(entry_ptr)->type->id])++; \ + if ( (entry_ptr)->is_pinned ) { \ + (((cache_ptr)->pinned_insertions)[(entry_ptr)->type->id])++; \ + ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \ + (entry_ptr)->pins++; \ + if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \ + (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \ + if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ + (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; \ + } \ + 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)->slist_len > (cache_ptr)->max_slist_len ) \ + (cache_ptr)->max_slist_len = (cache_ptr)->slist_len; \ + if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \ + (cache_ptr)->max_slist_size = (cache_ptr)->slist_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 H5C2__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 ( ! ((entry_ptr)->is_read_only) ) { \ + ((cache_ptr)->write_protects)[(entry_ptr)->type->id]++; \ + } else { \ + ((cache_ptr)->read_protects)[(entry_ptr)->type->id]++; \ + if ( ((entry_ptr)->ro_ref_count) > \ + ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] ) { \ + ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] = \ + ((entry_ptr)->ro_ref_count); \ + } \ + } \ + 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)++; + +#define H5C2__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr) \ + ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \ + (entry_ptr)->pins++; \ + if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \ + (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \ + if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ + (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; + +#else /* H5C2_COLLECT_CACHE_ENTRY_STATS */ + +#define H5C2__RESET_CACHE_ENTRY_STATS(entry_ptr) + +#define H5C2__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) \ + if ( (entry_ptr)->is_pinned ) { \ + (((cache_ptr)->pinned_clears)[(entry_ptr)->type->id])++; \ + } \ + (((cache_ptr)->clears)[(entry_ptr)->type->id])++; + +#define H5C2__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) \ + (((cache_ptr)->flushes)[(entry_ptr)->type->id])++; \ + if ( (entry_ptr)->is_pinned ) { \ + (((cache_ptr)->pinned_flushes)[(entry_ptr)->type->id])++; \ + } + +#define H5C2__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) \ + (((cache_ptr)->evictions)[(entry_ptr)->type->id])++; + +#define H5C2__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) \ + (((cache_ptr)->insertions)[(entry_ptr)->type->id])++; \ + if ( (entry_ptr)->is_pinned ) { \ + (((cache_ptr)->pinned_insertions)[(entry_ptr)->type->id])++; \ + ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \ + if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \ + (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \ + if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ + (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; \ + } \ + 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)->slist_len > (cache_ptr)->max_slist_len ) \ + (cache_ptr)->max_slist_len = (cache_ptr)->slist_len; \ + if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \ + (cache_ptr)->max_slist_size = (cache_ptr)->slist_size; + +#define H5C2__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 ( ! ((entry_ptr)->is_read_only) ) { \ + ((cache_ptr)->write_protects)[(entry_ptr)->type->id]++; \ + } else { \ + ((cache_ptr)->read_protects)[(entry_ptr)->type->id]++; \ + if ( ((entry_ptr)->ro_ref_count) > \ + ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] ) { \ + ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] = \ + ((entry_ptr)->ro_ref_count); \ + } \ + } \ + 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; + +#define H5C2__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr) \ + ((cache_ptr)->pins)[(entry_ptr)->type->id]++; \ + if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len ) \ + (cache_ptr)->max_pel_len = (cache_ptr)->pel_len; \ + if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \ + (cache_ptr)->max_pel_size = (cache_ptr)->pel_size; + +#endif /* H5C2_COLLECT_CACHE_ENTRY_STATS */ + +#else /* H5C2_COLLECT_CACHE_STATS */ + +#define H5C2__RESET_CACHE_ENTRY_STATS(entry_ptr) +#define H5C2__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr) +#define H5C2__UPDATE_STATS_FOR_UNPROTECT(cache_ptr) +#define H5C2__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr) +#define H5C2__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size) +#define H5C2__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) +#define H5C2__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) +#define H5C2__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, success, depth) +#define H5C2__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) +#define H5C2__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) +#define H5C2__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) +#define H5C2__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) +#define H5C2__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit) +#define H5C2__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr) +#define H5C2__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr) + +#endif /* H5C2_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 + * + ***********************************************************************/ + +/* H5C2__HASH_TABLE_LEN is defined in H5C2pkg.h. It mut be a power of two. */ + +#define H5C2__HASH_MASK ((size_t)(H5C2__HASH_TABLE_LEN - 1) << 3) + +#define H5C2__HASH_FCN(x) (int)(((x) & H5C2__HASH_MASK) >> 3) + +#if H5C2_DO_SANITY_CHECKS + +#define H5C2__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \ +if ( ( (cache_ptr) == NULL ) || \ + ( (cache_ptr)->magic != H5C2__H5C2_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 = H5C2__HASH_FCN((entry_ptr)->addr)) < 0 ) || \ + ( k >= H5C2__HASH_TABLE_LEN ) ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, \ + "Pre HT insert SC failed") \ +} + +#define H5C2__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) \ +if ( ( (cache_ptr) == NULL ) || \ + ( (cache_ptr)->magic != H5C2__H5C2_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 ) || \ + ( H5C2__HASH_FCN((entry_ptr)->addr) < 0 ) || \ + ( H5C2__HASH_FCN((entry_ptr)->addr) >= H5C2__HASH_TABLE_LEN ) || \ + ( ((cache_ptr)->index)[(H5C2__HASH_FCN((entry_ptr)->addr))] \ + == NULL ) || \ + ( ( ((cache_ptr)->index)[(H5C2__HASH_FCN((entry_ptr)->addr))] \ + != (entry_ptr) ) && \ + ( (entry_ptr)->ht_prev == NULL ) ) || \ + ( ( ((cache_ptr)->index)[(H5C2__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 H5C2__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \ +if ( ( (cache_ptr) == NULL ) || \ + ( (cache_ptr)->magic != H5C2__H5C2_T_MAGIC ) || \ + ( ! H5F_addr_defined(Addr) ) || \ + ( H5C2__HASH_FCN(Addr) < 0 ) || \ + ( H5C2__HASH_FCN(Addr) >= H5C2__HASH_TABLE_LEN ) ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, "Pre HT search SC failed") \ +} + +#define H5C2__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val) \ +if ( ( (cache_ptr) == NULL ) || \ + ( (cache_ptr)->magic != H5C2__H5C2_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 H5C2__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") \ +} + +#define H5C2__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) \ +if ( ( (cache_ptr) == NULL ) || \ + ( (cache_ptr)->index_len <= 0 ) || \ + ( (cache_ptr)->index_size <= 0 ) || \ + ( (new_size) <= 0 ) || \ + ( (old_size) > (cache_ptr)->index_size ) || \ + ( (new_size) <= 0 ) || \ + ( ( (cache_ptr)->index_len == 1 ) && \ + ( (cache_ptr)->index_size != (old_size) ) ) ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Pre HT entry size change SC failed") \ +} + +#define H5C2__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) \ +if ( ( (cache_ptr) == NULL ) || \ + ( (cache_ptr)->index_len <= 0 ) || \ + ( (cache_ptr)->index_size <= 0 ) || \ + ( (new_size) > (cache_ptr)->index_size ) || \ + ( ( (cache_ptr)->index_len == 1 ) && \ + ( (cache_ptr)->index_size != (new_size) ) ) ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Post HT entry size change SC failed") \ +} + +#else /* H5C2_DO_SANITY_CHECKS */ + +#define H5C2__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) +#define H5C2__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) +#define H5C2__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) +#define H5C2__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val) +#define H5C2__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) +#define H5C2__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) +#define H5C2__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) + +#endif /* H5C2_DO_SANITY_CHECKS */ + + +#define H5C2__INSERT_IN_INDEX(cache_ptr, entry_ptr, fail_val) \ +{ \ + int k; \ + H5C2__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \ + k = H5C2__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; \ + H5C2__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) \ +} + +#define H5C2__DELETE_FROM_INDEX(cache_ptr, entry_ptr) \ +{ \ + int k; \ + H5C2__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) \ + k = H5C2__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; \ + H5C2__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) \ +} + +#define H5C2__SEARCH_INDEX(cache_ptr, Addr, entry_ptr, fail_val) \ +{ \ + int k; \ + int depth = 0; \ + H5C2__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \ + k = H5C2__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 ) \ + { \ + H5C2__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); \ + H5C2__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) \ + } \ + } \ + H5C2__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, (entry_ptr != NULL), depth) \ +} + +#define H5C2__SEARCH_INDEX_NO_STATS(cache_ptr, Addr, entry_ptr, fail_val) \ +{ \ + int k; \ + int depth = 0; \ + H5C2__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \ + k = H5C2__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 ) \ + { \ + H5C2__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); \ + H5C2__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) \ + } \ + } \ +} + +#define H5C2__UPDATE_INDEX_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \ +{ \ + H5C2__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) \ + (cache_ptr)->index_size -= old_size; \ + (cache_ptr)->index_size += new_size; \ + H5C2__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size) \ +} + + +/************************************************************************** + * + * Skip list insertion and deletion macros: + * + * These used to be functions, but I converted them to macros to avoid some + * function call overhead. + * + **************************************************************************/ + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__INSERT_ENTRY_IN_SLIST + * + * Purpose: Insert the specified instance of H5C2_cache_entry_t into + * the skip list in the specified instance of H5C2_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 H5C2_insert_entry_in_tree() into + * the macro H5C2__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, H5SL_insert() will fail. + * + * QAK -- 11/27/04 + * Switched over to using skip list routines. + * + * JRM -- 6/27/06 + * Added fail_val parameter. + * + * JRM -- 8/25/06 + * Added the H5C2_DO_SANITY_CHECKS version of the macro. + * + * This version maintains the slist_len_increase and + * slist_size_increase fields that are used in sanity + * checks in the flush routines. + * + * All this is needed as the fractal heap needs to be + * able to dirty, resize and/or rename entries during the + * flush. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_DO_SANITY_CHECKS + +#define H5C2__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( H5F_addr_defined((entry_ptr)->addr) ); \ + HDassert( !((entry_ptr)->in_slist) ); \ + \ + if ( H5SL_insert((cache_ptr)->slist_ptr, entry_ptr, &(entry_ptr)->addr) \ + < 0 ) \ + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, (fail_val), \ + "Can't insert entry in skip list") \ + \ + (entry_ptr)->in_slist = TRUE; \ + (cache_ptr)->slist_len++; \ + (cache_ptr)->slist_size += (entry_ptr)->size; \ + (cache_ptr)->slist_len_increase++; \ + (cache_ptr)->slist_size_increase += (entry_ptr)->size; \ + \ + HDassert( (cache_ptr)->slist_len > 0 ); \ + HDassert( (cache_ptr)->slist_size > 0 ); \ + \ +} /* H5C2__INSERT_ENTRY_IN_SLIST */ + +#else /* H5C2_DO_SANITY_CHECKS */ + +#define H5C2__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( H5F_addr_defined((entry_ptr)->addr) ); \ + HDassert( !((entry_ptr)->in_slist) ); \ + \ + if ( H5SL_insert((cache_ptr)->slist_ptr, entry_ptr, &(entry_ptr)->addr) \ + < 0 ) \ + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, (fail_val), \ + "Can't insert entry in skip list") \ + \ + (entry_ptr)->in_slist = TRUE; \ + (cache_ptr)->slist_len++; \ + (cache_ptr)->slist_size += (entry_ptr)->size; \ + \ + HDassert( (cache_ptr)->slist_len > 0 ); \ + HDassert( (cache_ptr)->slist_size > 0 ); \ + \ +} /* H5C2__INSERT_ENTRY_IN_SLIST */ + +#endif /* H5C2_DO_SANITY_CHECKS */ + + +/*------------------------------------------------------------------------- + * + * Function: H5C2__REMOVE_ENTRY_FROM_SLIST + * + * Purpose: Remove the specified instance of H5C2_cache_entry_t from the + * index skip list in the specified instance of H5C2_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 H5C2_remove_entry_from_tree() + * to the macro H5C2__REMOVE_ENTRY_FROM_TREE in the hopes of + * wringing a little more performance out of the cache. + * + * QAK -- 11/27/04 + * Switched over to using skip list routines. + * + * JRM -- 3/28/07 + * Updated sanity checks for the new is_read_only and + * ro_ref_count fields in H5C2_cache_entry_t. + * + *------------------------------------------------------------------------- + */ + +#define H5C2__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->in_slist ); \ + HDassert( (cache_ptr)->slist_ptr ); \ + \ + if ( H5SL_remove((cache_ptr)->slist_ptr, &(entry_ptr)->addr) \ + != (entry_ptr) ) \ + \ + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, \ + "Can't delete entry from skip list.") \ + \ + HDassert( (cache_ptr)->slist_len > 0 ); \ + (cache_ptr)->slist_len--; \ + HDassert( (cache_ptr)->slist_size >= (entry_ptr)->size ); \ + (cache_ptr)->slist_size -= (entry_ptr)->size; \ + (entry_ptr)->in_slist = FALSE; \ +} /* H5C2__REMOVE_ENTRY_FROM_SLIST */ + + +/*------------------------------------------------------------------------- + * + * Function: H5C2__UPDATE_SLIST_FOR_SIZE_CHANGE + * + * Purpose: Update cache_ptr->slist_size for a change in the size of + * and entry in the slist. + * + * Return: N/A + * + * Programmer: John Mainzer, 9/07/05 + * + * Modifications: + * + * JRM -- 8/27/06 + * Added the H5C2_DO_SANITY_CHECKS version of the macro. + * + * This version maintains the slist_size_increase field + * that are used in sanity checks in the flush routines. + * + * All this is needed as the fractal heap needs to be + * able to dirty, resize and/or rename entries during the + * flush. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_DO_SANITY_CHECKS + +#define H5C2__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (old_size) > 0 ); \ + HDassert( (new_size) > 0 ); \ + HDassert( (old_size) <= (cache_ptr)->slist_size ); \ + HDassert( (cache_ptr)->slist_len > 0 ); \ + HDassert( ((cache_ptr)->slist_len > 1) || \ + ( (cache_ptr)->slist_size == (old_size) ) ); \ + \ + (cache_ptr)->slist_size -= (old_size); \ + (cache_ptr)->slist_size += (new_size); \ + \ + (cache_ptr)->slist_size_increase -= (int64_t)(old_size); \ + (cache_ptr)->slist_size_increase += (int64_t)(new_size); \ + \ + HDassert( (new_size) <= (cache_ptr)->slist_size ); \ + HDassert( ( (cache_ptr)->slist_len > 1 ) || \ + ( (cache_ptr)->slist_size == (new_size) ) ); \ +} /* H5C2__REMOVE_ENTRY_FROM_SLIST */ + +#else /* H5C2_DO_SANITY_CHECKS */ + +#define H5C2__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (old_size) > 0 ); \ + HDassert( (new_size) > 0 ); \ + HDassert( (old_size) <= (cache_ptr)->slist_size ); \ + HDassert( (cache_ptr)->slist_len > 0 ); \ + HDassert( ((cache_ptr)->slist_len > 1) || \ + ( (cache_ptr)->slist_size == (old_size) ) ); \ + \ + (cache_ptr)->slist_size -= (old_size); \ + (cache_ptr)->slist_size += (new_size); \ + \ + HDassert( (new_size) <= (cache_ptr)->slist_size ); \ + HDassert( ( (cache_ptr)->slist_len > 1 ) || \ + ( (cache_ptr)->slist_size == (new_size) ) ); \ +} /* H5C2__REMOVE_ENTRY_FROM_SLIST */ + +#endif /* H5C2_DO_SANITY_CHECKS */ + + +/************************************************************************** + * + * Replacement policy update macros: + * + * These used to be functions, but I converted them to macros to avoid some + * function call overhead. + * + **************************************************************************/ + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__FAKE_RP_FOR_MOST_RECENT_ACCESS + * + * Purpose: For efficiency, we sometimes change the order of flushes -- + * but doing so can confuse the replacement policy. This + * macro exists to allow us to specify an entry as the + * most recently touched so we can repair any such + * confusion. + * + * 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 macro + * should switch on the current policy and act accordingly. + * + * Return: N/A + * + * Programmer: John Mainzer, 10/13/05 + * + * Modifications: + * + * JRM -- 3/20/06 + * Modified macro to ignore pinned entries. Pinned entries + * do not appear in the data structures maintained by the + * replacement policy code, and thus this macro has nothing + * to do if called for such an entry. + * + * JRM -- 3/28/07 + * Added sanity checks using the new is_read_only and + * ro_ref_count fields of struct H5C2_cache_entry_t. + * + * JRM -- 3/29/08 + * Added a sanity check to verify that the target entry + * does not have a pending journal entry write. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C2__FAKE_RP_FOR_MOST_RECENT_ACCESS(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->last_trans == 0 ); \ + \ + if ( ! ((entry_ptr)->is_pinned) ) { \ + \ + /* modified LRU specific code */ \ + \ + /* remove the entry from the LRU list, and re-insert it at the head. \ + */ \ + \ + H5C2__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)) \ + \ + H5C2__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)) \ + \ + /* 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 same LRU list. \ + * \ + * At least initially, all entries should be clean. That may \ + * change, so we may as well deal with both cases now. \ + */ \ + \ + if ( (entry_ptr)->is_dirty ) { \ + H5C2__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)) \ + \ + H5C2__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 { \ + H5C2__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)) \ + \ + H5C2__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. */ \ + } \ +} /* H5C2__FAKE_RP_FOR_MOST_RECENT_ACCESS */ + +#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C2__FAKE_RP_FOR_MOST_RECENT_ACCESS(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->last_trans == 0 ); \ + \ + if ( ! ((entry_ptr)->is_pinned) ) { \ + \ + /* modified LRU specific code */ \ + \ + /* remove the entry from the LRU list, and re-insert it at the head \ + */ \ + \ + H5C2__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)) \ + \ + H5C2__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. */ \ + } \ +} /* H5C2__FAKE_RP_FOR_MOST_RECENT_ACCESS */ + +#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__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 H5C2_update_rp_for_eviction() to the + * macro H5C2__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. + * + * JRM - 3/20/06 + * Pinned entries can't be evicted, so this entry should never + * be called on a pinned entry. Added assert to verify this. + * + * JRM -- 3/28/07 + * Added sanity checks for the new is_read_only and + * ro_ref_count fields of struct H5C2_cache_entry_t. + * + * JRM -- 3/29/08 + * Added sanity check to verify that the evicted entry + * does not have a pending journal entry write. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C2__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( !((entry_ptr)->is_pinned) ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->last_trans == 0 ); \ + \ + /* modified LRU specific code */ \ + \ + /* remove the entry from the LRU list. */ \ + \ + H5C2__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 ) { \ + \ + H5C2__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 { \ + H5C2__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)) \ + } \ + \ +} /* H5C2__UPDATE_RP_FOR_EVICTION */ + +#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C2__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( !((entry_ptr)->is_pinned) ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->last_trans == 0 ); \ + \ + /* modified LRU specific code */ \ + \ + /* remove the entry from the LRU list. */ \ + \ + H5C2__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)) \ + \ +} /* H5C2__UPDATE_RP_FOR_EVICTION */ + +#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__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 H5C2_update_rp_for_flush() to the + * macro H5C2__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 versions, one supporting the clean and + * dirty LRU lists, and the other not. Yet another attempt + * at optimization. + * + * JRM - 3/20/06 + * While pinned entries can be flushed, they don't reside in + * the replacement policy data structures when unprotected. + * Thus I modified this macro to do nothing if the entry is + * pinned. + * + * JRM - 3/28/07 + * Added sanity checks based on the new is_read_only and + * ro_ref_count fields of struct H5C2_cache_entry_t. + * + * JRM -- 3/29/08 + * Added sanity check to verify that the flushed entry + * does not have a pending journal entry write. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C2__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->last_trans == 0 ); \ + \ + if ( ! ((entry_ptr)->is_pinned) ) { \ + \ + /* modified LRU specific code */ \ + \ + /* remove the entry from the LRU list, and re-insert it at the \ + * head. \ + */ \ + \ + H5C2__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)) \ + \ + H5C2__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 ) { \ + H5C2__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 { \ + H5C2__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)) \ + } \ + \ + H5C2__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. */ \ + } \ +} /* H5C2__UPDATE_RP_FOR_FLUSH */ + +#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C2__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->last_trans == 0 ); \ + \ + if ( ! ((entry_ptr)->is_pinned) ) { \ + \ + /* modified LRU specific code */ \ + \ + /* remove the entry from the LRU list, and re-insert it at the \ + * head. \ + */ \ + \ + H5C2__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)) \ + \ + H5C2__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. */ \ + } \ +} /* H5C2__UPDATE_RP_FOR_FLUSH */ + +#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__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 H5C2_update_rp_for_insertion() to the + * macro H5C2__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. + * + * JRM - 3/10/06 + * This macro should never be called on a pinned entry. + * Inserted an assert to verify this. + * + * JRM - 8/9/06 + * Not any more. We must now allow insertion of pinned + * entries. Updated macro to support this. + * + * JRM - 3/28/07 + * Added sanity checks using the new is_read_only and + * ro_ref_count fields of struct H5C2_cache_entry_t. + * + * JRM - 3/29/30 + * Added sanity check that verifies that the last_trans field + * of the entry matches the trans_num field of the cache. + * Note that when journaling is disabled, both of these + * fields should contain zero. Also verify that either + * journaling is disabled or a transaction is in progress. + * + * Added code to put the entry in the journal write in + * progress list if entries last_trans field is non- + * zero and the entry is not pinned. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C2__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->last_trans == (cache_ptr)->trans_num ); \ + HDassert( ( ! ((cache_ptr)->mdj_enabled) ) || \ + ( (cache_ptr)->trans_in_progress ) ); \ + \ + if ( (entry_ptr)->is_pinned ) { \ + \ + H5C2__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \ + (cache_ptr)->pel_tail_ptr, \ + (cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, (fail_val)) \ + \ + } else if ( (entry_ptr)->last_trans != 0 ) { \ + \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (cache_ptr)->trans_in_progress ); \ + H5C2__TRANS_DLL_PREPEND((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), fail_val) \ + \ + } else { \ + \ + /* modified LRU specific code */ \ + \ + /* insert the entry at the head of the LRU list. */ \ + \ + H5C2__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 ) { \ + H5C2__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 { \ + H5C2__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 /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C2__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->last_trans == (cache_ptr)->trans_num ); \ + HDassert( ( ! ((cache_ptr)->mdj_enabled) ) || \ + ( (cache_ptr)->trans_in_progress ) ); \ + \ + if ( (entry_ptr)->is_pinned ) { \ + \ + H5C2__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \ + (cache_ptr)->pel_tail_ptr, \ + (cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, (fail_val)) \ + \ + } else if ( (entry_ptr)->last_trans != 0 ) { \ + \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (cache_ptr)->trans_in_progress ); \ + H5C2__TRANS_DLL_PREPEND((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), (fail_val)) \ + \ + } else { \ + \ + /* modified LRU specific code */ \ + \ + /* insert the entry at the head of the LRU list. */ \ + \ + H5C2__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 /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__UPDATE_RP_FOR_JOURNAL_WRITE_COMPLETE + * + * Purpose: Update the replacement policy data structures for the + * completion of the last pending journal write for the + * specified un-pinned and un-protected cache entry. + * + * If an entry with a pending journal write is not protected + * and is not pinned, it must be on the journal write in + * progress list. Unlink it from that list, and add it to + * 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. + * + * Note that the macro presumes that the entry's last_trans + * field is zero on entry. + * + * Return: N/A + * + * Programmer: John Mainzer, 3/31/08 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C2__UPDATE_RP_FOR_JOURNAL_WRITE_COMPLETE(cache_ptr, entry_ptr, \ + fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_pinned) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->is_dirty ); \ + HDassert( (entry_ptr)->last_trans == 0 ); \ + \ + H5C2__DLL_REMOVE((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), \ + (fail_val)) \ + \ + /* modified LRU specific code */ \ + \ + /* insert the entry at the head of the LRU list. */ \ + \ + H5C2__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 ) { \ + H5C2__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 { \ + H5C2__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. */ \ + \ +} /* H5C2__UPDATE_RP_FOR_JOURNAL_WRITE_COMPLETE */ + +#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C2__UPDATE_RP_FOR_JOURNAL_WRITE_COMPLETE(cache_ptr, entry_ptr, \ + fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_pinned) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( (entry_ptr)->is_dirty ); \ + HDassert( (entry_ptr)->last_trans == 0 ); \ + \ + H5C2__DLL_REMOVE((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), \ + (fail_val)) \ + \ + /* modified LRU specific code */ \ + \ + /* insert the entry at the head of the LRU list. */ \ + \ + H5C2__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. */ \ + \ +} /* H5C2__UPDATE_RP_FOR_JOURNAL_WRITE_COMPLETE */ + +#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__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 H5C2_update_rp_for_protect() to the + * macro H5C2__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. + * + * JRM - 3/17/06 + * Modified macro to attempt to remove pinned entriese from + * the pinned entry list instead of from the data structures + * maintained by the replacement policy. + * + * JRM - 3/28/07 + * Added sanity checks based on the new is_read_only and + * ro_ref_count fields of struct H5C2_cache_entry_t. + * + * JRM - 3/29/08 + * Added code to remove the entry from the journal write in + * progress list if appropriate. Also related sanity checks. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C2__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + \ + if ( (entry_ptr)->is_pinned ) { \ + \ + H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \ + (cache_ptr)->pel_tail_ptr, \ + (cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, (fail_val)) \ + \ + } else if ( (entry_ptr)->last_trans != 0 ) { \ + \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_REMOVE((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), \ + (fail_val)) \ + \ + } else { \ + \ + /* modified LRU specific code */ \ + \ + /* remove the entry from the LRU list. */ \ + \ + H5C2__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 ) { \ + \ + H5C2__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 { \ + \ + H5C2__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, or whether the entry is \ + * pinned, now add the entry to the protected list. \ + */ \ + \ + H5C2__DLL_APPEND((entry_ptr), (cache_ptr)->pl_head_ptr, \ + (cache_ptr)->pl_tail_ptr, \ + (cache_ptr)->pl_len, \ + (cache_ptr)->pl_size, (fail_val)) \ +} /* H5C2__UPDATE_RP_FOR_PROTECT */ + +#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C2__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + \ + if ( (entry_ptr)->is_pinned ) { \ + \ + H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \ + (cache_ptr)->pel_tail_ptr, \ + (cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, (fail_val)) \ + \ + } else if ( (entry_ptr)->last_trans != 0 ) { \ + \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (cache_ptr)->trans_in_progress ); \ + H5C2__DLL_REMOVE((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), \ + (fail_val)) \ + \ + } else { \ + \ + /* modified LRU specific code */ \ + \ + /* remove the entry from the LRU list. */ \ + \ + H5C2__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, or whether the entry is \ + * pinned, now add the entry to the protected list. \ + */ \ + \ + H5C2__DLL_APPEND((entry_ptr), (cache_ptr)->pl_head_ptr, \ + (cache_ptr)->pl_tail_ptr, \ + (cache_ptr)->pl_len, \ + (cache_ptr)->pl_size, (fail_val)) \ +} /* H5C2__UPDATE_RP_FOR_PROTECT */ + +#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__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 H5C2_update_rp_for_rename() to the + * macro H5C2__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. + * + * JRM - 6/23/05 + * Added the was_dirty parameter. It is possible that + * the entry was clean when it was renamed -- if so it + * it is in the clean LRU regardless of the current + * value of the is_dirty field. + * + * At present, all renamed entries are forced to be + * dirty. This macro is a bit more general that that, + * to allow it to function correctly should that policy + * be relaxed in the future. + * + * JRM - 3/17/06 + * Modified macro to do nothing if the entry is pinned. + * In this case, the entry is on the pinned entry list, not + * in the replacement policy data structures, so there is + * nothing to be done. + * + * JRM - 3/28/07 + * Added sanity checks using the new is_read_only and + * ro_ref_count fields of struct H5C2_cache_entry_t. + * + * JRM - 3/29/08 + * Reworked macro to handle the case in which the renamed + * entry has a journal write pending -- this required the + * addition of the had_jwip parameter. Also added some + * related sanity checks. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C2__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, was_dirty, \ + had_jwip, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + /* read following as: had_jwip => (entry_ptr)->last_trans != 0 */ \ + HDassert( ( (entry_ptr)->last_trans != 0 ) || ( ! (had_jwip) ) ); \ + \ + if ( ! ( (entry_ptr)->is_pinned ) ) { \ + \ + /* remove the entry from either the jwip list, or from the current \ + * replacement policy data structures, as appropriate. \ + */ \ + if ( had_jwip ) { /* must be on jwip list */ \ + \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (cache_ptr)->trans_in_progress ); \ + HDassert( (entry_ptr)->last_trans != 0 ); \ + HDassert( was_dirty ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_REMOVE((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), \ + (fail_val)) \ + \ + } else { /* must be in replacement policy data structures */ \ + \ + /* begin modified LRU specific code */ \ + \ + /* remove the entry from the LRU list */ \ + \ + H5C2__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)) \ + \ + /* remove the entry from either the clean or dirty LUR list as \ + * indicated by the was_dirty parameter \ + */ \ + if ( was_dirty ) { \ + \ + H5C2__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 { \ + \ + H5C2__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 */ \ + } \ + /* insert in either jwip list, or replacement policy data structures \ + * as appropriate. \ + */ \ + if ( (entry_ptr)->last_trans != 0 ) { /* goes in jwip list */ \ + \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (cache_ptr)->trans_in_progress ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_PREPEND((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), fail_val) \ + \ + } else { /* goes back in the replacement policy data structures */ \ + \ + /* begin modified LRU specific code */ \ + \ + H5C2__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 either the clean or dirty \ + * LRU list as appropriate. \ + */ \ + \ + if ( (entry_ptr)->is_dirty ) { \ + \ + H5C2__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 { \ + \ + H5C2__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. */ \ + } \ + } \ +} /* H5C2__UPDATE_RP_FOR_RENAME */ + +#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C2__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, was_dirty, \ + had_jwip, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + /* read following as: had_jwip => (entry_ptr)->last_trans != 0 */ \ + HDassert( ( (entry_ptr)->last_trans != 0 ) || ( ! (had_jwip) ) ); \ + \ + if ( ! ( (entry_ptr)->is_pinned ) ) { \ + \ + /* remove the entry from either the jwip list, or from the current \ + * replacement policy data structures, as appropriate. \ + */ \ + if ( had_jwip ) { /* must be on jwip list */ \ + \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (cache_ptr)->trans_in_progress ); \ + HDassert( (entry_ptr)->last_trans != 0 ); \ + HDassert( was_dirty ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_REMOVE((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), \ + (fail_val)) \ + \ + } else { /* must be in replacement policy data structures */ \ + \ + /* begin modified LRU specific code */ \ + \ + /* remove the entry from the LRU list */ \ + \ + H5C2__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 */ \ + } \ + /* insert in either jwip list, or replacement policy data \ + * structures as appropriate. \ + */ \ + if ( (entry_ptr)->last_trans != 0 ) { /* goes in jwip list */ \ + \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (cache_ptr)->trans_in_progress ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_PREPEND((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), fail_val) \ + \ + } else { /* goes back in the replacement policy data structures */ \ + \ + /* begin modified LRU specific code */ \ + \ + H5C2__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. */ \ + } \ + } \ +} /* H5C2__UPDATE_RP_FOR_RENAME */ + +#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__UPDATE_RP_FOR_SIZE_CHANGE + * + * Purpose: Update the replacement policy data structures for a + * size change of the specified cache entry. + * + * To do this, determine if the entry is pinned. If it is, + * update the size of the pinned entry list. + * + * If it isn't pinned, the entry must handled by the + * replacement policy. Update the appropriate replacement + * policy data structures. + * + * At present, we only support the modified LRU policy, so + * this function deals with that case unconditionally. If + * we ever support other replacement policies, the function + * should switch on the current policy and act accordingly. + * + * Return: N/A + * + * Programmer: John Mainzer, 8/23/06 + * + * Modifications: + * + * JRM -- 3/28/07 + * Added sanity checks based on the new is_read_only and + * ro_ref_count fields of struct H5C2_cache_entry_t. + * + * JRM -- 3/29/08 + * Added code to deal with the journal write in progress + * list -- in essence, after checking to see if the entry is + * pinned, check to see if it is on the jwip list. If it + * is, update the size of that list. If not, proceed as + * before. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C2__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_size) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( new_size > 0 ); \ + \ + if ( (entry_ptr)->is_pinned ) { \ + \ + H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + } else if ( (entry_ptr)->last_trans != 0 ) { \ + \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->jwipl_len, \ + (cache_ptr)->jwipl_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + } else { \ + \ + /* modified LRU specific code */ \ + \ + /* Update the size of the LRU list */ \ + \ + H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->LRU_list_len, \ + (cache_ptr)->LRU_list_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + /* Similarly, update the size of the clean or dirty LRU list as \ + * appropriate. At present, the entry must be clean, but that \ + * could change. \ + */ \ + \ + if ( (entry_ptr)->is_dirty ) { \ + \ + H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->dLRU_list_len, \ + (cache_ptr)->dLRU_list_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + } else { \ + \ + H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->cLRU_list_len, \ + (cache_ptr)->cLRU_list_size, \ + (entry_ptr)->size, \ + (new_size)); \ + } \ + \ + /* End modified LRU specific code. */ \ + } \ + \ +} /* H5C2__UPDATE_RP_FOR_SIZE_CHANGE */ + +#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C2__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_size) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->size > 0 ); \ + HDassert( new_size > 0 ); \ + \ + if ( (entry_ptr)->is_pinned ) { \ + \ + H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + } else if ( (entry_ptr)->last_trans != 0 ) { \ + \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->jwipl_len, \ + (cache_ptr)->jwipl_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + } else { \ + \ + /* modified LRU specific code */ \ + \ + /* Update the size of the LRU list */ \ + \ + H5C2__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->LRU_list_len, \ + (cache_ptr)->LRU_list_size, \ + (entry_ptr)->size, \ + (new_size)); \ + \ + /* End modified LRU specific code. */ \ + } \ + \ +} /* H5C2__UPDATE_RP_FOR_SIZE_CHANGE */ + +#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__UPDATE_RP_FOR_UNPIN + * + * Purpose: Update the replacement policy data structures for an + * unpin of the specified cache entry. + * + * To do this, unlink the specified entry from the protected + * entry 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 macro + * should switch on the current policy and act accordingly. + * + * Return: N/A + * + * Programmer: John Mainzer, 3/22/06 + * + * Modifications: + * + * JRM -- 3/28/07 + * Added sanity checks based on the new is_read_only and + * ro_ref_count fields of struct H5C2_cache_entry_t. + * + * JRM -- 3/30/08 + * Added code to place the newly unpinned entry on the + * journal write pending list if appropriate. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C2__UPDATE_RP_FOR_UNPIN(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->is_pinned); \ + HDassert( (entry_ptr)->size > 0 ); \ + \ + /* Regardless of the replacement policy, remove the entry from the \ + * pinned entry list. \ + */ \ + H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \ + (cache_ptr)->pel_tail_ptr, (cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, (fail_val)) \ + \ + if ( (entry_ptr)->last_trans != 0 ) { \ + \ + /* put the entry in the jwip list */ \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_PREPEND((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), fail_val) \ + \ + } else { /* put entry in the replacement policy data structures */ \ + \ + /* modified LRU specific code */ \ + \ + /* insert the entry at the head of the LRU list. */ \ + \ + H5C2__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 ) { \ + \ + H5C2__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 { \ + \ + H5C2__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. */ \ + } \ + \ +} /* H5C2__UPDATE_RP_FOR_UNPIN */ + +#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C2__UPDATE_RP_FOR_UNPIN(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_T_MAGIC ); \ + HDassert( (entry_ptr) ); \ + HDassert( !((entry_ptr)->is_protected) ); \ + HDassert( !((entry_ptr)->is_read_only) ); \ + HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ + HDassert( (entry_ptr)->is_pinned); \ + HDassert( (entry_ptr)->size > 0 ); \ + \ + /* Regardless of the replacement policy, remove the entry from the \ + * pinned entry list. \ + */ \ + H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr, \ + (cache_ptr)->pel_tail_ptr, (cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, (fail_val)) \ + \ + if ( (entry_ptr)->last_trans != 0 ) { \ + \ + /* put the entry in the jwip list */ \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_PREPEND((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), fail_val) \ + \ + } else { /* put entry in the replacement policy data structures */ \ + \ + /* modified LRU specific code */ \ + \ + /* insert the entry at the head of the LRU list. */ \ + \ + H5C2__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. */ \ + } \ + \ +} /* H5C2__UPDATE_RP_FOR_UNPIN */ + +#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__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 H5C2_update_rp_for_unprotect() to + * the macro H5C2__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. + * + * JRM - 3/17/06 + * Modified macro to put pinned entries on the pinned entry + * list instead of inserting them in the data structures + * maintained by the replacement policy. + * + * JRM - 3/30/08 + * Modified macro to put un-pinned entries with pending + * journal writes on the journal write in progress list. + * + *------------------------------------------------------------------------- + */ + +#if H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS + +#define H5C2__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_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. \ + */ \ + H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pl_head_ptr, \ + (cache_ptr)->pl_tail_ptr, (cache_ptr)->pl_len, \ + (cache_ptr)->pl_size, (fail_val)) \ + \ + if ( (entry_ptr)->is_pinned ) { \ + \ + H5C2__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \ + (cache_ptr)->pel_tail_ptr, \ + (cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, (fail_val)) \ + \ + } else if ( (entry_ptr)->last_trans != 0 ) { \ + \ + /* put the entry in the jwip list */ \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_PREPEND((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), fail_val) \ + \ + } else { /* put the entry in the replacement policy data structures */ \ + \ + /* modified LRU specific code */ \ + \ + /* insert the entry at the head of the LRU list. */ \ + \ + H5C2__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 ) { \ + \ + H5C2__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 { \ + \ + H5C2__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. */ \ + } \ + \ +} /* H5C2__UPDATE_RP_FOR_UNPROTECT */ + +#else /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + +#define H5C2__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, fail_val) \ +{ \ + HDassert( (cache_ptr) ); \ + HDassert( (cache_ptr)->magic == H5C2__H5C2_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. \ + */ \ + H5C2__DLL_REMOVE((entry_ptr), (cache_ptr)->pl_head_ptr, \ + (cache_ptr)->pl_tail_ptr, (cache_ptr)->pl_len, \ + (cache_ptr)->pl_size, (fail_val)) \ + \ + if ( (entry_ptr)->is_pinned ) { \ + \ + H5C2__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr, \ + (cache_ptr)->pel_tail_ptr, \ + (cache_ptr)->pel_len, \ + (cache_ptr)->pel_size, (fail_val)) \ + \ + } else if ( (entry_ptr)->last_trans != 0 ) { \ + \ + /* put the entry in the jwip list */ \ + HDassert( (cache_ptr)->mdj_enabled ); \ + HDassert( (entry_ptr)->is_dirty ); \ + H5C2__DLL_PREPEND((entry_ptr), \ + ((cache_ptr)->jwipl_head_ptr), \ + ((cache_ptr)->jwipl_tail_ptr), \ + ((cache_ptr)->jwipl_len), \ + ((cache_ptr)->jwipl_size), fail_val) \ + \ + } else { \ + \ + /* modified LRU specific code */ \ + \ + /* insert the entry at the head of the LRU list. */ \ + \ + H5C2__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. */ \ + } \ +} /* H5C2__UPDATE_RP_FOR_UNPROTECT */ + +#endif /* H5C2_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ + + +/************************************************************************** + * + * Transaction list update macros: + * + * When journaling is enabled, we must maintain the transaction list -- the + * list of all entries that have been dirtied during the current + * transaction. + * + * The following macros exist to support this task. + * + **************************************************************************/ + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__INSERT_ENTRY_IN_TL() + * + * Purpose: Check to see if journaling is enabled. + * + * If it is, set the last_trans field of the target entry + * to the current transaction number, and insert the entry + * in the transaction list. + * + * Return: N/A + * + * Programmer: John Mainzer, 3/31/08 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +#define H5C2__INSERT_ENTRY_IN_TL(cache_ptr, entry_ptr, fail_val) \ +if ( cache_ptr->mdj_enabled ) \ +{ \ + HDassert( cache_ptr->trans_in_progress ); \ + HDassert( entry_ptr->last_trans == 0 ); \ + \ + entry_ptr->last_trans = cache_ptr->trans_num; \ + \ + H5C2__TRANS_DLL_PREPEND((entry_ptr), (cache_ptr->tl_head_ptr), \ + (cache_ptr->tl_tail_ptr), \ + (cache_ptr->tl_len), (cache_ptr->tl_size), \ + (fail_val)); \ +} /* H5C2__INSERT_ENTRY_IN_TL */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__UPDATE_TL_FOR_ENTRY_CLEAR + * + * Purpose: Check to see if journaling is enabled. + * + * If it is, see if the target entry is in the transaction + * list. If it is, remove it from the list, and set its + * last_trans field to the current transaction number minus + * 1. + * + * Return: N/A + * + * Programmer: John Mainzer, 3/31/08 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +#define H5C2__UPDATE_TL_FOR_ENTRY_CLEAR(cache_ptr, entry_ptr, fail_val) \ +if ( cache_ptr->mdj_enabled ) \ +{ \ + HDassert( cache_ptr->trans_in_progress ); \ + HDassert( entry_ptr->last_trans <= cache_ptr->trans_num ); \ + \ + if ( entry_ptr->last_trans == cache_ptr->trans_num ) { \ + \ + H5C2__TRANS_DLL_REMOVE((entry_ptr), (cache_ptr->tl_head_ptr), \ + (cache_ptr->tl_tail_ptr), \ + (cache_ptr->tl_len), \ + (cache_ptr->tl_size), (fail_val)); \ + entry_ptr->last_trans = cache_ptr->trans_num - 1; \ + } \ +} /* H5C2__UPDATE_TL_FOR_ENTRY_CLEAR */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__UPDATE_TL_FOR_ENTRY_DIRTY + * + * Purpose: Check to see if journaling is enabled. + * + * If it is, see if the target entry is in the transaction + * list. If it is, remove it from the list. If it isn't, + * set the entries last_trans field to the id of the current + * transaction. + * + * In either case, then insert the entry at the head of the + * transaction list. + * + * Return: N/A + * + * Programmer: John Mainzer, 3/31/08 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +#define H5C2__UPDATE_TL_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr, fail_val) \ +if ( cache_ptr->mdj_enabled ) \ +{ \ + HDassert( cache_ptr->trans_in_progress ); \ + HDassert( entry_ptr->last_trans <= cache_ptr->trans_num ); \ + \ + if ( entry_ptr->last_trans == cache_ptr->trans_num ) { \ + \ + H5C2__TRANS_DLL_REMOVE((entry_ptr), (cache_ptr->tl_head_ptr), \ + (cache_ptr->tl_tail_ptr), \ + (cache_ptr->tl_len), \ + (cache_ptr->tl_size), (fail_val)); \ + } else { \ + entry_ptr->last_trans = cache_ptr->trans_num; \ + } \ + \ + H5C2__TRANS_DLL_PREPEND((entry_ptr), (cache_ptr->tl_head_ptr), \ + (cache_ptr->tl_tail_ptr), \ + (cache_ptr->tl_len), (cache_ptr->tl_size), \ + (fail_val)); \ +} /* H5C2__UPDATE_TL_FOR_ENTRY_DIRTY */ + + +/*------------------------------------------------------------------------- + * + * Macro: H5C2__UPDATE_TL_FOR_ENTRY_SIZE_CHANGE + * + * Purpose: Update the transaction list for a change in the size of + * one of its constituents. Note that it is the caller's + * responsibility to verify that the entry is in the + * transaction list. + * + * Return: N/A + * + * Programmer: John Mainzer, 3/31/08 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +#define H5C2__UPDATE_TL_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, \ + old_size, new_size) \ +if ( (cache_ptr)->mdj_enabled ) { \ + HDassert( (cache_ptr)->trans_in_progress ); \ + if ( (entry_ptr)->last_trans == (cache_ptr)->trans_num ) { \ + H5C2__DLL_UPDATE_FOR_SIZE_CHANGE(((cache_ptr)->tl_len), \ + ((cache_ptr)->tl_size), \ + (old_size), (new_size)); \ + } \ +} /* H5C2__UPDATE_TL_FOR_ENTRY_SIZE_CHANGE() */ + #endif /* _H5C2pkg_H */ diff --git a/src/H5C2private.h b/src/H5C2private.h index 98120d7..4f42927 100644 --- a/src/H5C2private.h +++ b/src/H5C2private.h @@ -784,6 +784,37 @@ typedef herr_t (*H5C2_log_flush_func_t)(H5C2_t * cache_ptr, * there is no previous item, it should be NULL. * * + * Fields supporting metadata journaling: + * + * last_trans: unit64_t containing the ID of the last transaction in + * which this entry was dirtied. If journaling is disabled, + * or if the entry has never been dirtied in a transaction, + * this field should be set to zero. Once we notice that + * the specified transaction has made it to disk, we will + * reset this field to zero as well. + * + * We must maintain this field, as to avoid messages from + * the future, we must not flush a dirty entry to disk + * until the last transaction in which it was dirtied + * has made it to disk in the journal file. + * + * trans_next: Next pointer in the entries modified in the current + * transaction list. This field should always be null + * unless journaling is enabled, the entry is dirty, + * and last_trans field contains the current transaction + * number. Even if all these conditions are fulfilled, + * the field will still be NULL if this is the last + * entry on the list. + * + * trans_prev: Previous pointer in the entries modified in the current + * transaction list. This field should always be null + * unless journaling is enabled, the entry is dirty, + * and last_trans field contains the current transaction + * number. Even if all these conditions are fulfilled, + * the field will still be NULL if this is the first + * entry on the list. + * + * * Cache entry stats collection fields: * * These fields should only be compiled in when both H5C2_COLLECT_CACHE_STATS @@ -844,6 +875,13 @@ typedef struct H5C2_cache_entry_t struct H5C2_cache_entry_t * aux_next; struct H5C2_cache_entry_t * aux_prev; + + /* fields supporting journaling */ + + uint64_t last_trans; + struct H5C2_cache_entry_t * trans_next; + struct H5C2_cache_entry_t * trans_prev; + #if H5C2_COLLECT_CACHE_ENTRY_STATS /* cache entry stats fields */ @@ -1268,14 +1306,17 @@ typedef struct H5C2_auto_size_ctl_t #define H5C2__READ_ONLY_FLAG 0x0400 #define H5C2__CHECK_SIZE_FLAG 0x0800 -H5_DLL H5C2_t * H5C2_create(size_t max_cache_size, +H5_DLL H5C2_t * H5C2_create(H5F_t * f, + hid_t dxpl_id, + size_t max_cache_size, size_t min_clean_size, int max_type_id, const char * (* type_name_table_ptr), H5C2_write_permitted_func_t check_write_permitted, hbool_t write_permitted, H5C2_log_flush_func_t log_flush, - void * aux_ptr); + void * aux_ptr, + hbool_t journal_recovered); H5_DLL void H5C2_def_auto_resize_rpt_fcn(H5C2_t * cache_ptr, int32_t version, @@ -1297,8 +1338,8 @@ H5_DLL herr_t H5C2_expunge_entry(H5F_t * f, haddr_t addr); H5_DLL herr_t H5C2_flush_cache(H5F_t *f, - hid_t dxpl_id, - unsigned flags); + hid_t dxpl_id, + unsigned flags); H5_DLL herr_t H5C2_flush_to_min_clean(H5F_t * f, @@ -1412,11 +1453,46 @@ H5_DLL herr_t H5C2_validate_resize_config(H5C2_auto_size_ctl_t * config_ptr, /***************** journaling function definitions proper: ****************/ /**************************************************************************/ -H5_DLL herr_t H5C2__begin_transaction(H5C2_t * cache_ptr, - uint64_t * trans_num_ptr); +H5_DLL herr_t H5C2_begin_journaling(H5F_t * f, + hid_t dxpl_id, + H5C2_t * cache_ptr, + char * journal_file_name_ptr, + size_t buf_size, + int num_bufs, + hbool_t use_aio, + hbool_t human_readable); + +H5_DLL herr_t H5C2_begin_transaction(H5C2_t * cache_ptr, + uint64_t * trans_num_ptr, + const char * api_call_name); + +H5_DLL herr_t H5C2_end_journaling(H5F_t * f, + hid_t dxpl_id, + H5C2_t * cache_ptr); -H5_DLL herr_t H5C2__end_transaction(H5C2_t * cache_ptr, - uint64_t trans_num); +H5_DLL herr_t H5C2_end_transaction(H5F_t * f, + H5C2_t * cache_ptr, + uint64_t trans_num, + const char * api_call_name); + +H5_DLL herr_t H5C2_get_journal_config(H5C2_t * cache_ptr, + hbool_t * journaling_enabled_ptr, + char * journal_file_path_ptr, + size_t * jbrb_buf_size_ptr, + int * jbrb_num_bufs_ptr, + hbool_t * jbrb_use_aio_ptr, + hbool_t * jbrb_human_readable_ptr); + +H5_DLL herr_t H5C2_journal_post_flush(H5C2_t * cache_ptr, + hbool_t cache_is_clean); + +H5_DLL herr_t H5C2_journal_pre_flush(H5C2_t * cache_ptr); + +H5_DLL herr_t H5C2_journal_transaction(H5F_t * f, + H5C2_t * cache_ptr); + +H5_DLL herr_t H5C2_update_for_new_last_trans_on_disk(H5C2_t * cache_ptr, + uint64_t new_last_trans_on_disk); /*****************************************************************************/ @@ -1433,7 +1509,7 @@ H5_DLL herr_t H5C2_jb__write_to_buffer(H5C2_jbrb_t * struct_ptr, size_t size, const char * data, hbool_t is_end_trans, - unsigned long trans_num); + uint64_t trans_num); H5_DLL herr_t H5C2_jb__init(H5C2_jbrb_t * struct_ptr, const char * HDF5_file_name, @@ -1444,22 +1520,22 @@ H5_DLL herr_t H5C2_jb__init(H5C2_jbrb_t * struct_ptr, hbool_t human_readable); H5_DLL herr_t H5C2_jb__start_transaction(H5C2_jbrb_t * struct_ptr, - unsigned long trans_num); + uint64_t trans_num); H5_DLL herr_t H5C2_jb__journal_entry(H5C2_jbrb_t * struct_ptr, - unsigned long trans_num, + uint64_t trans_num, haddr_t base_addr, size_t length, const uint8_t * body); H5_DLL herr_t H5C2_jb__end_transaction(H5C2_jbrb_t * struct_ptr, - unsigned long trans_num); + uint64_t trans_num); H5_DLL herr_t H5C2_jb__comment(H5C2_jbrb_t * struct_ptr, const char * comment_ptr); H5_DLL herr_t H5C2_jb__get_last_transaction_on_disk(H5C2_jbrb_t * struct_ptr, - unsigned long * trans_num_ptr); + uint64_t * trans_num_ptr); H5_DLL herr_t H5C2_jb__trunc(H5C2_jbrb_t * struct_ptr); @@ -1480,6 +1556,11 @@ H5_DLL herr_t H5C2_jb__bin2hex(const uint8_t * buf, /********** journal config block management function definitions: ************/ /*****************************************************************************/ +H5_DLL herr_t H5C2_check_for_journaling(H5F_t * f, + hid_t dxpl_id, + H5C2_t * cache_ptr, + hbool_t journal_recovered); + H5_DLL herr_t H5C2_create_journal_config_block(H5F_t *f, hid_t dxpl_id, const char * journal_file_name_ptr); @@ -1487,11 +1568,13 @@ H5_DLL herr_t H5C2_create_journal_config_block(H5F_t *f, H5_DLL herr_t H5C2_discard_journal_config_block(H5F_t * f, hid_t dxpl_id); -H5_DLL herr_t H5C2_get_journaling_in_progress(H5F_t * f, - hid_t dxpl_id); +H5_DLL herr_t H5C2_get_journaling_in_progress(const H5F_t * f, + hid_t dxpl_id, + H5C2_t * cache_ptr); -H5_DLL herr_t H5C2_load_journal_config_block(H5F_t * f, +H5_DLL herr_t H5C2_load_journal_config_block(const H5F_t * f, hid_t dxpl_id, + H5C2_t * cache_ptr, haddr_t block_addr, hsize_t block_len); @@ -1500,7 +1583,8 @@ H5_DLL herr_t H5C2_mark_journaling_in_progress(H5F_t * f, const char * journal_file_name_ptr); H5_DLL herr_t H5C2_unmark_journaling_in_progress(H5F_t * f, - hid_t dxpl_id); + hid_t dxpl_id, + H5C2_t * cache_ptr); @@ -32,6 +32,7 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5FLprivate.h" /* Free lists */ #include "H5Iprivate.h" /* IDs */ +#include "H5AC2private.h" /* Metadata cache */ /****************/ @@ -133,7 +134,7 @@ H5Dcreate2(hid_t loc_id, const char *name, hid_t type_id, hid_t space_id, const H5S_t *space; /* Dataspace for dataset */ hid_t ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Dcreate2, FAIL) + FUNC_ENTER_API_META(H5Dcreate2, loc_id, FAIL) H5TRACE7("i", "i*siiiii", loc_id, name, type_id, space_id, lcpl_id, dcpl_id, dapl_id); @@ -226,7 +227,7 @@ H5Dcreate_anon(hid_t loc_id, hid_t type_id, hid_t space_id, hid_t dcpl_id, const H5S_t *space; /* Dataspace for dataset */ hid_t ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Dcreate_anon, FAIL) + FUNC_ENTER_API_META(H5Dcreate_anon, loc_id, FAIL) H5TRACE5("i", "iiiii", loc_id, type_id, space_id, dcpl_id, dapl_id); /* Check arguments */ @@ -372,7 +373,7 @@ H5Dclose(hid_t dset_id) H5D_t *dset; /* Dataset object to release */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Dclose, FAIL) + FUNC_ENTER_API_META(H5Dclose, dset_id, FAIL) H5TRACE1("e", "i", dset_id); /* Check args */ @@ -994,7 +995,7 @@ H5Dset_extent(hid_t dset_id, const hsize_t *size) H5D_t *dset; /* Dataset for this operation */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Dset_extent, FAIL) + FUNC_ENTER_API_META(H5Dset_extent, dset_id, FAIL) H5TRACE2("e", "i*h", dset_id, size); /* Check args */ diff --git a/src/H5Ddeprec.c b/src/H5Ddeprec.c index 7d6cc02..2810f5a 100644 --- a/src/H5Ddeprec.c +++ b/src/H5Ddeprec.c @@ -45,6 +45,7 @@ #include "H5Dpkg.h" /* Datasets */ #include "H5Eprivate.h" /* Error handling */ #include "H5Iprivate.h" /* IDs */ +#include "H5AC2private.h" /* Metadata cache */ /****************/ @@ -147,7 +148,7 @@ H5Dcreate1(hid_t loc_id, const char *name, hid_t type_id, hid_t space_id, const H5S_t *space; /* Dataspace for dataset */ hid_t ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Dcreate1, FAIL) + FUNC_ENTER_API_META(H5Dcreate1, loc_id, FAIL) H5TRACE5("i", "i*siii", loc_id, name, type_id, space_id, dcpl_id); /* Check arguments */ @@ -284,7 +285,7 @@ H5Dextend(hid_t dset_id, const hsize_t *size) H5D_t *dset; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Dextend, FAIL) + FUNC_ENTER_API_META(H5Dextend, dset_id, FAIL) H5TRACE2("e", "i*h", dset_id, size); /* Check args */ diff --git a/src/H5Dio.c b/src/H5Dio.c index a3148c8..78140e0 100644 --- a/src/H5Dio.c +++ b/src/H5Dio.c @@ -32,6 +32,7 @@ #include "H5Sprivate.h" /* Dataspace functions */ #include "H5SLprivate.h" /* Skip lists */ #include "H5Vprivate.h" /* Vector and array functions */ +#include "H5AC2private.h" /* Metadata cache */ #ifdef H5_HAVE_PARALLEL /* Remove this if H5R_DATASET_REGION is no longer used in this file */ @@ -388,7 +389,7 @@ H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, char fake_char; herr_t ret_value=SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Dwrite, FAIL) + FUNC_ENTER_API_META(H5Dwrite, dset_id, FAIL) H5TRACE6("e", "iiiii*x", dset_id, mem_type_id, mem_space_id, file_space_id, plist_id, buf); @@ -935,8 +935,13 @@ H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id, H5FD_t *lf) /* Create a metadata cache with modified API along side the regular * version. For now, this is just for testing. Once we get it * fully in use, we will delete the old version. + * + * Note the use of H5P_DATASET_XFER_DEFAULT for the dxpl_id parameter + * of H5AC2_create(). We may want to change this. */ - if(H5AC2_create(f, (H5AC2_cache_config_t *)&(f->shared->mdc_initCacheCfg)) < 0) + if(H5AC2_create(f, H5P_DATASET_XFER_DEFAULT, + (H5AC2_cache_config_t *)&(f->shared->mdc_initCacheCfg)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create meta data cache2") /* Create the file's "open object" information */ @@ -1432,7 +1437,8 @@ H5Fcreate(const char *filename, unsigned flags, hid_t fcpl_id, hid_t fapl_id) H5F_t *new_file = NULL; /*file struct for new file */ hid_t ret_value; /*return value */ - FUNC_ENTER_API_META(H5Fcreate, FAIL) + /* can't journal at this point, as the file doesn't exist yet. */ + FUNC_ENTER_API(H5Fcreate, FAIL) H5TRACE4("i", "*sIuii", filename, flags, fcpl_id, fapl_id); /* Check/fix arguments */ @@ -1484,7 +1490,7 @@ done: if(H5F_close(new_file) < 0) HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file") - FUNC_LEAVE_API_META(ret_value) + FUNC_LEAVE_API(ret_value) } /* end H5Fcreate() */ @@ -1534,7 +1540,13 @@ H5Fopen(const char *filename, unsigned flags, hid_t fapl_id) H5F_t *new_file = NULL; /*file struct for new file */ hid_t ret_value; /*return value */ - FUNC_ENTER_API_META(H5Fopen, FAIL) + /* can't journal at this point as the file is not open */ + /* In theory, opening the file shouldn't generate any dirty metadata, + * but we do have one case where we fix some object automatically + * when we first touch it. Can this happen here? If so, we will + * have to do somethings to start a transaction before this happens. + */ + FUNC_ENTER_API(H5Fopen, FAIL) H5TRACE3("i", "*sIui", filename, flags, fapl_id); /* Check/fix arguments. */ @@ -1564,7 +1576,7 @@ done: if(ret_value < 0 && new_file && H5F_try_close(new_file) < 0) HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file") - FUNC_LEAVE_API_META(ret_value) + FUNC_LEAVE_API(ret_value) } /* end H5Fopen() */ @@ -1601,7 +1613,8 @@ H5Fflush(hid_t object_id, H5F_scope_t scope) H5O_loc_t *oloc = NULL; herr_t ret_value=SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Fflush, FAIL) + /* don't start a transaction here, as a flush must not modify metadata. */ + FUNC_ENTER_API(H5Fflush, FAIL) H5TRACE2("e", "iFs", object_id, scope); switch(H5I_get_type(object_id)) { @@ -1651,7 +1664,7 @@ H5Fflush(hid_t object_id, H5F_scope_t scope) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "flush failed") done: - FUNC_LEAVE_API_META(ret_value) + FUNC_LEAVE_API(ret_value) } /* end H5Fflush() */ @@ -2011,7 +2024,8 @@ H5Fclose(hid_t file_id) { herr_t ret_value = SUCCEED; - FUNC_ENTER_API_META(H5Fclose, FAIL) + /* This function shouldn't change metadata, so don't start a transaction */ + FUNC_ENTER_API(H5Fclose, FAIL) H5TRACE1("e", "i", file_id); /* Check/fix arguments. */ @@ -2026,7 +2040,7 @@ H5Fclose(hid_t file_id) HGOTO_ERROR(H5E_ATOM, H5E_CANTCLOSEFILE, FAIL, "decrementing file ID failed") done: - FUNC_LEAVE_API_META(ret_value) + FUNC_LEAVE_API(ret_value) } /* end H5Fclose() */ @@ -2059,7 +2073,8 @@ H5Freopen(hid_t file_id) H5F_t *new_file = NULL; hid_t ret_value; - FUNC_ENTER_API_META(H5Freopen, FAIL) + /* should be no metadata changes, so done start a transaction */ + FUNC_ENTER_API(H5Freopen, FAIL) H5TRACE1("i", "i", file_id); /* Check arguments */ @@ -2087,7 +2102,7 @@ done: if(H5F_dest(new_file, H5AC_dxpl_id) < 0) HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file") - FUNC_LEAVE_API_META(ret_value) + FUNC_LEAVE_API(ret_value) } /* end H5Freopen() */ @@ -3369,6 +3384,7 @@ H5Fset_mdc_config(hid_t file_id, /* pass the resize configuration to the modified cache as well. */ result = H5AC2_set_cache_auto_resize_config(file, + H5P_DATASET_XFER_DEFAULT, (H5AC2_cache_config_t *)config_ptr); if ( result != SUCCEED ) { diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h index 291fc88..b68f141 100644 --- a/src/H5FDpublic.h +++ b/src/H5FDpublic.h @@ -89,19 +89,12 @@ typedef enum H5FD_mem_t { #define H5FD_MEM_SOHM_TABLE H5FD_MEM_OHDR #define H5FD_MEM_SOHM_INDEX H5FD_MEM_BTREE -/* Map metadata journaling configuration block to raw for now, as it is of - * arbitrary size, and the metadata cache will be managing it directly, - * without passing it through the metadata cache proper. +/* Per discussion with Quincey, I'm mapping the metadata journaling + * configuration block to super. * - * JRM -- 3/11/08 - * - * Quincey: I suspect this is bogus. However, I gather that adding a - * new memory type is a bit of a bother, so I'm trying to avoid - * it until I talk to you. Please let me know what you think - * I should do here. - * -- JRM + * JRM -- 3/20/08 */ -#define H5FD_MEM_MDJCONFIG H5FD_MEM_DRAW +#define H5FD_MEM_MDJCONFIG H5FD_MEM_SUPER /* * A free-list map which maps all types of allocation requests to a single diff --git a/src/H5Fmount.c b/src/H5Fmount.c index 92882ae..7eee769 100644 --- a/src/H5Fmount.c +++ b/src/H5Fmount.c @@ -27,6 +27,7 @@ #include "H5Iprivate.h" /* IDs */ #include "H5Pprivate.h" /* Property lists */ #include "H5MMprivate.h" /* Memory management */ +#include "H5AC2private.h" /* Metadata cache */ /* PRIVATE PROTOTYPES */ static herr_t H5F_mount(H5G_loc_t *loc, const char *name, H5F_t *child, @@ -482,7 +483,12 @@ H5Fmount(hid_t loc_id, const char *name, hid_t child_id, hid_t plist_id) H5F_t *child = NULL; herr_t ret_value=SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Fmount, FAIL) + /* Not sure this will generate any dirty metadata... + * + * Also we must work out how we are going to deal with journaling + * in such cases. + */ + FUNC_ENTER_API_META(H5Fmount, loc_id, FAIL) H5TRACE4("e", "i*sii", loc_id, name, child_id, plist_id); /* Check arguments */ @@ -532,7 +538,12 @@ H5Funmount(hid_t loc_id, const char *name) H5G_loc_t loc; herr_t ret_value=SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Funmount, FAIL) + /* Not sure that this will generate any dirty metadata. + * + * Also, must decide how we are going to deal with journaling + * in such cases. + */ + FUNC_ENTER_API_META(H5Funmount, loc_id, FAIL) H5TRACE2("e", "i*s", loc_id, name); /* Check args */ @@ -89,6 +89,7 @@ #include "H5Iprivate.h" /* IDs */ #include "H5Lprivate.h" /* Links */ #include "H5Pprivate.h" /* Property lists */ +#include "H5AC2private.h" /* Metadata cache */ /* Local macros */ #define H5G_RESERVED_ATOMS 0 @@ -146,7 +147,7 @@ H5Gcreate2(hid_t loc_id, const char *name, hid_t lcpl_id, hid_t gcpl_id, H5G_t *grp = NULL; /* New group created */ hid_t ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Gcreate2, FAIL) + FUNC_ENTER_API_META(H5Gcreate2, loc_id, FAIL) H5TRACE5("i", "i*siii", loc_id, name, lcpl_id, gcpl_id, gapl_id); /* Check arguments */ @@ -286,7 +287,7 @@ H5Gcreate_anon(hid_t loc_id, hid_t gcpl_id, hid_t gapl_id) H5G_t *grp = NULL; hid_t ret_value; - FUNC_ENTER_API_META(H5Gcreate_anon, FAIL) + FUNC_ENTER_API_META(H5Gcreate_anon, loc_id, FAIL) H5TRACE3("i", "iii", loc_id, gcpl_id, gapl_id); /* Check arguments */ @@ -661,7 +662,8 @@ H5Gclose(hid_t group_id) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Gclose, FAIL) + /* Can this change metadata? If not, no need for a transaction. */ + FUNC_ENTER_API_META(H5Gclose, group_id, FAIL) H5TRACE1("e", "i", group_id); /* Check args */ diff --git a/src/H5Gdeprec.c b/src/H5Gdeprec.c index 03a380b..07de86a 100644 --- a/src/H5Gdeprec.c +++ b/src/H5Gdeprec.c @@ -46,6 +46,7 @@ #include "H5Iprivate.h" /* IDs */ #include "H5Lprivate.h" /* Links */ #include "H5Pprivate.h" /* Property lists */ +#include "H5AC2private.h" /* Metadata cache */ /****************/ @@ -203,7 +204,7 @@ H5Gcreate1(hid_t loc_id, const char *name, size_t size_hint) hid_t tmp_gcpl = (-1); /* Temporary group creation property list */ hid_t ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Gcreate1, FAIL) + FUNC_ENTER_API_META(H5Gcreate1, loc_id, FAIL) H5TRACE3("i", "i*sz", loc_id, name, size_hint); /* Check arguments */ @@ -325,7 +326,7 @@ H5Glink(hid_t cur_loc_id, H5G_link_t type, const char *cur_name, const char *new { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Glink, FAIL) + FUNC_ENTER_API_META(H5Glink, cur_loc_id, FAIL) H5TRACE4("e", "iLl*s*s", cur_loc_id, type, cur_name, new_name); /* Check arguments */ @@ -371,7 +372,7 @@ H5Glink2(hid_t cur_loc_id, const char *cur_name, H5G_link_t type, { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Glink2, FAIL) + FUNC_ENTER_API_META(H5Glink2, cur_loc_id, FAIL) H5TRACE5("e", "i*sLli*s", cur_loc_id, cur_name, type, new_loc_id, new_name); /* Check arguments */ @@ -474,7 +475,7 @@ H5Gmove(hid_t src_loc_id, const char *src_name, const char *dst_name) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Gmove, FAIL) + FUNC_ENTER_API_META(H5Gmove, src_loc_id, FAIL) H5TRACE3("e", "i*s*s", src_loc_id, src_name, dst_name); /* Call common routine to move the link */ @@ -499,7 +500,7 @@ H5Gmove2(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Gmove2, FAIL) + FUNC_ENTER_API_META(H5Gmove2, src_loc_id, FAIL) H5TRACE4("e", "i*si*s", src_loc_id, src_name, dst_loc_id, dst_name); /* Call common routine to move the link */ @@ -581,7 +582,7 @@ H5Gunlink(hid_t loc_id, const char *name) H5G_loc_t loc; /* Group's location */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Gunlink, FAIL) + FUNC_ENTER_API_META(H5Gunlink, loc_id, FAIL) H5TRACE2("e", "i*s", loc_id, name); /* Check arguments */ @@ -654,7 +655,7 @@ H5Gset_comment(hid_t loc_id, const char *name, const char *comment) H5G_loc_t loc; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Gset_comment, FAIL) + FUNC_ENTER_API_META(H5Gset_comment, loc_id, FAIL) H5TRACE3("e", "i*s*s", loc_id, name, comment); if(H5G_loc(loc_id, &loc) < 0) @@ -48,6 +48,7 @@ #include "H5Ipkg.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ #include "H5Oprivate.h" /* Object headers */ +#include "H5AC2private.h" /* Metadata cache */ /* Define this to compile in support for dumping ID information */ /* #define H5I_DEBUG_OUTPUT */ @@ -1261,7 +1262,7 @@ H5Idec_ref(hid_t id) { int ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Idec_ref, FAIL); + FUNC_ENTER_API_META(H5Idec_ref, id, FAIL); H5TRACE1("Is", "i", id); /* Check arguments */ @@ -1386,7 +1387,7 @@ H5Iinc_ref(hid_t id) { int ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Iinc_ref, FAIL); + FUNC_ENTER_API_META(H5Iinc_ref, id, FAIL); H5TRACE1("Is", "i", id); /* Check arguments */ @@ -37,6 +37,7 @@ #include "H5MMprivate.h" /* Memory management */ #include "H5Oprivate.h" /* File objects */ #include "H5Pprivate.h" /* Property lists */ +#include "H5AC2private.h" /* Metadata cache */ /****************/ /* Local Macros */ @@ -314,7 +315,7 @@ H5Lmove(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, H5G_loc_t dst_loc, *dst_loc_p; herr_t ret_value=SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Lmove, FAIL) + FUNC_ENTER_API_META(H5Lmove, src_loc_id, FAIL) H5TRACE6("e", "i*si*sii", src_loc_id, src_name, dst_loc_id, dst_name, lcpl_id, lapl_id); @@ -372,7 +373,7 @@ H5Lcopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, H5G_loc_t dst_loc, *dst_loc_p; herr_t ret_value=SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Lcopy, FAIL) + FUNC_ENTER_API_META(H5Lcopy, src_loc_id, FAIL) H5TRACE6("e", "i*si*sii", src_loc_id, src_name, dst_loc_id, dst_name, lcpl_id, lapl_id); @@ -433,7 +434,7 @@ H5Lcreate_soft(const char *link_target, H5G_loc_t link_loc; /* Group location for new link */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Lcreate_soft, FAIL) + FUNC_ENTER_API_META(H5Lcreate_soft, link_loc_id, FAIL) H5TRACE5("e", "*si*sii", link_target, link_loc_id, link_name, lcpl_id, lapl_id); /* Check arguments */ @@ -479,7 +480,7 @@ H5Lcreate_hard(hid_t cur_loc_id, const char *cur_name, H5G_loc_t new_loc, *new_loc_p; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Lcreate_hard, FAIL) + FUNC_ENTER_API_META(H5Lcreate_hard, cur_loc_id, FAIL) H5TRACE6("e", "i*si*sii", cur_loc_id, cur_name, new_loc_id, new_name, lcpl_id, lapl_id); @@ -548,7 +549,7 @@ H5Lcreate_ud(hid_t link_loc_id, const char *link_name, H5L_type_t link_type, H5G_loc_t link_loc; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Lcreate_ud, FAIL) + FUNC_ENTER_API_META(H5Lcreate_ud, link_loc_id, FAIL) H5TRACE7("e", "i*sLl*xzii", link_loc_id, link_name, link_type, udata, udata_size, lcpl_id, lapl_id); @@ -590,7 +591,7 @@ H5Ldelete(hid_t loc_id, const char *name, hid_t lapl_id) H5G_loc_t loc; /* Group's location */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Ldelete, FAIL) + FUNC_ENTER_API_META(H5Ldelete, loc_id, FAIL) H5TRACE3("e", "i*si", loc_id, name, lapl_id); /* Check arguments */ @@ -635,7 +636,7 @@ H5Ldelete_by_idx(hid_t loc_id, const char *group_name, H5L_trav_rmbi_t udata; /* User data for callback */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Ldelete_by_idx, FAIL) + FUNC_ENTER_API_META(H5Ldelete_by_idx, loc_id, FAIL) H5TRACE6("e", "i*sIiIohi", loc_id, group_name, idx_type, order, n, lapl_id); /* Check arguments */ diff --git a/src/H5Lexternal.c b/src/H5Lexternal.c index 43751b3..70ed4b3 100644 --- a/src/H5Lexternal.c +++ b/src/H5Lexternal.c @@ -25,8 +25,9 @@ #include "H5Iprivate.h" /* IDs */ #include "H5Lpkg.h" /* Links */ #include "H5MMprivate.h" /* Memory management */ -#include "H5Opublic.h" /* File objects */ +#include "H5Opublic.h" /* File objects */ #include "H5Pprivate.h" /* Property lists */ +#include "H5AC2private.h" /* Metadata cache */ static hid_t H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group, const void *udata, size_t UNUSED udata_size, hid_t lapl_id); @@ -311,7 +312,7 @@ H5Lcreate_external(const char *file_name, const char *obj_name, uint8_t *p; /* Pointer into external link buffer */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Lcreate_external, FAIL) + FUNC_ENTER_API_META(H5Lcreate_external, link_loc_id, FAIL) H5TRACE6("e", "*s*si*sii", file_name, obj_name, link_loc_id, link_name, lcpl_id, lapl_id); @@ -46,6 +46,7 @@ #include "H5MFprivate.h" /* File memory management */ #include "H5Opkg.h" /* Object headers */ #include "H5SMprivate.h" /* Shared object header messages */ +#include "H5AC2private.h" /* Metadata cache */ /****************/ @@ -411,7 +412,7 @@ H5Olink(hid_t obj_id, hid_t new_loc_id, const char *new_name, hid_t lcpl_id, H5G_loc_t obj_loc; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Olink, FAIL) + FUNC_ENTER_API_META(H5Olink, obj_id, FAIL) H5TRACE5("e", "ii*sii", obj_id, new_loc_id, new_name, lcpl_id, lapl_id); /* Check arguments */ @@ -463,7 +464,7 @@ H5Oincr_refcount(hid_t object_id) H5O_loc_t *oloc; herr_t ret_value = SUCCEED; - FUNC_ENTER_API_META(H5Oincr_refcount, FAIL) + FUNC_ENTER_API_META(H5Oincr_refcount, object_id, FAIL) H5TRACE1("e", "i", object_id); /* Get the object's oloc so we can adjust its link count */ @@ -504,7 +505,7 @@ H5Odecr_refcount(hid_t object_id) H5O_loc_t *oloc; herr_t ret_value = SUCCEED; - FUNC_ENTER_API_META(H5Odecr_refcount, FAIL) + FUNC_ENTER_API_META(H5Odecr_refcount, object_id, FAIL) H5TRACE1("e", "i", object_id); /* Get the object's oloc so we can adjust its link count */ @@ -692,7 +693,7 @@ H5Oset_comment(hid_t obj_id, const char *comment) H5G_loc_t loc; /* Location of group */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Oset_comment, FAIL) + FUNC_ENTER_API_META(H5Oset_comment, obj_id, FAIL) H5TRACE2("e", "i*s", obj_id, comment); /* Check args */ @@ -732,7 +733,7 @@ H5Oset_comment_by_name(hid_t loc_id, const char *name, const char *comment, H5G_loc_t loc; /* Location of group */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Oset_comment_by_name, FAIL) + FUNC_ENTER_API_META(H5Oset_comment_by_name, loc_id, FAIL) H5TRACE4("e", "i*s*si", loc_id, name, comment, lapl_id); /* Check args */ @@ -862,7 +863,10 @@ H5Oclose(hid_t object_id) { herr_t ret_value = SUCCEED; - FUNC_ENTER_API_META(H5Oclose, FAIL) + /* Will this ever change metadata? No need for a transaction unless + * it does. + */ + FUNC_ENTER_API_META(H5Oclose, object_id, FAIL) H5TRACE1("e", "i", object_id); /* Get the type of the object and close it in the correct way */ diff --git a/src/H5Ocopy.c b/src/H5Ocopy.c index 334883d..5233f79 100644 --- a/src/H5Ocopy.c +++ b/src/H5Ocopy.c @@ -43,6 +43,8 @@ #include "H5MMprivate.h" /* Memory management */ #include "H5Opkg.h" /* Object headers */ #include "H5Pprivate.h" /* Property lists */ +#include "H5AC2private.h" /* Metadata cache */ + /****************/ /* Local Macros */ @@ -185,7 +187,7 @@ H5Ocopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Ocopy, FAIL) + FUNC_ENTER_API_META(H5Ocopy, dst_loc_id, FAIL) H5TRACE6("e", "i*si*sii", src_loc_id, src_name, dst_loc_id, dst_name, ocpypl_id, lcpl_id); @@ -29,6 +29,7 @@ #include "H5MMprivate.h" /* Memory management */ #include "H5Rpkg.h" /* References */ #include "H5Sprivate.h" /* Dataspaces */ +#include "H5AC2private.h" /* Metadata cache */ /* Local macro definitions */ @@ -311,7 +312,7 @@ H5Rcreate(void *ref, hid_t loc_id, const char *name, H5R_type_t ref_type, hid_t H5S_t *space = NULL; /* Pointer to dataspace containing region */ herr_t ret_value; /* Return value */ - FUNC_ENTER_API_META(H5Rcreate, FAIL) + FUNC_ENTER_API_META(H5Rcreate, loc_id, FAIL) H5TRACE5("e", "*xi*sRti", ref, loc_id, name, ref_type, space_id); /* Check args */ @@ -38,6 +38,7 @@ #include "H5MMprivate.h" /*memory management */ #include "H5Pprivate.h" /* Property Lists */ #include "H5Tpkg.h" /*data-type functions */ +#include "H5AC2private.h" /* Metadata cache */ /* Check for header needed for SGI floating-point code */ #ifdef H5_HAVE_SYS_FPU_H @@ -1700,7 +1701,7 @@ H5Tclose(hid_t type_id) H5T_t *dt = NULL; herr_t ret_value=SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Tclose, FAIL) + FUNC_ENTER_API_META(H5Tclose, type_id, FAIL) H5TRACE1("e", "i", type_id); /* Check args */ diff --git a/src/H5Tcommit.c b/src/H5Tcommit.c index 0beeeea..885227a 100644 --- a/src/H5Tcommit.c +++ b/src/H5Tcommit.c @@ -32,6 +32,7 @@ #include "H5Lprivate.h" /* Links */ #include "H5Pprivate.h" /* Property lists */ #include "H5Tpkg.h" /* Datatypes */ +#include "H5AC2private.h" /* Metadata cache */ /* Static local functions */ static H5T_t *H5T_open_oid(const H5G_loc_t *loc, hid_t dxpl_id); @@ -80,7 +81,7 @@ H5Tcommit2(hid_t loc_id, const char *name, hid_t type_id, hid_t lcpl_id, H5T_t *type; /* Datatype for ID */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Tcommit2, FAIL) + FUNC_ENTER_API_META(H5Tcommit2, loc_id, FAIL) H5TRACE6("e", "i*siiii", loc_id, name, type_id, lcpl_id, tcpl_id, tapl_id); /* Check arguments */ @@ -229,7 +230,7 @@ H5Tcommit_anon(hid_t loc_id, hid_t type_id, hid_t tcpl_id, hid_t tapl_id) H5T_t *type = NULL; herr_t ret_value=SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Tcommit_anon, FAIL) + FUNC_ENTER_API_META(H5Tcommit_anon, loc_id, FAIL) H5TRACE4("e", "iiii", loc_id, type_id, tcpl_id, tapl_id); /* Check arguments */ diff --git a/src/H5Tdeprec.c b/src/H5Tdeprec.c index 0ddf26e..fad2b05 100644 --- a/src/H5Tdeprec.c +++ b/src/H5Tdeprec.c @@ -46,6 +46,7 @@ #include "H5FOprivate.h" /* File objects */ #include "H5Iprivate.h" /* IDs */ #include "H5Tpkg.h" /* Datatypes */ +#include "H5AC2private.h" /* Metadata cache */ #ifndef H5_NO_DEPRECATED_SYMBOLS @@ -128,7 +129,7 @@ H5Tcommit1(hid_t loc_id, const char *name, hid_t type_id) H5T_t *type; /* Datatype for ID */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_META(H5Tcommit1, FAIL) + FUNC_ENTER_API_META(H5Tcommit1, loc_id, FAIL) H5TRACE3("e", "i*si", loc_id, name, type_id); /* Check arguments */ diff --git a/src/H5private.h b/src/H5private.h index 54f99ac1..48fbd01 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -1233,14 +1233,26 @@ static herr_t H5_INTERFACE_INIT_FUNC(void); { /* Use this macro for API functions that [could] modify metadata */ -#define FUNC_ENTER_API_META(func_name,err) {{ \ + +#define FUNC_ENTER_API_META(func_name, id, err) {{ \ FUNC_ENTER_API_VARS(func_name) \ FUNC_ENTER_COMMON(func_name,H5_IS_API(#func_name)); \ FUNC_ENTER_API_THREADSAFE; \ FUNC_ENTER_API_COMMON(func_name,err); \ /* Clear thread error stack entering public functions */ \ - H5E_clear_stack(NULL); \ - { + H5E_clear_stack(NULL); \ + { \ + uint64_t trans_num = 0; \ + H5O_loc_t id_oloc; \ + hbool_t do_transaction = FALSE; \ + hbool_t id_oloc_open = FALSE; \ + hbool_t transaction_begun = FALSE; \ + if (H5AC2_begin_transaction(id, &do_transaction, &id_oloc, \ + &id_oloc_open, &transaction_begun, \ + &trans_num, FUNC) < 0) { \ + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, err, \ + "H5AC2_begin_transaction() failed."); \ + } /* * Use this macro for API functions that shouldn't clear the error stack @@ -1388,7 +1400,14 @@ static herr_t H5_INTERFACE_INIT_FUNC(void); }} /*end scope from beginning of FUNC_ENTER*/ /* Use this macro to match the FUNC_ENTER_API_META macro */ + #define FUNC_LEAVE_API_META(ret_value) \ + if ( H5AC2_end_transaction(do_transaction, &id_oloc, \ + id_oloc_open, transaction_begun, \ + trans_num, FUNC) < 0 ) { \ + HDONE_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5AC2_end_transaction() failed."); \ + } \ FINISH_MPE_LOG; \ H5TRACE_RETURN(ret_value); \ H5_POP_FUNC; \ |