-
-
Notifications
You must be signed in to change notification settings - Fork 310
Fix issue with handling of failure during discard of metadata cache entries #5817
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,6 +63,9 @@ static herr_t H5C__pin_entry_from_client(H5C_t *cache_ptr, H5C_cache_entry_t *en | |
static herr_t H5C__unpin_entry_real(H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr, bool update_rp); | ||
static herr_t H5C__unpin_entry_from_client(H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr, bool update_rp); | ||
static herr_t H5C__generate_image(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr); | ||
static herr_t H5C__discard_single_entry(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr, | ||
bool destroy_entry, bool free_file_space, | ||
bool suppress_image_entry_frees); | ||
static herr_t H5C__verify_len_eoa(H5F_t *f, const H5C_class_t *type, haddr_t addr, size_t *len, bool actual); | ||
static void *H5C__load_entry(H5F_t *f, | ||
#ifdef H5_HAVE_PARALLEL | ||
|
@@ -753,118 +756,13 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) | |
* Now discard the entry if appropriate. | ||
*/ | ||
if (destroy) { | ||
/* Sanity check */ | ||
assert(0 == entry_ptr->flush_dep_nparents); | ||
|
||
/* if both suppress_image_entry_frees and entry_ptr->include_in_image | ||
* are true, simply set entry_ptr->image_ptr to NULL, as we have | ||
* another pointer to the buffer in an instance of H5C_image_entry_t | ||
* in cache_ptr->image_entries. | ||
* | ||
* Otherwise, free the buffer if it exists. | ||
*/ | ||
if (suppress_image_entry_frees && entry_ptr->include_in_image) | ||
entry_ptr->image_ptr = NULL; | ||
else if (entry_ptr->image_ptr != NULL) | ||
entry_ptr->image_ptr = H5MM_xfree(entry_ptr->image_ptr); | ||
|
||
/* If the entry is not a prefetched entry, verify that the flush | ||
* dependency parents addresses array has been transferred. | ||
* | ||
* If the entry is prefetched, the free_isr routine will dispose of | ||
* the flush dependency parents addresses array if necessary. | ||
*/ | ||
if (!entry_ptr->prefetched) { | ||
assert(0 == entry_ptr->fd_parent_count); | ||
assert(NULL == entry_ptr->fd_parent_addrs); | ||
} /* end if */ | ||
|
||
/* Check whether we should free the space in the file that | ||
* the entry occupies | ||
*/ | ||
if (free_file_space) { | ||
hsize_t fsf_size; | ||
|
||
/* Sanity checks */ | ||
assert(H5_addr_defined(entry_ptr->addr)); | ||
assert(!H5F_IS_TMP_ADDR(f, entry_ptr->addr)); | ||
#ifndef NDEBUG | ||
{ | ||
size_t curr_len; | ||
|
||
/* Get the actual image size for the thing again */ | ||
entry_ptr->type->image_len((void *)entry_ptr, &curr_len); | ||
assert(curr_len == entry_ptr->size); | ||
} | ||
#endif | ||
|
||
/* If the file space free size callback is defined, use | ||
* it to get the size of the block of file space to free. | ||
* Otherwise use entry_ptr->size. | ||
*/ | ||
if (entry_ptr->type->fsf_size) { | ||
if ((entry_ptr->type->fsf_size)((void *)entry_ptr, &fsf_size) < 0) | ||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "unable to get file space free size"); | ||
} /* end if */ | ||
else /* no file space free size callback -- use entry size */ | ||
fsf_size = entry_ptr->size; | ||
|
||
/* Release the space on disk */ | ||
if (H5MF_xfree(f, entry_ptr->type->mem_type, entry_ptr->addr, fsf_size) < 0) | ||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "unable to free file space for cache entry"); | ||
} /* end if ( free_file_space ) */ | ||
|
||
/* Reset the pointer to the cache the entry is within. -QAK */ | ||
entry_ptr->cache_ptr = NULL; | ||
|
||
/* increment entries_removed_counter and set | ||
* last_entry_removed_ptr. As we are likely abuut to | ||
* free the entry, recall that last_entry_removed_ptr | ||
* must NEVER be dereferenced. | ||
* | ||
* Recall that these fields are maintained to allow functions | ||
* that perform scans of lists of entries to detect the | ||
* unexpected removal of entries (via expunge, eviction, | ||
* or take ownership at present), so that they can re-start | ||
* their scans if necessary. | ||
* | ||
* Also check if the entry we are watching for removal is being | ||
* removed (usually the 'next' entry for an iteration) and reset | ||
* it to indicate that it was removed. | ||
*/ | ||
cache_ptr->entries_removed_counter++; | ||
cache_ptr->last_entry_removed_ptr = entry_ptr; | ||
|
||
if (entry_ptr == cache_ptr->entry_watched_for_removal) | ||
cache_ptr->entry_watched_for_removal = NULL; | ||
|
||
/* Check for actually destroying the entry in memory */ | ||
/* (As opposed to taking ownership of it) */ | ||
if (destroy_entry) { | ||
if (entry_ptr->is_dirty) { | ||
/* Reset dirty flag */ | ||
entry_ptr->is_dirty = false; | ||
|
||
/* If the entry's type has a 'notify' callback send a | ||
* 'entry cleaned' notice now that the entry is fully | ||
* integrated into the cache. | ||
*/ | ||
if (entry_ptr->type->notify && | ||
(entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0) | ||
HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, | ||
"can't notify client about entry dirty flag cleared"); | ||
} /* end if */ | ||
|
||
/* verify that the image has been freed */ | ||
assert(entry_ptr->image_ptr == NULL); | ||
/* Make sure one of either `destroy_entry` or `take_ownership` are true */ | ||
assert(destroy_entry != take_ownership); | ||
|
||
if (entry_ptr->type->free_icr((void *)entry_ptr) < 0) | ||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "free_icr callback failed"); | ||
} /* end if */ | ||
else { | ||
assert(take_ownership); | ||
} /* end else */ | ||
} /* if (destroy) */ | ||
if (H5C__discard_single_entry(f, cache_ptr, entry_ptr, destroy_entry, free_file_space, | ||
suppress_image_entry_frees) < 0) | ||
HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "can't discard cache entry"); | ||
} | ||
|
||
/* Check if we have to update the page buffer with cleared entries | ||
* so it doesn't go out of date | ||
|
@@ -891,6 +789,145 @@ H5C__flush_single_entry(H5F_t *f, H5C_cache_entry_t *entry_ptr, unsigned flags) | |
FUNC_LEAVE_NOAPI(ret_value) | ||
} /* H5C__flush_single_entry() */ | ||
|
||
/*------------------------------------------------------------------------- | ||
* Function: H5C__discard_single_entry | ||
* | ||
* Purpose: Helper routine to discard a cache entry, freeing as much | ||
* of the relevant file space and data structures as possible | ||
* along the way. | ||
* | ||
* Return: FAIL if error is detected, SUCCEED otherwise. | ||
* | ||
*------------------------------------------------------------------------- | ||
*/ | ||
static herr_t | ||
H5C__discard_single_entry(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr, bool destroy_entry, | ||
bool free_file_space, bool suppress_image_entry_frees) | ||
{ | ||
herr_t ret_value = SUCCEED; | ||
|
||
FUNC_ENTER_PACKAGE | ||
|
||
assert(f); | ||
assert(cache_ptr); | ||
assert(entry_ptr); | ||
|
||
/* Sanity check */ | ||
assert(0 == entry_ptr->flush_dep_nparents); | ||
|
||
/* if both suppress_image_entry_frees and entry_ptr->include_in_image | ||
* are true, simply set entry_ptr->image_ptr to NULL, as we have | ||
* another pointer to the buffer in an instance of H5C_image_entry_t | ||
* in cache_ptr->image_entries. | ||
* | ||
* Otherwise, free the buffer if it exists. | ||
*/ | ||
if (suppress_image_entry_frees && entry_ptr->include_in_image) | ||
entry_ptr->image_ptr = NULL; | ||
else if (entry_ptr->image_ptr != NULL) | ||
entry_ptr->image_ptr = H5MM_xfree(entry_ptr->image_ptr); | ||
|
||
/* If the entry is not a prefetched entry, verify that the flush | ||
* dependency parents addresses array has been transferred. | ||
* | ||
* If the entry is prefetched, the free_icr routine will dispose of | ||
* the flush dependency parents addresses array if necessary. | ||
*/ | ||
if (!entry_ptr->prefetched) { | ||
assert(0 == entry_ptr->fd_parent_count); | ||
assert(NULL == entry_ptr->fd_parent_addrs); | ||
} /* end if */ | ||
|
||
/* Check whether we should free the space in the file that | ||
* the entry occupies | ||
*/ | ||
if (free_file_space) { | ||
hsize_t fsf_size; | ||
|
||
/* Sanity checks */ | ||
assert(H5_addr_defined(entry_ptr->addr)); | ||
assert(!H5F_IS_TMP_ADDR(f, entry_ptr->addr)); | ||
#ifndef NDEBUG | ||
{ | ||
size_t curr_len; | ||
|
||
/* Get the actual image size for the thing again */ | ||
entry_ptr->type->image_len((void *)entry_ptr, &curr_len); | ||
assert(curr_len == entry_ptr->size); | ||
} | ||
#endif | ||
|
||
/* If the file space free size callback is defined, use | ||
* it to get the size of the block of file space to free. | ||
* Otherwise use entry_ptr->size. | ||
*/ | ||
if (entry_ptr->type->fsf_size) { | ||
if ((entry_ptr->type->fsf_size)((void *)entry_ptr, &fsf_size) < 0) | ||
/* Note error but keep going */ | ||
HDONE_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "unable to get file space free size"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should make sure fsf_size is set to 0 if this fails, since it gets passed to H5MM_xfree. Either set it here or initialize it to 0. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or simply skip calling H5MM_xfree if fsf_size fails There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean the call to |
||
} /* end if */ | ||
else /* no file space free size callback -- use entry size */ | ||
fsf_size = entry_ptr->size; | ||
|
||
/* Release the space on disk */ | ||
if ((ret_value >= 0) && H5MF_xfree(f, entry_ptr->type->mem_type, entry_ptr->addr, fsf_size) < 0) | ||
/* Note error but keep going */ | ||
HDONE_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "unable to free file space for cache entry"); | ||
} /* end if ( free_file_space ) */ | ||
|
||
/* Reset the pointer to the cache the entry is within. -QAK */ | ||
entry_ptr->cache_ptr = NULL; | ||
|
||
/* increment entries_removed_counter and set | ||
* last_entry_removed_ptr. As we are likely about to | ||
* free the entry, recall that last_entry_removed_ptr | ||
* must NEVER be dereferenced. | ||
* | ||
* Recall that these fields are maintained to allow functions | ||
* that perform scans of lists of entries to detect the | ||
* unexpected removal of entries (via expunge, eviction, | ||
* or take ownership at present), so that they can re-start | ||
* their scans if necessary. | ||
* | ||
* Also check if the entry we are watching for removal is being | ||
* removed (usually the 'next' entry for an iteration) and reset | ||
* it to indicate that it was removed. | ||
*/ | ||
cache_ptr->entries_removed_counter++; | ||
cache_ptr->last_entry_removed_ptr = entry_ptr; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any chance cache_ptr->last_entry_removed_ptr is pointing to something else? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like to say no, but I didn't validate any of the comments here. |
||
|
||
if (entry_ptr == cache_ptr->entry_watched_for_removal) | ||
cache_ptr->entry_watched_for_removal = NULL; | ||
|
||
/* Check for actually destroying the entry in memory */ | ||
/* (As opposed to taking ownership of it) */ | ||
if (destroy_entry) { | ||
if (entry_ptr->is_dirty) { | ||
/* Reset dirty flag */ | ||
entry_ptr->is_dirty = false; | ||
|
||
/* If the entry's type has a 'notify' callback send a | ||
* 'entry cleaned' notice now that the entry is fully | ||
* integrated into the cache. | ||
*/ | ||
if (entry_ptr->type->notify && | ||
(entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0) | ||
/* Note error but keep going */ | ||
HDONE_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, | ||
"can't notify client about entry dirty flag cleared"); | ||
} /* end if */ | ||
|
||
/* verify that the image has been freed */ | ||
assert(entry_ptr->image_ptr == NULL); | ||
|
||
if (entry_ptr->type->free_icr((void *)entry_ptr) < 0) | ||
/* Note error but keep going */ | ||
HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "free_icr callback failed"); | ||
} /* end if */ | ||
|
||
FUNC_LEAVE_NOAPI(ret_value) | ||
} /* end H5C__discard_single_entry() */ | ||
|
||
/*------------------------------------------------------------------------- | ||
* Function: H5C__verify_len_eoa | ||
* | ||
|
Uh oh!
There was an error while loading. Please reload this page.