mirror of
https://github.com/HDFGroup/hdf5.git
synced 2025-02-23 16:20:57 +08:00
[svn-r16600] Description:
Ensure that metadata cache entries with flush dependencies are written to the file in the correct order (for serial I/O, at least). Tested on: FreeBSD/32 6.3 (duty) in debug mode FreeBSD/64 6.3 (liberty) w/C++ & FORTRAN, in debug mode Linux/32 2.6 (jam) w/PGI compilers, w/C++ & FORTRAN, w/threadsafe, in debug mode Linux/64-ia64 2.6 (cobalt) w/Intel compilers, w/C++ & FORTRAN, in production mode Linux/64-ia64 2.4 (tg-login3) w/parallel, w/FORTRAN, in production mode Linux/64-amd64 2.6 (abe) w/parallel, w/FORTRAN, in production mode Mac OS X/32 10.5.6 (amazon) in debug mode Mac OS X/32 10.5.6 (amazon) w/C++ & FORTRAN, w/threadsafe, in production mode
This commit is contained in:
parent
adf47d11b8
commit
667b34c713
156
src/H5C.c
156
src/H5C.c
@ -3808,30 +3808,30 @@ H5C_flush_cache(H5F_t * f,
|
||||
( protected_entries == 0 ) &&
|
||||
( flushed_entries_last_pass ) )
|
||||
{
|
||||
unsigned curr_flush_dep_height = 0;
|
||||
unsigned flush_dep_passes = 0;
|
||||
|
||||
flushed_entries_last_pass = FALSE;
|
||||
|
||||
/* Loop over all flush dependency heights of entries */
|
||||
while((curr_flush_dep_height <= H5C__NUM_FLUSH_DEP_HEIGHTS) &&
|
||||
(cache_ptr->slist_len != 0) &&
|
||||
(flush_dep_passes < H5C__MAX_PASSES_ON_FLUSH) )
|
||||
{
|
||||
hbool_t flushed_during_dep_loop = FALSE;
|
||||
|
||||
/* Start at beginning of skip list each time */
|
||||
node_ptr = H5SL_first(cache_ptr->slist_ptr);
|
||||
HDassert( node_ptr != NULL );
|
||||
|
||||
if ( node_ptr != NULL ) {
|
||||
|
||||
/* Get cache entry for this node */
|
||||
next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr);
|
||||
|
||||
if ( next_entry_ptr == NULL ) {
|
||||
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
|
||||
"next_entry_ptr == NULL 1 ?!?!");
|
||||
}
|
||||
if ( NULL == next_entry_ptr )
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "next_entry_ptr == NULL ?!?!")
|
||||
HDassert( next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC );
|
||||
HDassert( next_entry_ptr->is_dirty );
|
||||
HDassert( next_entry_ptr->in_slist );
|
||||
|
||||
} else {
|
||||
|
||||
next_entry_ptr = NULL;
|
||||
|
||||
}
|
||||
|
||||
HDassert( node_ptr != NULL );
|
||||
|
||||
#if H5C_DO_SANITY_CHECKS
|
||||
/* For sanity checking, try to verify that the skip list has
|
||||
* the expected size and number of entries at the end of each
|
||||
@ -3918,10 +3918,10 @@ H5C_flush_cache(H5F_t * f,
|
||||
( ! entry_ptr->in_slist ) ) {
|
||||
|
||||
/* the s-list has been modified out from under us.
|
||||
* set node_ptr to NULL and break out of the loop.
|
||||
* set node_ptr to NULL and break out of the inner loop.
|
||||
*/
|
||||
node_ptr = NULL;
|
||||
break;
|
||||
goto end_of_inner_loop;;
|
||||
}
|
||||
|
||||
/* increment node pointer now, before we delete its target
|
||||
@ -3964,11 +3964,7 @@ H5C_flush_cache(H5F_t * f,
|
||||
* aren't trying to do a destroy here, so that
|
||||
* is not an issue.
|
||||
*/
|
||||
if ( TRUE ) { /* When we get to multithreaded cache,
|
||||
* we will need either locking code,
|
||||
* and/or a test to see if the entry
|
||||
* is in flushable condition here.
|
||||
*/
|
||||
if(entry_ptr->flush_dep_height == curr_flush_dep_height ) {
|
||||
#if H5C_DO_SANITY_CHECKS
|
||||
flushed_entries_count++;
|
||||
flushed_entries_size += entry_ptr->size;
|
||||
@ -3990,9 +3986,18 @@ H5C_flush_cache(H5F_t * f,
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
|
||||
"dirty pinned entry flush failed.")
|
||||
}
|
||||
flushed_entries_last_pass = TRUE;
|
||||
}
|
||||
flushed_during_dep_loop = TRUE;
|
||||
} /* end if */
|
||||
else if(entry_ptr->flush_dep_height < curr_flush_dep_height)
|
||||
/* This shouldn't happen -- if it does, just scream and die. */
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "dirty entry below current flush dep. height.")
|
||||
} else {
|
||||
/* Test to see if we are can flush the entry now.
|
||||
* If we can, go ahead and flush. Note that we
|
||||
* aren't trying to do a destroy here, so that
|
||||
* is not an issue.
|
||||
*/
|
||||
if(entry_ptr->flush_dep_height == curr_flush_dep_height ){
|
||||
#if H5C_DO_SANITY_CHECKS
|
||||
flushed_entries_count++;
|
||||
flushed_entries_size += entry_ptr->size;
|
||||
@ -4014,11 +4019,34 @@ H5C_flush_cache(H5F_t * f,
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
|
||||
"Can't flush entry.")
|
||||
}
|
||||
flushed_entries_last_pass = TRUE;
|
||||
}
|
||||
}
|
||||
flushed_during_dep_loop = TRUE;
|
||||
} /* end if */
|
||||
else if(entry_ptr->flush_dep_height < curr_flush_dep_height)
|
||||
/* This shouldn't happen -- if it does, just scream and die. */
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "dirty entry below current flush dep. height.")
|
||||
} /* end else */
|
||||
} /* end if */
|
||||
} /* while ( node_ptr != NULL ) */
|
||||
|
||||
/* Check for incrementing flush dependency height */
|
||||
if(flushed_during_dep_loop) {
|
||||
/* If we flushed an entry at this flush dependency height
|
||||
* start over at the bottom level of the flush dependencies
|
||||
*/
|
||||
curr_flush_dep_height = 0;
|
||||
|
||||
/* Make certain we don't get stuck in an infinite loop */
|
||||
flush_dep_passes++;
|
||||
|
||||
/* Set flag for outer loop */
|
||||
flushed_entries_last_pass = TRUE;
|
||||
} /* end if */
|
||||
else
|
||||
curr_flush_dep_height++;
|
||||
|
||||
} /* while ( curr_flush_dep_height <= H5C__NUM_FLUSH_DEP_HEIGHTS) */
|
||||
end_of_inner_loop:
|
||||
|
||||
#if H5C_DO_SANITY_CHECKS
|
||||
/* Verify that the slist size and length are as expected. */
|
||||
|
||||
@ -8736,8 +8764,6 @@ H5C_destroy_flush_dependency(H5C_t * cache_ptr, void *parent_thing,
|
||||
HDassert(H5F_addr_defined(child_entry->addr));
|
||||
|
||||
/* Usage checks */
|
||||
if(!parent_entry->is_protected)
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Parent entry isn't pinned")
|
||||
if(!parent_entry->is_pinned)
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Parent entry isn't pinned")
|
||||
if(0 == parent_entry->flush_dep_height)
|
||||
@ -8785,6 +8811,9 @@ H5C_destroy_flush_dependency(H5C_t * cache_ptr, void *parent_thing,
|
||||
* parent of _any_ child flush dependencies).
|
||||
*/
|
||||
if(0 == parent_entry->flush_dep_height) {
|
||||
if(!parent_entry->is_protected)
|
||||
H5C__UPDATE_RP_FOR_UNPIN(cache_ptr, parent_entry, FAIL)
|
||||
|
||||
/* Unpin parent entry */
|
||||
parent_entry->is_pinned = FALSE;
|
||||
H5C__UPDATE_STATS_FOR_UNPIN(cache_ptr, parent_entry)
|
||||
@ -10263,6 +10292,16 @@ H5C_flush_invalidate_cache(H5F_t * f,
|
||||
|
||||
while ( ! done )
|
||||
{
|
||||
unsigned curr_flush_dep_height = 0;
|
||||
unsigned flush_dep_passes = 0;
|
||||
|
||||
/* Loop over all flush dependency heights of entries */
|
||||
while((curr_flush_dep_height <= H5C__NUM_FLUSH_DEP_HEIGHTS) &&
|
||||
(cache_ptr->index_len > 0 ) &&
|
||||
(flush_dep_passes < H5C__MAX_PASSES_ON_FLUSH) )
|
||||
{
|
||||
hbool_t flushed_during_dep_loop = FALSE;
|
||||
|
||||
/* first, try to flush-destroy any dirty entries. Do this by
|
||||
* making a scan through the slist. Note that new dirty entries
|
||||
* may be created by the flush call backs. Thus it is possible
|
||||
@ -10369,7 +10408,7 @@ H5C_flush_invalidate_cache(H5F_t * f,
|
||||
/* the s-list has been modified out from under us.
|
||||
* break out of the loop.
|
||||
*/
|
||||
break;
|
||||
goto end_of_inner_loop;;
|
||||
}
|
||||
|
||||
/* increment node pointer now, before we delete its target
|
||||
@ -10437,12 +10476,7 @@ H5C_flush_invalidate_cache(H5F_t * f,
|
||||
* H5C_flush_single_entry() to destroy the entry
|
||||
* as pinned entries can't be evicted.
|
||||
*/
|
||||
if ( TRUE ) { /* When we get to multithreaded cache,
|
||||
* we will need either locking code, and/or
|
||||
* a test to see if the entry is in flushable
|
||||
* condition here.
|
||||
*/
|
||||
|
||||
if(entry_ptr->flush_dep_height == curr_flush_dep_height ) {
|
||||
status = H5C_flush_single_entry(f,
|
||||
primary_dxpl_id,
|
||||
secondary_dxpl_id,
|
||||
@ -10460,9 +10494,15 @@ H5C_flush_invalidate_cache(H5F_t * f,
|
||||
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
|
||||
"dirty pinned entry flush failed.")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} /* end if */
|
||||
flushed_during_dep_loop = TRUE;
|
||||
} /* end if */
|
||||
else if(entry_ptr->flush_dep_height < curr_flush_dep_height)
|
||||
/* This shouldn't happen -- if it does, just scream and die. */
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "dirty entry below current flush dep. height.")
|
||||
} /* end if */
|
||||
else {
|
||||
if(entry_ptr->flush_dep_height == curr_flush_dep_height ){
|
||||
|
||||
status = H5C_flush_single_entry(f,
|
||||
primary_dxpl_id,
|
||||
@ -10482,8 +10522,13 @@ H5C_flush_invalidate_cache(H5F_t * f,
|
||||
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
|
||||
"dirty entry flush destroy failed.")
|
||||
}
|
||||
}
|
||||
} /* end if */
|
||||
flushed_during_dep_loop = TRUE;
|
||||
} /* end if */
|
||||
else if(entry_ptr->flush_dep_height < curr_flush_dep_height)
|
||||
/* This shouldn't happen -- if it does, just scream and die. */
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "dirty entry below current flush dep. height.")
|
||||
} /* end else */
|
||||
} /* end while loop scanning skip list */
|
||||
|
||||
#if H5C_DO_SANITY_CHECKS
|
||||
@ -10540,6 +10585,10 @@ H5C_flush_invalidate_cache(H5F_t * f,
|
||||
}
|
||||
} else if ( ! ( entry_ptr->is_pinned ) ) {
|
||||
|
||||
/* Test to see if we are can flush the entry now.
|
||||
* If we can, go ahead and flush.
|
||||
*/
|
||||
if(entry_ptr->flush_dep_height == curr_flush_dep_height ){
|
||||
status = H5C_flush_single_entry(f,
|
||||
primary_dxpl_id,
|
||||
secondary_dxpl_id,
|
||||
@ -10559,7 +10608,12 @@ H5C_flush_invalidate_cache(H5F_t * f,
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \
|
||||
"Entry flush destroy failed.")
|
||||
}
|
||||
}
|
||||
flushed_during_dep_loop = TRUE;
|
||||
} /* end if */
|
||||
else if(entry_ptr->flush_dep_height < curr_flush_dep_height)
|
||||
/* This shouldn't happen -- if it does, just scream and die. */
|
||||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "dirty entry below current flush dep. height.")
|
||||
} /* end if */
|
||||
/* We can't do anything if the entry is pinned. The
|
||||
* hope is that the entry will be unpinned as the
|
||||
* result of destroys of entries that reference it.
|
||||
@ -10593,6 +10647,22 @@ H5C_flush_invalidate_cache(H5F_t * f,
|
||||
} /* end while loop scanning hash table bin */
|
||||
} /* end for loop scanning hash table */
|
||||
|
||||
/* Check for incrementing flush dependency height */
|
||||
if(flushed_during_dep_loop) {
|
||||
/* If we flushed an entry at this flush dependency height
|
||||
* start over at the bottom level of the flush dependencies
|
||||
*/
|
||||
curr_flush_dep_height = 0;
|
||||
|
||||
/* Make certain we don't get stuck in an infinite loop */
|
||||
flush_dep_passes++;
|
||||
} /* end if */
|
||||
else
|
||||
curr_flush_dep_height++;
|
||||
|
||||
} /* end while loop over flush dependency heights */
|
||||
end_of_inner_loop:
|
||||
|
||||
old_pel_len = cur_pel_len;
|
||||
cur_pel_len = cache_ptr->pel_len;
|
||||
|
||||
|
@ -185,7 +185,7 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t * cache_ptr,
|
||||
|
||||
/* Maximum height of flush dependency relationships between entries. This is
|
||||
* currently tuned to the extensible array (H5EA) data structure, which only
|
||||
* requires 4 levels of dependency (i.e. heights 0-3).
|
||||
* requires 4 levels of dependency (i.e. heights 0-4).
|
||||
*/
|
||||
|
||||
#define H5C__NUM_FLUSH_DEP_HEIGHTS 4
|
||||
|
3976
test/cache.c
3976
test/cache.c
File diff suppressed because it is too large
Load Diff
@ -1171,7 +1171,8 @@ add_flush_op(int target_type,
|
||||
int type,
|
||||
int idx,
|
||||
hbool_t flag,
|
||||
size_t new_size)
|
||||
size_t new_size,
|
||||
unsigned * order_ptr)
|
||||
{
|
||||
int i;
|
||||
test_entry_t * target_base_addr;
|
||||
@ -1204,6 +1205,7 @@ add_flush_op(int target_type,
|
||||
(target_entry_ptr->flush_ops)[i].idx = idx;
|
||||
(target_entry_ptr->flush_ops)[i].flag = flag;
|
||||
(target_entry_ptr->flush_ops)[i].size = new_size;
|
||||
(target_entry_ptr->flush_ops)[i].order_ptr = order_ptr;
|
||||
|
||||
}
|
||||
|
||||
@ -1470,6 +1472,12 @@ execute_flush_op(H5C_t * cache_ptr,
|
||||
op_ptr->flag);
|
||||
break;
|
||||
|
||||
case FLUSH_OP__ORDER:
|
||||
HDassert( op_ptr->order_ptr );
|
||||
entry_ptr->flush_order = *op_ptr->order_ptr;
|
||||
(*op_ptr->order_ptr)++;
|
||||
break;
|
||||
|
||||
default:
|
||||
pass = FALSE;
|
||||
failure_mssg = "Undefined flush op code.";
|
||||
@ -1656,6 +1664,8 @@ reset_entries(void)
|
||||
base_addr[j].child_flush_dep_height_rc[k] = 0;
|
||||
base_addr[j].flush_dep_height = 0;
|
||||
|
||||
base_addr[j].flush_order = 0;
|
||||
|
||||
addr += (haddr_t)entry_size;
|
||||
alt_addr += (haddr_t)entry_size;
|
||||
} /* end for */
|
||||
@ -2252,8 +2262,25 @@ verify_entry_status(H5C_t * cache_ptr,
|
||||
} /* end if */
|
||||
} /* end if */
|
||||
|
||||
/* Flush dependency flush order */
|
||||
if ( pass ) {
|
||||
if ( expected[i].flush_order >= 0 && entry_ptr->flush_order != (unsigned)expected[i].flush_order ) {
|
||||
pass = FALSE;
|
||||
sprintf(msg,
|
||||
"%d entry (%d, %d) flush_order actual/expected = %u/%d.\n",
|
||||
tag,
|
||||
expected[i].entry_type,
|
||||
expected[i].entry_index,
|
||||
entry_ptr->flush_order,
|
||||
expected[i].flush_order);
|
||||
failure_mssg = msg;
|
||||
} /* end if */
|
||||
} /* end if */
|
||||
|
||||
i++;
|
||||
} /* while */
|
||||
if(!pass)
|
||||
HDfprintf(stderr, "failure_mssg = '%s'\n", failure_mssg);
|
||||
|
||||
return;
|
||||
|
||||
@ -5023,7 +5050,6 @@ destroy_flush_dependency(H5C_t * cache_ptr,
|
||||
/* Sanity check parent entry */
|
||||
HDassert( par_entry_ptr->index == par_idx );
|
||||
HDassert( par_entry_ptr->type == par_type );
|
||||
HDassert( par_entry_ptr->is_protected );
|
||||
HDassert( par_entry_ptr->is_pinned );
|
||||
HDassert( par_entry_ptr->flush_dep_height > 0 );
|
||||
HDassert( par_entry_ptr == par_entry_ptr->self );
|
||||
|
@ -127,7 +127,8 @@
|
||||
#define FLUSH_OP__DIRTY 1
|
||||
#define FLUSH_OP__RESIZE 2
|
||||
#define FLUSH_OP__RENAME 3
|
||||
#define FLUSH_OP__MAX_OP 3
|
||||
#define FLUSH_OP__ORDER 4
|
||||
#define FLUSH_OP__MAX_OP 4
|
||||
|
||||
#define MAX_FLUSH_OPS 10 /* Maximum number of flush operations
|
||||
* that can be associated with a
|
||||
@ -144,6 +145,7 @@ typedef struct flush_op
|
||||
* FLUSH_OP__DIRTY
|
||||
* FLUSH_OP__RESIZE
|
||||
* FLUSH_OP__RENAME
|
||||
* FLUSH_OP__ORDER
|
||||
*/
|
||||
int type; /* type code of the cache entry that
|
||||
* is the target of the operation.
|
||||
@ -183,6 +185,10 @@ typedef struct flush_op
|
||||
* FLUSH_OP__RENAME operation.
|
||||
* Unused elsewhere.
|
||||
*/
|
||||
unsigned * order_ptr; /* Pointer to outside counter for
|
||||
* recording the order of entries
|
||||
* flushed.
|
||||
*/
|
||||
} flush_op;
|
||||
|
||||
typedef struct test_entry_t
|
||||
@ -300,6 +306,7 @@ typedef struct test_entry_t
|
||||
* dependency children
|
||||
*/
|
||||
unsigned flush_dep_height; /* flush dependency height of entry */
|
||||
unsigned flush_order; /* Order that entry was flushed in */
|
||||
} test_entry_t;
|
||||
|
||||
/* The following is a cut down copy of the hash table manipulation
|
||||
@ -471,6 +478,7 @@ struct expected_entry_status
|
||||
* dependency children
|
||||
*/
|
||||
unsigned flush_dep_height; /* flush dependency height of entry */
|
||||
int flush_order; /* flush order of entry */
|
||||
};
|
||||
|
||||
|
||||
@ -602,7 +610,8 @@ void add_flush_op(int target_type,
|
||||
int type,
|
||||
int idx,
|
||||
hbool_t flag,
|
||||
size_t size);
|
||||
size_t size,
|
||||
unsigned * order);
|
||||
|
||||
|
||||
void addr_to_type_and_index(haddr_t addr,
|
||||
|
Loading…
Reference in New Issue
Block a user