[svn-r9596] Purpose:

Code optimization

Description:
    Retarget metadata cache code from using TBBT routines to using new skiplist
routines, for a reasonable speedup (when dealing with dirty metadata)

Platforms tested:
    FreeBSD 4.10 (sleipnir) w/parallel
    Solaris 2.7  (arabica)
    Too minor to require h5committest
This commit is contained in:
Quincey Koziol 2004-11-29 14:55:18 -05:00
parent 3e99d8411c
commit 51ed85b277
5 changed files with 170 additions and 218 deletions

355
src/H5C.c
View File

@ -33,6 +33,10 @@
*
* Modifications:
*
* QAK - 11/27/2004
* Switched over to using skip list routines instead of TBBT
* routines.
*
*-------------------------------------------------------------------------
*/
@ -65,9 +69,9 @@
*
* - Create MPI type for dirty objects when flushing in parallel.
*
* - Fix TBBT routines so deletions don't move nodes in memory and
* point directly to the TBBT node from the LRU list, eliminating
* binary tree lookups when evicting objects from the cache.
* - Now that TBBT routines aren't used, fix nodes in memory to
* point directly to the skip list node from the LRU list, eliminating
* skip list lookups when evicting objects from the cache.
*
* Tests:
*
@ -93,7 +97,7 @@
#include "H5Iprivate.h" /* IDs */
#include "H5MMprivate.h" /* Memory management */
#include "H5Pprivate.h" /* Property lists */
#include "H5TBprivate.h" /* Threaded, Balanced, Binary Trees */
#include "H5SLprivate.h" /* Skip lists */
/****************************************************************************
@ -422,10 +426,10 @@ if ( ( (entry_ptr) == NULL ) || \
(cache_ptr)->max_index_len = (cache_ptr)->index_len; \
if ( (cache_ptr)->index_size > (cache_ptr)->max_index_size ) \
(cache_ptr)->max_index_size = (cache_ptr)->index_size; \
if ( (cache_ptr)->tree_len > (cache_ptr)->max_tree_len ) \
(cache_ptr)->max_tree_len = (cache_ptr)->tree_len; \
if ( (cache_ptr)->tree_size > (cache_ptr)->max_tree_size ) \
(cache_ptr)->max_tree_size = (cache_ptr)->tree_size; \
if ( (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] \
@ -433,10 +437,10 @@ if ( ( (entry_ptr) == NULL ) || \
}
#define H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr) \
if ( (cache_ptr)->tree_len > (cache_ptr)->max_tree_len ) \
(cache_ptr)->max_tree_len = (cache_ptr)->tree_len; \
if ( (cache_ptr)->tree_size > (cache_ptr)->max_tree_size ) \
(cache_ptr)->max_tree_size = (cache_ptr)->tree_size;
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 H5C__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr) \
(((cache_ptr)->renames)[(entry_ptr)->type->id])++;
@ -750,7 +754,7 @@ if ( ( (cache_ptr) == NULL ) || \
/**************************************************************************
*
* Tree insertion and deletion macros:
* Skip list insertion and deletion macros:
*
* These used to be functions, but I converted them to macros to avoid some
* function call overhead.
@ -759,10 +763,10 @@ if ( ( (cache_ptr) == NULL ) || \
/*-------------------------------------------------------------------------
*
* Macro: H5C__INSERT_ENTRY_IN_TREE
* Macro: H5C__INSERT_ENTRY_IN_SLIST
*
* Purpose: Insert the specified instance of H5C_cache_entry_t into
* the tree in the specified instance of H5C_t. Update
* the skip list in the specified instance of H5C_t. Update
* the associated length and size fields.
*
* Return: N/A
@ -786,45 +790,42 @@ if ( ( (cache_ptr) == NULL ) || \
* wringing a little more speed out of the cache.
*
* Note that we don't bother to check if the entry is already
* in the tree -- if it is, H5TB_dins() will fail.
* in the tree -- if it is, H5SL_insert() will fail.
*
* QAK -- 11/27/04
* Switched over to using skip list routines.
*
*-------------------------------------------------------------------------
*/
#define H5C__INSERT_ENTRY_IN_TREE(cache_ptr, entry_ptr) \
#define H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr) \
{ \
H5TB_NODE * loc_node_ptr = NULL; \
\
HDassert( (cache_ptr) ); \
HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
HDassert( (entry_ptr) ); \
HDassert( (entry_ptr)->size > 0 ); \
HDassert( H5F_addr_defined((entry_ptr)->addr) ); \
HDassert( !((entry_ptr)->in_tree) ); \
HDassert( !((entry_ptr)->in_slist) ); \
\
loc_node_ptr = H5TB_dins((cache_ptr)->tree_ptr, (void *)(entry_ptr), NULL);\
if ( H5SL_insert((cache_ptr)->slist_ptr, &entry_ptr->addr, entry_ptr) < 0 ) \
HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "Can't insert entry in skip list") \
\
if ( loc_node_ptr == NULL ) { \
(entry_ptr)->in_slist = TRUE; \
(cache_ptr)->slist_len++; \
(cache_ptr)->slist_size += (entry_ptr)->size; \
\
HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't insert entry in tree") \
} \
HDassert( (cache_ptr)->slist_len > 0 ); \
HDassert( (cache_ptr)->slist_size > 0 ); \
\
(entry_ptr)->in_tree = TRUE; \
(cache_ptr)->tree_len++; \
(cache_ptr)->tree_size += (entry_ptr)->size; \
\
HDassert( (cache_ptr)->tree_len > 0 ); \
HDassert( (cache_ptr)->tree_size > 0 ); \
\
} /* H5C__INSERT_ENTRY_IN_TREE */
} /* H5C__INSERT_ENTRY_IN_SLIST */
/*-------------------------------------------------------------------------
*
* Function: H5C__REMOVE_ENTRY_FROM_TREE
* Function: H5C__REMOVE_ENTRY_FROM_SLIST
*
* Purpose: Remove the specified instance of H5C_cache_entry_t from the
* index tree in the specified instance of H5C_t. Update
* index skip list in the specified instance of H5C_t. Update
* the associated length and size fields.
*
* Return: N/A
@ -841,37 +842,34 @@ if ( ( (cache_ptr) == NULL ) || \
* to the macro H5C__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.
*
*-------------------------------------------------------------------------
*/
#define H5C__REMOVE_ENTRY_FROM_TREE(cache_ptr, entry_ptr, node_ptr) \
#define H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) \
{ \
HDassert( (cache_ptr) ); \
HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC ); \
HDassert( (entry_ptr) ); \
HDassert( !((entry_ptr)->is_protected) ); \
HDassert( (node_ptr) ); \
HDassert( (node_ptr)->data == (entry_ptr) ); \
HDassert( (entry_ptr)->size > 0 ); \
HDassert( (entry_ptr)->in_tree ); \
HDassert( (cache_ptr)->tree_ptr ); \
HDassert( (cache_ptr)->tree_ptr->root ); \
HDassert( (entry_ptr)->in_slist ); \
HDassert( (cache_ptr)->slist_ptr ); \
\
if ( H5TB_rem(&((cache_ptr)->tree_ptr->root), (node_ptr), NULL) \
!= (entry_ptr) ) { \
if ( H5SL_remove((cache_ptr)->slist_ptr, &(entry_ptr)->addr) \
!= (entry_ptr) ) \
\
HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
"Can't delete entry from tree.") \
HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, \
"Can't delete entry from skip list.") \
\
} else { \
\
HDassert( (cache_ptr)->tree_len > 0 ); \
(cache_ptr)->tree_len--; \
HDassert( (cache_ptr)->tree_size >= (entry_ptr)->size ); \
(cache_ptr)->tree_size -= (entry_ptr)->size; \
(entry_ptr)->in_tree = FALSE; \
} \
} /* H5C__REMOVE_ENTRY_FROM_TREE */
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; \
} /* H5C__REMOVE_ENTRY_FROM_SLIST */
/**************************************************************************
@ -1589,6 +1587,11 @@ if ( ( (cache_ptr) == NULL ) || \
*
* JRM - 7/19/04
*
* Note that the dirty entries are now stored in a skip list, instead of
* the threaded, balanced binary tree (TBBT).
*
* QAK - 11/27/04
*
* *********************************************
*
* WARNING: A copy of H5C_t is in tst/cache.c (under the name "local_H5C_t"
@ -1680,23 +1683,23 @@ if ( ( (cache_ptr) == NULL ) || \
*
*
* When we flush the cache, we need to write entries out in increasing
* address order. An instance of TBBT is used to store dirty entries in
* address order. An instance of a skip list is used to store dirty entries in
* sorted order. Whether it is cheaper to sort the dirty entries as needed,
* or to maintain the tree is an open question. At a guess, it depends
* or to maintain the list is an open question. At a guess, it depends
* on how frequently the cache is flushed. We will see how it goes.
*
* For now at least, I will not remove dirty entries from the tree as they
* For now at least, I will not remove dirty entries from the list as they
* are flushed.
*
* tree_len: Number of entries currently in the threaded binary B-tree
* slist_len: Number of entries currently in the skip list
* used to maintain a sorted list of dirty entries in the
* cache.
*
* tree_size: Number of bytes of cache entries currently stored in the
* threaded binary B-tree used to maintain a sorted list of
* slist_size: Number of bytes of cache entries currently stored in the
* skip list used to maintain a sorted list of
* dirty entries in the cache.
*
* tree_ptr: pointer to the instance of H5TB_TREE used maintain a sorted
* slist_ptr: pointer to the instance of H5SL_t used maintain a sorted
* list of dirty entries in the cache. This sorted list has
* two uses:
*
@ -1913,10 +1916,10 @@ if ( ( (cache_ptr) == NULL ) || \
* max_index_size: Largest value attained by the index_size field in the
* current epoch.
*
* max_tree_len: Largest value attained by the tree_len field in the
* max_slist_len: Largest value attained by the slist_len field in the
* current epoch.
*
* max_tree_size: Largest value attained by the tree_size field in the
* max_slist_size: Largest value attained by the slist_size field in the
* current epoch.
*
* max_pl_len: Largest value attained by the pl_len field in the
@ -1997,9 +2000,9 @@ struct H5C_t
H5C_cache_entry_t * (index[H5C__HASH_TABLE_LEN]);
int32_t tree_len;
size_t tree_size;
H5TB_TREE * tree_ptr;
int32_t slist_len;
size_t slist_size;
H5SL_t * slist_ptr;
int32_t pl_len;
size_t pl_size;
@ -2042,8 +2045,8 @@ struct H5C_t
int32_t max_index_len;
size_t max_index_size;
int32_t max_tree_len;
size_t max_tree_size;
int32_t max_slist_len;
size_t max_slist_size;
int32_t max_pl_len;
size_t max_pl_size;
@ -2084,9 +2087,8 @@ static herr_t H5C_flush_single_entry(H5F_t * f,
const H5C_class_t * type_ptr,
haddr_t addr,
unsigned flags,
H5TB_NODE * tgt_node_ptr,
hbool_t * first_flush_ptr,
hbool_t del_entry_from_tree_on_destroy);
hbool_t del_entry_from_slist_on_destroy);
static void * H5C_load_entry(H5F_t * f,
hid_t dxpl_id,
@ -2167,10 +2169,10 @@ H5C_create(size_t max_cache_size,
"memory allocation failed")
}
if ( (cache_ptr->tree_ptr = H5TB_fast_dmake(H5TB_FAST_HADDR_COMPARE))
if ( (cache_ptr->slist_ptr = H5SL_create(H5SL_TYPE_HADDR,0.5,16))
== NULL ) {
HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, NULL, "can't create TBBT.")
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
@ -2190,8 +2192,8 @@ H5C_create(size_t max_cache_size,
cache_ptr->index_len = 0;
cache_ptr->index_size = (size_t)0;
cache_ptr->tree_len = 0;
cache_ptr->tree_size = (size_t)0;
cache_ptr->slist_len = 0;
cache_ptr->slist_size = (size_t)0;
for ( i = 0; i < H5C__HASH_TABLE_LEN; i++ )
{
@ -2232,13 +2234,8 @@ done:
if ( cache_ptr != NULL ) {
if ( cache_ptr->tree_ptr != NULL ) {
/* the index tree should be empty, so we can pass in
* NULL for the fd & fk parameters.
*/
H5TB_dfree(cache_ptr->tree_ptr, NULL, NULL);
}
if ( cache_ptr->slist_ptr != NULL )
H5SL_close(cache_ptr->slist_ptr);
cache_ptr->magic = 0;
H5FL_FREE(H5C_t, cache_ptr);
@ -2299,13 +2296,10 @@ H5C_dest(H5F_t * f,
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache")
}
if ( cache_ptr->tree_ptr != NULL ) {
if ( cache_ptr->slist_ptr != NULL ) {
/* the index tree should be empty, so we can pass in
* NULL for the fd & fk parameters.
*/
H5TB_dfree(cache_ptr->tree_ptr, NULL, NULL);
cache_ptr->tree_ptr = NULL;
H5SL_close(cache_ptr->slist_ptr);
cache_ptr->slist_ptr = NULL;
}
cache_ptr->magic = 0;
@ -2355,13 +2349,10 @@ H5C_dest_empty(H5C_t * cache_ptr)
}
if ( cache_ptr->tree_ptr != NULL ) {
if ( cache_ptr->slist_ptr != NULL ) {
/* the tree should be empty, so we can pass in
* NULL for the fd & fk parameters.
*/
H5TB_dfree(cache_ptr->tree_ptr, NULL, NULL);
cache_ptr->tree_ptr = NULL;
H5SL_close(cache_ptr->slist_ptr);
cache_ptr->slist_ptr = NULL;
}
cache_ptr->magic = 0;
@ -2418,11 +2409,11 @@ H5C_flush_cache(H5F_t * f,
hbool_t first_flush = TRUE;
int32_t protected_entries = 0;
int32_t i;
H5TB_NODE * node_ptr;
H5SL_node_t * node_ptr;
H5C_cache_entry_t * entry_ptr;
#if H5C_DO_SANITY_CHECKS
int32_t actual_tree_len = 0;
size_t actual_tree_size = 0;
int32_t actual_slist_len = 0;
size_t actual_slist_size = 0;
#endif /* H5C_DO_SANITY_CHECKS */
FUNC_ENTER_NOAPI(H5C_flush_cache, FAIL)
@ -2430,29 +2421,28 @@ H5C_flush_cache(H5F_t * f,
HDassert( cache_ptr );
HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
HDassert( cache_ptr->skip_file_checks || f );
HDassert( cache_ptr->tree_ptr );
HDassert( cache_ptr->slist_ptr );
if ( cache_ptr->tree_ptr->root == NULL ) {
if ( cache_ptr->slist_len == 0 ) {
node_ptr = NULL;
HDassert( cache_ptr->tree_len == 0 );
HDassert( cache_ptr->tree_size == 0 );
HDassert( cache_ptr->slist_size == 0 );
} else {
node_ptr = H5TB_first(cache_ptr->tree_ptr->root);
node_ptr = H5SL_first(cache_ptr->slist_ptr);
}
while ( node_ptr != NULL )
{
entry_ptr = (H5C_cache_entry_t *)(node_ptr->data);
entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
HDassert( entry_ptr != NULL );
HDassert( entry_ptr->in_tree );
HDassert( entry_ptr->in_slist );
#if H5C_DO_SANITY_CHECKS
actual_tree_len++;
actual_tree_size += entry_ptr->size;
actual_slist_len++;
actual_slist_size += entry_ptr->size;
#endif /* H5C_DO_SANITY_CHECKS */
if ( entry_ptr->is_protected ) {
@ -2471,7 +2461,6 @@ H5C_flush_cache(H5F_t * f,
NULL,
entry_ptr->addr,
flags,
node_ptr,
&first_flush,
FALSE);
if ( status < 0 ) {
@ -2484,23 +2473,31 @@ H5C_flush_cache(H5F_t * f,
}
}
node_ptr = H5TB_next(node_ptr);
node_ptr = H5SL_next(node_ptr);
} /* while */
#if H5C_DO_SANITY_CHECKS
HDassert( actual_tree_len == cache_ptr->tree_len );
HDassert( actual_tree_size == cache_ptr->tree_size );
HDassert( actual_slist_len == cache_ptr->slist_len );
HDassert( actual_slist_size == cache_ptr->slist_size );
#endif /* H5C_DO_SANITY_CHECKS */
if ( destroy ) {
/* don't pass in any key or data free functions, as all
* unprotected entries should have already been destroyed.
*/
H5TB_free(&(cache_ptr->tree_ptr->root), NULL, NULL);
cache_ptr->tree_len = 0;
cache_ptr->tree_size = 0;
if(cache_ptr->slist_ptr) {
/* XXX: Replace this with call to H5SL_free() when its implemented... */
H5SL_close(cache_ptr->slist_ptr);
/* XXX: ...and remove this call */
if ( (cache_ptr->slist_ptr = H5SL_create(H5SL_TYPE_HADDR,0.5,16))
== NULL ) {
HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create skip list.")
}
}
cache_ptr->slist_len = 0;
cache_ptr->slist_size = 0;
/* Since we are doing a destroy, we must make a pass through
* the hash table and flush all entries that remain. Note that
@ -2521,7 +2518,7 @@ H5C_flush_cache(H5F_t * f,
H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr)
if ( !entry_ptr->in_tree ) {
if ( !entry_ptr->in_slist ) {
protected_entries++;
HDassert( !(entry_ptr->is_dirty) );
@ -2529,7 +2526,7 @@ H5C_flush_cache(H5F_t * f,
} else {
HDassert( !(entry_ptr->is_dirty) );
HDassert( !(entry_ptr->in_tree) );
HDassert( !(entry_ptr->in_slist) );
status = H5C_flush_single_entry(f,
primary_dxpl_id,
@ -2538,7 +2535,6 @@ H5C_flush_cache(H5F_t * f,
NULL,
entry_ptr->addr,
flags,
NULL,
&first_flush,
FALSE);
if ( status < 0 ) {
@ -2567,13 +2563,13 @@ H5C_flush_cache(H5F_t * f,
while ( entry_ptr != NULL )
{
entry_ptr->in_tree = FALSE;
entry_ptr->in_slist = FALSE;
H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL)
if ( entry_ptr->is_dirty ) {
H5C__INSERT_ENTRY_IN_TREE(cache_ptr, entry_ptr)
H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr)
}
entry_ptr = entry_ptr->next;
}
@ -2666,7 +2662,7 @@ H5C_insert_entry(H5F_t * f,
HDassert( entry_ptr->size < H5C_MAX_ENTRY_SIZE );
entry_ptr->in_tree = FALSE;
entry_ptr->in_slist = FALSE;
entry_ptr->ht_next = NULL;
entry_ptr->ht_prev = NULL;
@ -2771,7 +2767,7 @@ H5C_insert_entry(H5F_t * f,
if ( entry_ptr->is_dirty ) {
H5C__INSERT_ENTRY_IN_TREE(cache_ptr, entry_ptr)
H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr)
}
H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, FAIL)
@ -2813,10 +2809,8 @@ H5C_rename_entry(H5F_t * f,
haddr_t new_addr)
{
herr_t ret_value = SUCCEED; /* Return value */
H5TB_NODE * old_node_ptr = NULL;
H5C_cache_entry_t * entry_ptr = NULL;
H5C_cache_entry_t * test_entry_ptr = NULL;
H5C_cache_entry_t search_target;
FUNC_ENTER_NOAPI(H5C_rename_entry, FAIL)
@ -2830,30 +2824,14 @@ H5C_rename_entry(H5F_t * f,
H5C__SEARCH_INDEX(cache_ptr, old_addr, entry_ptr, FAIL)
if ( ( entry_ptr == NULL ) || ( entry_ptr->type != type ) ) {
if ( ( entry_ptr == NULL ) || ( entry_ptr->type != type ) )
/* the old item doesn't exist in the cache, so we are done. */
HGOTO_DONE(SUCCEED)
} else {
HDassert( entry_ptr->addr == old_addr );
HDassert( entry_ptr->type == type );
HDassert( !(entry_ptr->is_protected) );
if ( entry_ptr->in_tree ) {
HDassert( cache_ptr->tree_ptr );
search_target.addr = old_addr;
old_node_ptr = H5TB_dfind(cache_ptr->tree_ptr,
(void *)(&search_target),
NULL);
HDassert( old_node_ptr != NULL );
HDassert( old_node_ptr->key == (void *)entry_ptr );
}
}
HDassert( entry_ptr->addr == old_addr );
HDassert( entry_ptr->type == type );
HDassert( !(entry_ptr->is_protected) );
H5C__SEARCH_INDEX(cache_ptr, new_addr, test_entry_ptr, FAIL)
@ -2872,7 +2850,7 @@ H5C_rename_entry(H5F_t * f,
}
/* If we get this far, we have work to do. Remove *entry_ptr from
* the hash table (and tree if necessary), change its address to the
* the hash table (and skip list if necessary), change its address to the
* new address, and then re-insert.
*
* Update the replacement policy for a hit to avoid an eviction before
@ -2883,9 +2861,11 @@ H5C_rename_entry(H5F_t * f,
*/
H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr)
if ( old_node_ptr ) {
if ( entry_ptr->in_slist ) {
H5C__REMOVE_ENTRY_FROM_TREE(cache_ptr, entry_ptr, old_node_ptr)
HDassert( cache_ptr->slist_ptr );
H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr)
}
entry_ptr->addr = new_addr;
@ -2894,7 +2874,7 @@ H5C_rename_entry(H5F_t * f,
if ( entry_ptr->is_dirty ) {
H5C__INSERT_ENTRY_IN_TREE(cache_ptr, entry_ptr)
H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr)
}
H5C__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, FAIL)
@ -3058,7 +3038,7 @@ H5C_protect(H5F_t * f,
}
/* Insert the entry in the hash table. It can't be dirty yet, so
* we don't even check to see if it should go in the tree.
* we don't even check to see if it should go in the skip list.
*/
H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, NULL)
@ -3133,8 +3113,8 @@ done:
*
* JRM - 7/21/04
* Updated the function for the addition of the hash table.
* In particular, we now add dirty entries to the tree if
* they aren't in the tree already.
* In particular, we now add dirty entries to the skip list if
* they aren't in the list already.
*
*-------------------------------------------------------------------------
*/
@ -3178,13 +3158,13 @@ H5C_unprotect(H5F_t * f,
entry_ptr->is_protected = FALSE;
/* add the entry to the tree if it is dirty, and it isn't already in
* the tree.
/* add the entry to the skip list if it is dirty, and it isn't already in
* the list.
*/
if ( ( entry_ptr->is_dirty ) && ( ! (entry_ptr->in_tree) ) ) {
if ( ( entry_ptr->is_dirty ) && ( ! (entry_ptr->in_slist) ) ) {
H5C__INSERT_ENTRY_IN_TREE(cache_ptr, entry_ptr)
H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr)
}
/* this implementation of the "deleted" option is a bit inefficient, as
@ -3227,7 +3207,6 @@ H5C_unprotect(H5F_t * f,
type,
addr,
(H5F_FLUSH_CLEAR_ONLY|H5F_FLUSH_INVALIDATE),
NULL,
&dummy_first_flush,
TRUE) < 0 ) {
@ -3382,11 +3361,11 @@ H5C_stats(H5C_t * cache_ptr,
(long)(cache_ptr->max_index_len));
HDfprintf(stdout,
" current (max) tree size / length = %ld (%ld) / %ld (%ld)\n",
(long)(cache_ptr->tree_size),
(long)(cache_ptr->max_tree_size),
(long)(cache_ptr->tree_len),
(long)(cache_ptr->max_tree_len));
" current (max) skip list size / length = %ld (%ld) / %ld (%ld)\n",
(long)(cache_ptr->slist_size),
(long)(cache_ptr->max_slist_size),
(long)(cache_ptr->slist_len),
(long)(cache_ptr->max_slist_len));
HDfprintf(stdout,
" current (max) PL size / length = %ld (%ld) / %ld (%ld)\n",
@ -3559,8 +3538,8 @@ H5C_stats__reset(H5C_t * cache_ptr)
cache_ptr->max_index_len = 0;
cache_ptr->max_index_size = (size_t)0;
cache_ptr->max_tree_len = 0;
cache_ptr->max_tree_size = (size_t)0;
cache_ptr->max_slist_len = 0;
cache_ptr->max_slist_size = (size_t)0;
cache_ptr->max_pl_len = 0;
cache_ptr->max_pl_size = (size_t)0;
@ -3682,6 +3661,9 @@ done:
* JRM -- 7/21/04
* Updated function for the addition of the hash table.
*
* QAK -- 11/26/04
* Updated function for the switch from TBBTs to skip lists.
*
*-------------------------------------------------------------------------
*/
static herr_t
@ -3692,17 +3674,14 @@ H5C_flush_single_entry(H5F_t * f,
const H5C_class_t * type_ptr,
haddr_t addr,
unsigned flags,
H5TB_NODE * tgt_node_ptr,
hbool_t * first_flush_ptr,
hbool_t del_entry_from_tree_on_destroy)
hbool_t del_entry_from_slist_on_destroy)
{
hbool_t destroy = ( (flags & H5F_FLUSH_INVALIDATE) != 0 );
hbool_t clear_only = ( (flags & H5F_FLUSH_CLEAR_ONLY) != 0);
herr_t ret_value = SUCCEED; /* Return value */
herr_t status;
H5TB_NODE * node_ptr;
H5C_cache_entry_t * entry_ptr = NULL;
H5C_cache_entry_t search_target;
FUNC_ENTER_NOAPI_NOINIT(H5C_flush_single_entry)
@ -3715,37 +3694,17 @@ H5C_flush_single_entry(H5F_t * f,
/* attempt to find the target entry in the hash table */
H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL)
/* If tgt_node_ptr is NULL, look up the target entry in the tree. */
if ( tgt_node_ptr == NULL ) {
HDassert( cache_ptr->tree_ptr );
search_target.addr = addr;
node_ptr = H5TB_dfind(cache_ptr->tree_ptr,
(void *)&search_target,
NULL);
} else {
node_ptr = tgt_node_ptr;
}
#if H5C_DO_SANITY_CHECKS
if ( node_ptr != NULL ) {
if ( entry_ptr->in_slist ) {
if ( ( entry_ptr == NULL ) ||
( entry_ptr != (H5C_cache_entry_t *)(node_ptr->data) ) ||
( ! (entry_ptr->in_tree) ) ||
( entry_ptr->addr != addr ) ||
( node_ptr->data != node_ptr->key ) ) {
if ( ( entry_ptr->addr != addr ) ) {
HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
"Hash table and tree out of sync.")
"Hash table and skip list out of sync.")
}
} else if ( entry_ptr != NULL ) {
if ( ( entry_ptr->in_tree ) ||
if ( ( entry_ptr->in_slist ) ||
( entry_ptr->is_dirty ) ||
( entry_ptr->addr != addr ) ) {
@ -3820,9 +3779,9 @@ H5C_flush_single_entry(H5F_t * f,
}
/* Always remove the entry from the hash table on a destroy. On a
* flush with destroy, it is cheaper to discard the tree all at once
* flush with destroy, it is cheaper to discard the skip list all at once
* rather than remove the entries one by one, so we only delete from
* the tree if requested.
* the list if requested.
*
* We must do deletions now as the callback routines will free the
* entry if destroy is true.
@ -3831,9 +3790,9 @@ H5C_flush_single_entry(H5F_t * f,
H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr)
if ( ( node_ptr ) && ( del_entry_from_tree_on_destroy ) ) {
if ( ( entry_ptr->in_slist ) && ( del_entry_from_slist_on_destroy ) ) {
H5C__REMOVE_ENTRY_FROM_TREE(cache_ptr, entry_ptr, node_ptr)
H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr)
}
}
@ -3948,7 +3907,7 @@ H5C_load_entry(H5F_t * f,
entry_ptr->addr = addr;
entry_ptr->type = type;
entry_ptr->is_protected = FALSE;
entry_ptr->in_tree = FALSE;
entry_ptr->in_slist = FALSE;
if ( (type->size)(f, thing, &(entry_ptr->size)) < 0 ) {
@ -4069,7 +4028,6 @@ H5C_make_space_in_cache(H5F_t * f,
entry_ptr->type,
entry_ptr->addr,
(unsigned)0,
NULL,
&first_flush,
FALSE);
} else {
@ -4081,7 +4039,6 @@ H5C_make_space_in_cache(H5F_t * f,
entry_ptr->type,
entry_ptr->addr,
H5F_FLUSH_INVALIDATE,
NULL,
&first_flush,
TRUE);
}
@ -4107,7 +4064,7 @@ H5C_make_space_in_cache(H5F_t * f,
{
HDassert( ! (entry_ptr->is_protected) );
HDassert( entry_ptr->is_dirty );
HDassert( entry_ptr->in_tree );
HDassert( entry_ptr->in_slist );
prev_ptr = entry_ptr->aux_prev;
@ -4118,7 +4075,6 @@ H5C_make_space_in_cache(H5F_t * f,
entry_ptr->type,
entry_ptr->addr,
(unsigned)0,
NULL,
&first_flush,
FALSE);
@ -4162,7 +4118,6 @@ H5C_make_space_in_cache(H5F_t * f,
entry_ptr->type,
entry_ptr->addr,
H5F_FLUSH_INVALIDATE,
NULL,
&first_flush,
TRUE);

View File

@ -158,20 +158,14 @@ typedef herr_t (*H5C_write_permitted_func_t)(H5F_t *f,
* structure H5C_cache_entry_t
*
* Instances of the H5C_cache_entry_t structure are used to store cache
* entries in a hash table and sometimes in a threaded balanced binary tree.
* See H5TB.c for the particulars of the tree.
* entries in a hash table and sometimes in a skip list.
* See H5SL.c for the particulars of the skip list.
*
* In typical application, this structure is the first field in a
* structure to be cached. For historical reasons, the external module
* is responsible for managing the is_dirty field. All other fields are
* managed by the cache.
*
* Note that our current implementation of a threaded balanced binary tree
* will occasionaly change the node a particular datum is associated with.
* Thus this structure does not have a back pointer to its tree node. If we
* ever modify the threaded balanced binary tree code to fix this, a back
* pointer would save us a few tree traversals.
*
* The fields of this structure are discussed individually below:
*
* JRM - 4/26/04
@ -214,10 +208,10 @@ typedef herr_t (*H5C_write_permitted_func_t)(H5F_t *f,
* Note that protected entries are removed from the LRU lists
* and inserted on the protected list.
*
* in_tree: Boolean flag indicating whether the entry is in the threaded
* balanced binary tree. As a general rule, entries are placed
* in the tree when they are marked dirty. However they may
* remain in the tree after being flushed.
* in_slist: Boolean flag indicating whether the entry is in the skip list
* As a general rule, entries are placed in the list when they
* are marked dirty. However they may remain in the list after
* being flushed.
*
*
* Fields supporting the hash table:
@ -322,7 +316,7 @@ typedef struct H5C_cache_entry_t
const H5C_class_t * type;
hbool_t is_dirty;
hbool_t is_protected;
hbool_t in_tree;
hbool_t in_slist;
/* fields supporting the hash table: */

View File

@ -25,7 +25,7 @@
/* Private headers needed by this file */
#include "H5private.h" /* Generic Functions */
#include "H5Fprivate.h" /* File access */
#include "H5SLprivate.h" /* Skip list routines */
#include "H5SLprivate.h" /* Skip lists */
/* Typedefs */

View File

@ -47,8 +47,7 @@
/* Define the code template for insertions for the "OP" in the H5SL_FIND macro */
#define H5SL_FIND_INSERT_FOUND(SLIST,X,UPDATE,I,ITEM) \
X->item=ITEM; \
HGOTO_DONE(SUCCEED);
HGOTO_DONE(FAIL);
/* Define the code template for removals for the "OP" in the H5SL_FIND macro */
#define H5SL_FIND_REMOVE_FOUND(SLIST,X,UPDATE,I,ITEM) \
@ -381,8 +380,7 @@ H5SL_count(H5SL_t *slist)
Insert element into a skip list.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
Inserting an item with the same key as an existing object replaces
the existing object's item pointer with the new item pointer.
Inserting an item with the same key as an existing object fails.
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/

View File

@ -181,6 +181,11 @@ test_skiplist_insert(void)
found_item=H5SL_search(slist,&search_key);
VERIFY(found_item, NULL, "H5SL_search");
/* Attempt to insert duplicate key (should fail) */
search_key=2;
ret=H5SL_insert(slist,&search_key,&search_key);
VERIFY(ret, FAIL, "H5SL_insert");
/* Close the skip list */
ret=H5SL_close(slist);
CHECK(ret, FAIL, "H5SL_close");