[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:
Quincey Koziol 2009-03-24 12:52:17 -05:00
parent adf47d11b8
commit 667b34c713
5 changed files with 3611 additions and 1474 deletions

156
src/H5C.c
View File

@ -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;

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 );

View File

@ -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,