diff options
Diffstat (limited to 'src')
85 files changed, 13765 insertions, 8835 deletions
@@ -128,8 +128,7 @@ static herr_t H5AC__receive_haddr_list(MPI_Comm mpi_comm, int *num_entries_ptr, haddr_t **haddr_buf_ptr_ptr); static herr_t H5AC__receive_candidate_list(const H5AC_t *cache_ptr, int *num_entries_ptr, haddr_t **haddr_buf_ptr_ptr); -static herr_t H5AC__receive_and_apply_clean_list(H5F_t *f, hid_t primary_dxpl_id, - hid_t secondary_dxpl_id); +static herr_t H5AC__receive_and_apply_clean_list(H5F_t *f, hid_t dxpl_id); static herr_t H5AC__tidy_cache_0_lists(H5AC_t *cache_ptr, int num_candidates, haddr_t *candidates_list_ptr); static herr_t H5AC__rsp__dist_md_write__flush(H5F_t *f, hid_t dxpl_id); @@ -202,11 +201,11 @@ static const char * H5AC_entry_type_names[H5AC_NTYPES] = "extensible array super blocks", "extensible array data blocks", "extensible array data block pages", - "chunk proxy", "fixed array headers", "fixed array data block", "fixed array data block pages", "superblock", + "driver info", "test entry" /* for testing only -- not used for actual files */ }; @@ -593,7 +592,7 @@ H5AC_dest(H5F_t *f, hid_t dxpl_id) #endif /* H5_HAVE_PARALLEL */ /* Destroy the cache */ - if(H5C_dest(f, dxpl_id, H5AC_dxpl_id) < 0) + if(H5C_dest(f, dxpl_id) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "can't destroy cache") f->shared->cache = NULL; @@ -646,7 +645,7 @@ H5AC_evict(H5F_t *f, hid_t dxpl_id) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unable to get logging status") /* Evict all entries in the cache except the pinned superblock entry */ - if(H5C_evict(f, dxpl_id, H5AC_dxpl_id) < 0) + if(H5C_evict(f, dxpl_id) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "can't evict cache") done: @@ -693,8 +692,7 @@ H5AC_expunge_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, HDassert(f->shared); HDassert(f->shared->cache); HDassert(type); - HDassert(type->clear); - HDassert(type->dest); + HDassert(type->serialize); HDassert(H5F_addr_defined(addr)); /* Check if log messages are being emitted */ @@ -714,7 +712,7 @@ H5AC_expunge_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, } #endif /* H5AC__TRACE_FILE_ENABLED */ - if(H5C_expunge_entry(f, dxpl_id, H5AC_dxpl_id, type, addr, flags) < 0) + if(H5C_expunge_entry(f, dxpl_id, type, addr, flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "H5C_expunge_entry() failed.") done: @@ -792,7 +790,7 @@ H5AC_flush(H5F_t *f, hid_t dxpl_id) /* Flush the cache */ /* (Again, in parallel - writes out the superblock) */ - if(H5C_flush_cache(f, dxpl_id, H5AC_dxpl_id, H5AC__NO_FLAGS_SET) < 0) + if(H5C_flush_cache(f, dxpl_id, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush cache.") done: @@ -911,8 +909,7 @@ H5AC_insert_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t add HDassert(f->shared); HDassert(f->shared->cache); HDassert(type); - HDassert(type->flush); - HDassert(type->size); + HDassert(type->serialize); HDassert(H5F_addr_defined(addr)); HDassert(thing); @@ -951,7 +948,7 @@ H5AC_insert_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t add #endif /* H5AC_DO_TAGGING_SANITY_CHECKS */ /* Insert entry into metadata cache */ - if(H5C_insert_entry(f, dxpl_id, H5AC_dxpl_id, type, addr, thing, flags) < 0) + if(H5C_insert_entry(f, dxpl_id, type, addr, thing, flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5C_insert_entry() failed") #if H5AC__TRACE_FILE_ENABLED @@ -1318,7 +1315,7 @@ done: */ void * H5AC_protect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr, - void *udata, H5AC_protect_t rw) + void *udata, unsigned flags) { #if H5AC__TRACE_FILE_ENABLED char trace[128] = ""; @@ -1338,16 +1335,27 @@ H5AC_protect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr, HDassert(f->shared); HDassert(f->shared->cache); HDassert(type); - HDassert(type->flush); - HDassert(type->load); + HDassert(type->serialize); HDassert(H5F_addr_defined(addr)); /* Check if log messages are being emitted */ if(H5C_get_logging_status(f->shared->cache, &log_enabled, &curr_logging) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "unable to get logging status") + /* Check for unexpected flags -- H5C__FLUSH_COLLECTIVELY_FLAG + * only permitted in the parallel case. + */ +#ifdef H5_HAVE_PARALLEL + HDassert(0 == (flags & (unsigned)(~(H5C__READ_ONLY_FLAG | \ + H5C__FLUSH_LAST_FLAG | \ + H5C__FLUSH_COLLECTIVELY_FLAG)))); +#else /* H5_HAVE_PARALLEL */ + HDassert(0 == (flags & (unsigned)(~(H5C__READ_ONLY_FLAG | \ + H5C__FLUSH_LAST_FLAG)))); +#endif /* H5_HAVE_PARALLEL */ + /* Check for invalid access request */ - if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR) && rw == H5AC_WRITE) + if((0 == (H5F_INTENT(f) & H5F_ACC_RDWR)) && (0 == (flags & H5C__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "no write intent on file") /* FIXME: (temporary) @@ -1359,36 +1367,21 @@ H5AC_protect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr, HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "can't protect/write version 1 B-tree nodes under SWMR writes") #if H5AC__TRACE_FILE_ENABLED - /* For the protect call, only the addr and type id is really necessary - * in the trace file. Include the size of the entry protected as a - * sanity check. Also indicate whether the call was successful to - * catch occult errors. + /* For the protect call, only the addr, size, type id, and flags are + * necessary in the trace file. Also indicate whether the call was + * successful to catch occult errors. */ - if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr(cache_ptr))) { - const char * rw_string; - - if (rw == H5AC_WRITE ) - rw_string = "H5AC_WRITE"; - else if (rw == H5AC_READ ) - rw_string = "H5AC_READ"; - else - rw_string = "???"; - - sprintf(trace, "%s 0x%lx %d %s", FUNC, (unsigned long)addr, - (int)(type->id), rw_string); - } + if(NULL != (trace_file_ptr = H5C_get_trace_file_ptr(cache_ptr))) + sprintf(trace, "%s 0x%lx %d 0x%x", FUNC, (unsigned long)addr, + (int)(type->id), flags); #endif /* H5AC__TRACE_FILE_ENABLED */ - if ( rw == H5AC_READ ) - protect_flags |= H5C__READ_ONLY_FLAG; - #if H5AC_DO_TAGGING_SANITY_CHECKS if (!f->shared->cache->ignore_tags && (H5AC_verify_tag(dxpl_id, type) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, NULL, "Bad tag value") #endif /* H5AC_DO_TAGGING_SANITY_CHECKS */ - if(NULL == (thing = H5C_protect(f, dxpl_id, H5AC_dxpl_id, type, addr, udata, protect_flags))) - + if(NULL == (thing = H5C_protect(f, dxpl_id, type, addr, udata, flags))) HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C_protect() failed.") #if H5AC__TRACE_FILE_ENABLED @@ -1411,7 +1404,7 @@ done: herr_t fake_ret_value = (NULL == ret_value) ? FAIL : SUCCEED; if(H5AC__write_protect_entry_log_msg(f->shared->cache, (H5AC_info_t *)thing, - rw, fake_ret_value) < 0) + flags, fake_ret_value) < 0) HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "unable to emit log message") } @@ -1694,8 +1687,8 @@ H5AC_unprotect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr, HDassert(f->shared); HDassert(f->shared->cache); HDassert(type); - HDassert(type->clear); - HDassert(type->flush); + HDassert(type->deserialize); + HDassert(type->image_len); HDassert(H5F_addr_defined(addr)); HDassert(thing); HDassert( ((H5AC_info_t *)thing)->addr == addr ); @@ -1722,9 +1715,11 @@ H5AC_unprotect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr, * the entry. */ if(dirtied && !deleted) { + hbool_t curr_compressed = FALSE; /* dummy for call */ size_t curr_size = 0; + size_t curr_compressed_size = 0; /* dummy for call */ - if((type->size)(f, thing, &curr_size) < 0) + if((type->image_len)(thing, &curr_size, &curr_compressed, &curr_compressed_size) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTGETSIZE, FAIL, "Can't get size of thing") if(((H5AC_info_t *)thing)->size != curr_size) @@ -1743,7 +1738,7 @@ H5AC_unprotect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr, } /* end if */ #endif /* H5_HAVE_PARALLEL */ - if(H5C_unprotect(f, dxpl_id, H5AC_dxpl_id, type, addr, thing, flags) < 0) + if(H5C_unprotect(f, dxpl_id, type, addr, thing, flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "H5C_unprotect() failed.") #ifdef H5_HAVE_PARALLEL @@ -3699,7 +3694,7 @@ H5AC__propagate_and_apply_candidate_list(H5F_t *f, hid_t dxpl_id) aux_ptr->write_permitted = TRUE; /* Apply the candidate list */ - result = H5C_apply_candidate_list(f, dxpl_id, dxpl_id, cache_ptr, num_candidates, + result = H5C_apply_candidate_list(f, dxpl_id, cache_ptr, num_candidates, candidates_list_ptr, aux_ptr->mpi_rank, aux_ptr->mpi_size); /* Disable writes again */ @@ -3843,7 +3838,7 @@ H5AC__propagate_flushed_and_still_clean_entries_list(H5F_t *f, hid_t dxpl_id) HDassert(H5SL_count(aux_ptr->c_slist_ptr) == 0); } /* end if */ else { - if(H5AC__receive_and_apply_clean_list(f, dxpl_id, H5AC_dxpl_id) < 0) + if(H5AC__receive_and_apply_clean_list(f, dxpl_id) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't receive and/or process clean slist broadcast.") } /* end else */ @@ -3947,7 +3942,7 @@ done: */ #ifdef H5_HAVE_PARALLEL static herr_t -H5AC__receive_and_apply_clean_list(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id) +H5AC__receive_and_apply_clean_list(H5F_t *f, hid_t dxpl_id) { H5AC_t * cache_ptr; H5AC_aux_t * aux_ptr; @@ -3973,7 +3968,7 @@ H5AC__receive_and_apply_clean_list(H5F_t *f, hid_t primary_dxpl_id, hid_t second if(num_entries > 0) /* mark the indicated entries as clean */ - if(H5C_mark_entries_as_clean(f, primary_dxpl_id, secondary_dxpl_id, (int32_t)num_entries, haddr_buf_ptr) < 0) + if(H5C_mark_entries_as_clean(f, dxpl_id, (int32_t)num_entries, haddr_buf_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't mark entries clean.") /* if it is defined, call the sync point done callback. Note @@ -4140,7 +4135,7 @@ H5AC__rsp__dist_md_write__flush(H5F_t *f, hid_t dxpl_id) aux_ptr->write_permitted = TRUE; /* Apply the candidate list */ - result = H5C_apply_candidate_list(f, dxpl_id, dxpl_id, cache_ptr, num_entries, + result = H5C_apply_candidate_list(f, dxpl_id, cache_ptr, num_entries, haddr_buf_ptr, aux_ptr->mpi_rank, aux_ptr->mpi_size); /* Disable writes again */ @@ -4353,7 +4348,7 @@ H5AC__rsp__p0_only__flush(H5F_t *f, hid_t dxpl_id) aux_ptr->write_permitted = TRUE; /* Flush the cache */ - result = H5C_flush_cache(f, dxpl_id, dxpl_id, H5AC__NO_FLAGS_SET); + result = H5C_flush_cache(f, dxpl_id, H5AC__NO_FLAGS_SET); /* Disable writes again */ aux_ptr->write_permitted = FALSE; @@ -4477,7 +4472,7 @@ H5AC__rsp__p0_only__flush_to_min_clean(H5F_t *f, hid_t dxpl_id) aux_ptr->write_permitted = TRUE; /* Flush the cache */ - result = H5C_flush_to_min_clean(f, dxpl_id, H5AC_dxpl_id); + result = H5C_flush_to_min_clean(f, dxpl_id); /* Disable writes again */ aux_ptr->write_permitted = FALSE; @@ -4905,7 +4900,7 @@ H5AC_flush_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id) HDassert(f->shared); /* Call cache level function to flush metadata entries with specified tag */ - if(H5C_flush_tagged_entries(f, dxpl_id, H5AC_dxpl_id, metadata_tag)<0) + if(H5C_flush_tagged_entries(f, dxpl_id, metadata_tag)<0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot flush metadata") done: @@ -4941,7 +4936,7 @@ H5AC_evict_tagged_metadata(H5F_t * f, haddr_t metadata_tag, hid_t dxpl_id) HDassert(f->shared); /* Call cache level function to evict metadata entries with specified tag */ - if(H5C_evict_tagged_entries(f, dxpl_id, H5AC_dxpl_id, metadata_tag)<0) + if(H5C_evict_tagged_entries(f, dxpl_id, metadata_tag)<0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict metadata") done: @@ -5032,11 +5027,11 @@ H5AC_verify_tag(hid_t dxpl_id, const H5AC_class_t * type) * constraints are met. */ /* Superblock */ - if(type->id == H5AC_SUPERBLOCK_ID) { + if(type->id == H5AC_SUPERBLOCK_ID || type->id == H5AC_DRVRINFO_ID) { if(tag.value != H5AC__SUPERBLOCK_TAG) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "superblock not tagged with H5AC__SUPERBLOCK_TAG") + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "superblock/driver-info not tagged with H5AC__SUPERBLOCK_TAG") if(tag.globality != H5C_GLOBALITY_MAJOR) - HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "superblock globality not marked with H5C_GLOBALITY_MAJOR") + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "superblock/driver-info globality not marked with H5C_GLOBALITY_MAJOR") } else { if(tag.value == H5AC__SUPERBLOCK_TAG) diff --git a/src/H5AClog.c b/src/H5AClog.c index 1461738..fc96f9a 100644 --- a/src/H5AClog.c +++ b/src/H5AClog.c @@ -596,7 +596,7 @@ done: herr_t H5AC__write_protect_entry_log_msg(const H5AC_t *cache, const H5AC_info_t *entry, - H5AC_protect_t rw, + unsigned flags, herr_t fxn_ret_value) { char msg[MSG_SIZE]; @@ -610,12 +610,10 @@ H5AC__write_protect_entry_log_msg(const H5AC_t *cache, HDassert(cache->magic == H5C__H5C_T_MAGIC); HDassert(entry); - if(H5AC_READ == rw) + if(H5AC__READ_ONLY_FLAG == flags) HDstrcpy(rw_s, "READ"); - else if(H5AC_WRITE == rw) + else HDstrcpy(rw_s, "WRITE"); - else - HDstrcpy(rw_s, "UNKNOWN"); /* Create the log message string */ HDsnprintf(msg, MSG_SIZE, diff --git a/src/H5ACpkg.h b/src/H5ACpkg.h index e1c2693..3afce99 100644 --- a/src/H5ACpkg.h +++ b/src/H5ACpkg.h @@ -391,6 +391,12 @@ typedef struct H5AC_aux_t haddr_t * written_entries_tbl); } H5AC_aux_t; /* struct H5AC_aux_t */ +/* Package scoped functions */ +H5_DLL herr_t H5AC_set_sync_point_done_callback(H5C_t *cache_ptr, + void (*sync_point_done)(int num_writes, haddr_t *written_entries_tbl)); +H5_DLL herr_t H5AC_set_write_done_callback(H5C_t * cache_ptr, + void (* write_done)(void)); + #endif /* H5_HAVE_PARALLEL */ /******************************/ @@ -431,7 +437,7 @@ H5_DLL herr_t H5AC__write_create_fd_log_msg(const H5AC_t *cache, herr_t fxn_ret_value); H5_DLL herr_t H5AC__write_protect_entry_log_msg(const H5AC_t *cache, const H5AC_info_t *entry, - H5AC_protect_t rw, + unsigned flags, herr_t fxn_ret_value); H5_DLL herr_t H5AC__write_resize_entry_log_msg(const H5AC_t *cache, const H5AC_info_t *entry, diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h index 81f0dad..18794a0 100644 --- a/src/H5ACprivate.h +++ b/src/H5ACprivate.h @@ -76,11 +76,11 @@ typedef enum { H5AC_EARRAY_SBLOCK_ID, /* (20) extensible array super block */ H5AC_EARRAY_DBLOCK_ID, /* (21) extensible array data block */ H5AC_EARRAY_DBLK_PAGE_ID, /* (22) extensible array data block page */ - H5AC_CHUNK_PROXY_ID, /* (23) chunk proxy */ - H5AC_FARRAY_HDR_ID, /* (24) fixed array header */ - H5AC_FARRAY_DBLOCK_ID, /* (25) fixed array data block */ - H5AC_FARRAY_DBLK_PAGE_ID, /* (26) fixed array data block page */ - H5AC_SUPERBLOCK_ID, /* (27) file superblock */ + H5AC_FARRAY_HDR_ID, /* (23) fixed array header */ + H5AC_FARRAY_DBLOCK_ID, /* (24) fixed array data block */ + H5AC_FARRAY_DBLK_PAGE_ID, /* (25) fixed array data block page */ + H5AC_SUPERBLOCK_ID, /* (26) file superblock */ + H5AC_DRVRINFO_ID, /* (27) driver info block (supplements superblock)*/ H5AC_TEST_ID, /* (28) test entry -- not used for actual files */ H5AC_NTYPES /* Number of types, must be last */ } H5AC_type_t; @@ -93,6 +93,17 @@ typedef enum { * times for debugging purposes. * * Hence the following, somewhat odd set of #defines. + * + * NOTE: test/cache plays games with the f->shared->cache, and thus + * setting H5AC_DUMP_STATS_ON_CLOSE will generate constant, + * irrelevant data when run with that test program. See + * comments on setup_cache() / takedown_cache() in test/cache_common.c. + * for details. + * + * If you need to dump stats at file close in test/cache.c, + * use the dump_stats parameter to takedown_cache(), or call + * H5C_stats() directly. + * JRM -- 4/12/15 */ #if H5C_COLLECT_CACHE_STATS @@ -121,33 +132,12 @@ typedef enum { /* * Class methods pertaining to caching. Each type of cached object will * have a constant variable with permanent life-span that describes how - * to cache the object. That variable will be of type H5AC_class_t and - * have the following required fields... - * - * LOAD: Loads an object from disk to memory. The function - * should allocate some data structure and return it. - * - * FLUSH: Writes some data structure back to disk. It would be - * wise for the data structure to include dirty flags to - * indicate whether it really needs to be written. This - * function is also responsible for freeing memory allocated - * by the LOAD method if the DEST argument is non-zero (by - * calling the DEST method). - * - * DEST: Just frees memory allocated by the LOAD method. - * - * CLEAR: Just marks object as non-dirty. - * - * NOTIFY: Notify client that an action on an entry has taken/will take - * place - * - * SIZE: Report the size (on disk) of the specified cache object. - * Note that the space allocated on disk may not be contiguous. + * to cache the object. */ -#define H5AC_CALLBACK__NO_FLAGS_SET H5C_CALLBACK__NO_FLAGS_SET -#define H5AC_CALLBACK__SIZE_CHANGED_FLAG H5C_CALLBACK__SIZE_CHANGED_FLAG -#define H5AC_CALLBACK__MOVED_FLAG H5C_CALLBACK__MOVED_FLAG +#define H5AC__SERIALIZE_RESIZED_FLAG H5C__SERIALIZE_RESIZED_FLAG +#define H5AC__SERIALIZE_MOVED_FLAG H5C__SERIALIZE_MOVED_FLAG +#define H5AC__SERIALIZE_COMPRESSED_FLAG H5C__SERIALIZE_COMPRESSED_FLAG /* Cork actions: cork/uncork/get cork status of an object */ @@ -158,50 +148,40 @@ typedef enum { /* Aliases for 'notify action' type & values */ typedef H5C_notify_action_t H5AC_notify_action_t; #define H5AC_NOTIFY_ACTION_AFTER_INSERT H5C_NOTIFY_ACTION_AFTER_INSERT +#define H5AC_NOTIFY_ACTION_AFTER_LOAD H5C_NOTIFY_ACTION_AFTER_LOAD +#define H5AC_NOTIFY_ACTION_AFTER_FLUSH H5C_NOTIFY_ACTION_AFTER_FLUSH #define H5AC_NOTIFY_ACTION_BEFORE_EVICT H5C_NOTIFY_ACTION_BEFORE_EVICT -typedef H5C_load_func_t H5AC_load_func_t; -typedef H5C_flush_func_t H5AC_flush_func_t; -typedef H5C_dest_func_t H5AC_dest_func_t; -typedef H5C_clear_func_t H5AC_clear_func_t; -typedef H5C_notify_func_t H5AC_notify_func_t; -typedef H5C_size_func_t H5AC_size_func_t; +#define H5AC__CLASS_NO_FLAGS_SET H5C__CLASS_NO_FLAGS_SET +#define H5AC__CLASS_SPECULATIVE_LOAD_FLAG H5C__CLASS_SPECULATIVE_LOAD_FLAG +#define H5AC__CLASS_COMPRESSED_FLAG H5C__CLASS_COMPRESSED_FLAG -typedef H5C_class_t H5AC_class_t; +/* The following flags should only appear in test code */ +/* The H5AC__CLASS_SKIP_READS & H5AC__CLASS_SKIP_WRITES flags are used in H5Oproxy.c */ +#define H5AC__CLASS_NO_IO_FLAG H5C__CLASS_NO_IO_FLAG +#define H5AC__CLASS_SKIP_READS H5C__CLASS_SKIP_READS +#define H5AC__CLASS_SKIP_WRITES H5C__CLASS_SKIP_WRITES +typedef H5C_get_load_size_func_t H5AC_get_load_size_func_t; +typedef H5C_verify_chksum_func_t H5AC_verify_chksum_func_t; +typedef H5C_deserialize_func_t H5AC_deserialize_func_t; +typedef H5C_image_len_func_t H5AC_image_len_func_t; -/* The H5AC_NSLOTS #define is now obsolete, as the metadata cache no longer - * uses slots. However I am leaving it in for now to avoid modifying the - * interface between the metadata cache and the rest of HDF. It should - * be removed when we get to dealing with the size_hint parameter in - * H5AC_create(). - * JRM - 5/20/04 - * - * Old comment on H5AC_NSLOTS follows: - * - * A cache has a certain number of entries. Objects are mapped into a - * cache entry by hashing the object's file address. Each file has its - * own cache, an array of slots. - */ -#define H5AC_NSLOTS 10330 /* The library "likes" this number... */ - - -typedef H5C_cache_entry_t H5AC_info_t; +#define H5AC__SERIALIZE_NO_FLAGS_SET H5C__SERIALIZE_NO_FLAGS_SET +#define H5AC__SERIALIZE_RESIZED_FLAG H5C__SERIALIZE_RESIZED_FLAG +#define H5AC__SERIALIZE_MOVED_FLAG H5C__SERIALIZE_MOVED_FLAG +typedef H5C_pre_serialize_func_t H5AC_pre_serialize_func_t; +typedef H5C_serialize_func_t H5AC_serialize_func_t; +typedef H5C_notify_func_t H5AC_notify_func_t; +typedef H5C_free_icr_func_t H5AC_free_icr_func_t; +typedef H5C_clear_func_t H5AC_clear_func_t; +typedef H5C_get_fsf_size_t H5AC_get_fsf_size_t; -/*===----------------------------------------------------------------------=== - * Protect Types - *===----------------------------------------------------------------------=== - * - * These are for the wrapper functions to H5AC_protect. They specify what - * type of operation you're planning on doing to the metadata. The - * Flexible Parallel HDF5 locking can then act accordingly. - */ +typedef H5C_class_t H5AC_class_t; -typedef enum H5AC_protect_t { - H5AC_WRITE, /* Protect object for writing */ - H5AC_READ /* Protect object for reading */ -} H5AC_protect_t; +/* Cache entry info */ +typedef H5C_cache_entry_t H5AC_info_t; /* Typedef for metadata cache (defined in H5Cpkg.h) */ @@ -327,6 +307,7 @@ H5_DLLVAR hid_t H5AC_ind_dxpl_id; #define H5AC__FLUSH_CLEAR_ONLY_FLAG H5C__FLUSH_CLEAR_ONLY_FLAG #define H5AC__FLUSH_MARKED_ENTRIES_FLAG H5C__FLUSH_MARKED_ENTRIES_FLAG #define H5AC__FLUSH_IGNORE_PROTECTED_FLAG H5C__FLUSH_IGNORE_PROTECTED_FLAG +#define H5AC__READ_ONLY_FLAG H5C__READ_ONLY_FLAG #define H5AC__FREE_FILE_SPACE_FLAG H5C__FREE_FILE_SPACE_FLAG #define H5AC__TAKE_OWNERSHIP_FLAG H5C__TAKE_OWNERSHIP_FLAG #define H5AC__FLUSH_LAST_FLAG H5C__FLUSH_LAST_FLAG @@ -358,7 +339,7 @@ H5_DLL herr_t H5AC_insert_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *typ H5_DLL herr_t H5AC_pin_protected_entry(void *thing); H5_DLL herr_t H5AC_create_flush_dependency(void *parent_thing, void *child_thing); H5_DLL void * H5AC_protect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, - haddr_t addr, void *udata, H5AC_protect_t rw); + haddr_t addr, void *udata, unsigned flags); H5_DLL herr_t H5AC_resize_entry(void *thing, size_t new_size); H5_DLL herr_t H5AC_unpin_entry(void *thing); H5_DLL herr_t H5AC_destroy_flush_dependency(void *parent_thing, void *child_thing); @@ -372,10 +353,6 @@ H5_DLL herr_t H5AC_dest(H5F_t *f, hid_t dxpl_id); H5_DLL herr_t H5AC_evict(H5F_t *f, hid_t dxpl_id); H5_DLL herr_t H5AC_expunge_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr, unsigned flags); -H5_DLL herr_t H5AC_set_sync_point_done_callback(H5C_t *cache_ptr, - void (*sync_point_done)(int num_writes, haddr_t *written_entries_tbl)); -H5_DLL herr_t H5AC_set_write_done_callback(H5C_t * cache_ptr, - void (* write_done)(void)); H5_DLL herr_t H5AC_get_cache_auto_resize_config(const H5AC_t * cache_ptr, H5AC_cache_config_t *config_ptr); H5_DLL herr_t H5AC_get_cache_size(H5AC_t *cache_ptr, size_t *max_size_ptr, @@ -335,7 +335,7 @@ H5B_find(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void *u cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; - if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ))) + if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node") rt = bt->nchildren; @@ -485,7 +485,7 @@ H5B__split(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, unsigned idx, cache_udata.type = shared->type; cache_udata.parent = bt_ud->bt->parent; cache_udata.rc_shared = bt_ud->bt->rc_shared; - if(NULL == (split_bt_ud->bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, split_bt_ud->addr, &cache_udata, H5AC_WRITE))) + if(NULL == (split_bt_ud->bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, split_bt_ud->addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree") split_bt_ud->bt->level = bt_ud->bt->level; @@ -518,7 +518,7 @@ H5B__split(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, unsigned idx, if(H5F_addr_defined(bt_ud->bt->right)) { H5B_t *tmp_bt; - if(NULL == (tmp_bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt_ud->bt->right, &cache_udata, H5AC_WRITE))) + if(NULL == (tmp_bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt_ud->bt->right, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load right sibling") tmp_bt->left = split_bt_ud->addr; @@ -598,7 +598,7 @@ H5B_insert(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void cache_udata.type = type; cache_udata.rc_shared = rc_shared; bt_ud.addr = addr; - if(NULL == (bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_WRITE))) + if(NULL == (bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to locate root of B-tree") /* Insert the object */ @@ -910,7 +910,7 @@ H5B__insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, * Follow the minimum branch out of this node to a subtree. */ child_bt_ud.addr = bt->child[idx]; - if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC_WRITE))) + if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node") if((int)(my_ins = H5B__insert_helper(f, dxpl_id, &child_bt_ud, type, @@ -956,7 +956,7 @@ H5B__insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, */ idx = bt->nchildren - 1; child_bt_ud.addr = bt->child[idx]; - if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC_WRITE))) + if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node") if((int)(my_ins = H5B__insert_helper(f, dxpl_id, &child_bt_ud, type, @@ -1011,7 +1011,7 @@ H5B__insert_helper(H5F_t *f, hid_t dxpl_id, H5B_ins_ud_t *bt_ud, */ HDassert(idx < bt->nchildren); child_bt_ud.addr = bt->child[idx]; - if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC_WRITE))) + if(NULL == (child_bt_ud.bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, child_bt_ud.addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node") if((int)(my_ins = H5B__insert_helper(f, dxpl_id, &child_bt_ud, type, @@ -1177,7 +1177,7 @@ H5B__iterate_helper(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t ad cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; - if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ))) + if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load B-tree node") /* Iterate over node's children */ @@ -1299,7 +1299,7 @@ H5B__remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *typ cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; - if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_WRITE))) + if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load B-tree node") rt = bt->nchildren; @@ -1399,7 +1399,7 @@ H5B__remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *typ * "critical" for any child in its node to maintain this * consistency (and avoid breaking key/child consistency) */ if(H5F_addr_defined(bt->left)) { - if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->left, &cache_udata, H5AC_WRITE))) + if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->left, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load node from tree") /* Copy right-most key from deleted node to right-most key @@ -1416,7 +1416,7 @@ H5B__remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *typ sibling = NULL; /* Make certain future references will be caught */ } /* end if */ if(H5F_addr_defined(bt->right)) { - if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->right, &cache_udata, H5AC_WRITE))) + if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->right, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to unlink node from tree") /* Copy left-most key from deleted node to left-most key in @@ -1536,7 +1536,7 @@ H5B__remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *typ HDassert(level > 0); /* Update the rightmost key in the left sibling */ - if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->left, &cache_udata, H5AC_WRITE))) + if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->left, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to protect node") HDmemcpy(H5B_NKEY(sibling, shared, sibling->nchildren), @@ -1551,7 +1551,7 @@ H5B__remove_helper(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *typ HDassert(level > 0); /* Update the lefttmost key in the right sibling */ - if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->right, &cache_udata, H5AC_WRITE))) + if(NULL == (sibling = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, bt->right, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to protect node") HDmemcpy(H5B_NKEY(sibling, shared, 0), @@ -1659,7 +1659,7 @@ H5B_delete(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, void cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; - if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_WRITE))) + if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node") /* Iterate over all children in tree, deleting them */ @@ -1921,7 +1921,7 @@ H5B__get_info_helper(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t a cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; - if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ))) + if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node") /* Cache information from this node */ @@ -1945,7 +1945,7 @@ H5B__get_info_helper(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t a while(H5F_addr_defined(next_addr)) { /* Protect the next node to the right */ addr = next_addr; - if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ))) + if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "B-tree node") /* Cache information from this node */ @@ -2074,7 +2074,7 @@ H5B_valid(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr, cache_udata.type = type; cache_udata.parent = parent; cache_udata.rc_shared = rc_shared; - if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ))) + if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree node") done: @@ -161,8 +161,9 @@ H5B2_create(H5F_t *f, hid_t dxpl_id, const H5B2_create_t *cparam, /* Look up the B-tree header */ cache_udata.f = f; cache_udata.parent = parent; + cache_udata.addr = hdr_addr; cache_udata.ctx_udata = ctx_udata; - if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, hdr_addr, &cache_udata, H5AC_WRITE))) + if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, hdr_addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to load B-tree header") /* Point v2 B-tree wrapper at header and bump it's ref count */ @@ -222,8 +223,9 @@ H5B2_open(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *ctx_udata, void *parent) /* Look up the B-tree header */ cache_udata.f = f; cache_udata.parent = parent; + cache_udata.addr = addr; cache_udata.ctx_udata = ctx_udata; - if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, &cache_udata, H5AC_READ))) + if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to load B-tree header") /* Check for pending heap deletion */ @@ -491,7 +493,7 @@ H5B2_find(H5B2_t *bt2, hid_t dxpl_id, void *udata, H5B2_found_t op, H5B2_node_ptr_t next_node_ptr; /* Node pointer info for next node */ /* Lock B-tree current node */ - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, depth, H5AC_READ))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, depth, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node") /* Unpin parent if necessary */ @@ -565,7 +567,7 @@ H5B2_find(H5B2_t *bt2, hid_t dxpl_id, void *udata, H5B2_found_t op, H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */ /* Lock B-tree leaf node */ - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, H5AC_READ))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Unpin parent if necessary */ @@ -703,7 +705,7 @@ H5B2_index(H5B2_t *bt2, hid_t dxpl_id, H5_iter_order_t order, hsize_t idx, unsigned u; /* Local index variable */ /* Lock B-tree current node */ - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, depth, H5AC_READ))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, depth, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node") /* Unpin parent if necessary */ @@ -790,7 +792,7 @@ H5B2_index(H5B2_t *bt2, hid_t dxpl_id, H5_iter_order_t order, hsize_t idx, H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */ /* Lock B-tree leaf node */ - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, H5AC_READ))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Unpin parent if necessary */ @@ -1152,7 +1154,7 @@ H5B2_modify(H5B2_t *bt2, hid_t dxpl_id, void *udata, H5B2_modify_t op, H5B2_node_ptr_t next_node_ptr; /* Node pointer info for next node */ /* Lock B-tree current node */ - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, depth, H5AC_WRITE))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, depth, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node") /* Unpin parent if necessary */ @@ -1235,7 +1237,7 @@ H5B2_modify(H5B2_t *bt2, hid_t dxpl_id, void *udata, H5B2_modify_t op, hbool_t changed = FALSE;/* Whether the 'modify' callback changed the record */ /* Lock B-tree leaf node */ - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, H5AC_WRITE))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Unpin parent if necessary */ @@ -1382,7 +1384,7 @@ H5B2_close(H5B2_t *bt2, hid_t dxpl_id) /* Lock the v2 B-tree header into memory */ /* (OK to pass in NULL for callback context, since we know the header must be in the cache) */ - if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(bt2->f, dxpl_id, H5AC_BT2_HDR, bt2_addr, NULL, H5AC_WRITE))) + if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(bt2->f, dxpl_id, H5AC_BT2_HDR, bt2_addr, NULL, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect v2 B-tree header") /* Set the shared v2 B-tree header's file context for this operation */ @@ -1459,8 +1461,9 @@ HDfprintf(stderr, "%s: addr = %a\n", FUNC, addr); #endif /* QAK */ cache_udata.f = f; cache_udata.parent = parent; + cache_udata.addr = addr; cache_udata.ctx_udata = ctx_udata; - if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, &cache_udata, H5AC_WRITE))) + if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect v2 B-tree header") /* Remember the callback & context for later */ diff --git a/src/H5B2cache.c b/src/H5B2cache.c index 8e5554a..87daebb 100644 --- a/src/H5B2cache.c +++ b/src/H5B2cache.c @@ -37,7 +37,6 @@ #include "H5private.h" /* Generic Functions */ #include "H5B2pkg.h" /* v2 B-trees */ #include "H5Eprivate.h" /* Error handling */ -#include "H5MFprivate.h" /* File memory management */ #include "H5WBprivate.h" /* Wrapped Buffers */ @@ -50,9 +49,6 @@ #define H5B2_INT_VERSION 0 /* Internal node */ #define H5B2_LEAF_VERSION 0 /* Leaf node */ -/* Size of stack buffer for serialized headers */ -#define H5B2_HDR_BUF_SIZE 128 - /******************/ /* Local Typedefs */ @@ -69,25 +65,44 @@ /********************/ /* Metadata cache callbacks */ -static H5B2_hdr_t *H5B2__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5B2__cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_hdr_t *hdr, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5B2__cache_hdr_dest(H5F_t *f, H5B2_hdr_t *hdr); -static herr_t H5B2__cache_hdr_clear(H5F_t *f, H5B2_hdr_t *hdr, hbool_t destroy); -static herr_t H5B2__cache_hdr_notify(H5AC_notify_action_t action, H5B2_hdr_t *hdr); -static herr_t H5B2__cache_hdr_size(const H5F_t *f, const H5B2_hdr_t *hdr, size_t *size_ptr); -static H5B2_internal_t *H5B2__cache_internal_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5B2__cache_internal_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_internal_t *i, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5B2__cache_internal_dest(H5F_t *f, H5B2_internal_t *internal); -static herr_t H5B2__cache_internal_clear(H5F_t *f, H5B2_internal_t *i, hbool_t destroy); -static herr_t H5B2__cache_internal_notify(H5AC_notify_action_t action, H5B2_internal_t *internal); -static herr_t H5B2__cache_internal_size(const H5F_t *f, const H5B2_internal_t *i, size_t *size_ptr); -static H5B2_leaf_t *H5B2__cache_leaf_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5B2__cache_leaf_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_leaf_t *l, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5B2__cache_leaf_dest(H5F_t *f, H5B2_leaf_t *leaf); -static herr_t H5B2__cache_leaf_clear(H5F_t *f, H5B2_leaf_t *l, hbool_t destroy); -static herr_t H5B2__cache_leaf_notify(H5AC_notify_action_t action, H5B2_leaf_t *leaf); -static herr_t H5B2__cache_leaf_size(const H5F_t *f, const H5B2_leaf_t *l, size_t *size_ptr); - +static herr_t H5B2__cache_hdr_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5B2__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata); +static void *H5B2__cache_hdr_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5B2__cache_hdr_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5B2__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5B2__cache_hdr_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5B2__cache_hdr_free_icr(void *thing); + +static herr_t H5B2__cache_int_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5B2__cache_int_verify_chksum(const void *image_ptr, size_t len, void *udata); +static void *H5B2__cache_int_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5B2__cache_int_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5B2__cache_int_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5B2__cache_int_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5B2__cache_int_free_icr(void *thing); + +static herr_t H5B2__cache_leaf_get_load_size(const void * mage_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5B2__cache_leaf_verify_chksum(const void *image_ptr, size_t len, void *udata); +static void *H5B2__cache_leaf_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5B2__cache_leaf_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5B2__cache_leaf_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5B2__cache_leaf_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5B2__cache_leaf_free_icr(void *thing); /*********************/ /* Package Variables */ @@ -95,35 +110,56 @@ static herr_t H5B2__cache_leaf_size(const H5F_t *f, const H5B2_leaf_t *l, size_t /* H5B2 inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_BT2_HDR[1] = {{ - H5AC_BT2_HDR_ID, - (H5AC_load_func_t)H5B2__cache_hdr_load, - (H5AC_flush_func_t)H5B2__cache_hdr_flush, - (H5AC_dest_func_t)H5B2__cache_hdr_dest, - (H5AC_clear_func_t)H5B2__cache_hdr_clear, - (H5AC_notify_func_t)H5B2__cache_hdr_notify, - (H5AC_size_func_t)H5B2__cache_hdr_size, + H5AC_BT2_HDR_ID, /* Metadata client ID */ + "v2 B-tree header", /* Metadata client name (for debugging) */ + H5FD_MEM_BTREE, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5B2__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5B2__cache_hdr_verify_chksum, + H5B2__cache_hdr_deserialize, /* 'deserialize' callback */ + H5B2__cache_hdr_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5B2__cache_hdr_serialize, /* 'serialize' callback */ + H5B2__cache_hdr_notify, /* 'notify' callback */ + H5B2__cache_hdr_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* H5B2 inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_BT2_INT[1] = {{ - H5AC_BT2_INT_ID, - (H5AC_load_func_t)H5B2__cache_internal_load, - (H5AC_flush_func_t)H5B2__cache_internal_flush, - (H5AC_dest_func_t)H5B2__cache_internal_dest, - (H5AC_clear_func_t)H5B2__cache_internal_clear, - (H5AC_notify_func_t)H5B2__cache_internal_notify, - (H5AC_size_func_t)H5B2__cache_internal_size, + H5AC_BT2_INT_ID, /* Metadata client ID */ + "v2 B-tree internal node", /* Metadata client name (for debugging) */ + H5FD_MEM_BTREE, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5B2__cache_int_get_load_size, /* 'get_load_size' callback */ + H5B2__cache_int_verify_chksum, /* 'verify_chksum' callback */ + H5B2__cache_int_deserialize, /* 'deserialize' callback */ + H5B2__cache_int_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5B2__cache_int_serialize, /* 'serialize' callback */ + H5B2__cache_int_notify, /* 'notify' callback */ + H5B2__cache_int_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* H5B2 inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_BT2_LEAF[1] = {{ - H5AC_BT2_LEAF_ID, - (H5AC_load_func_t)H5B2__cache_leaf_load, - (H5AC_flush_func_t)H5B2__cache_leaf_flush, - (H5AC_dest_func_t)H5B2__cache_leaf_dest, - (H5AC_clear_func_t)H5B2__cache_leaf_clear, - (H5AC_notify_func_t)H5B2__cache_leaf_notify, - (H5AC_size_func_t)H5B2__cache_leaf_size, + H5AC_BT2_LEAF_ID, /* Metadata client ID */ + "v2 B-tree leaf node", /* Metadata client name (for debugging) */ + H5FD_MEM_BTREE, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5B2__cache_leaf_get_load_size, /* 'get_load_size' callback */ + H5B2__cache_leaf_verify_chksum, /* 'verify_chksum' callback */ + H5B2__cache_leaf_deserialize, /* 'deserialize' callback */ + H5B2__cache_leaf_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5B2__cache_leaf_serialize, /* 'serialize' callback */ + H5B2__cache_leaf_notify, /* 'notify' callback */ + H5B2__cache_leaf_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -139,7 +175,82 @@ const H5AC_class_t H5AC_BT2_LEAF[1] = {{ /*------------------------------------------------------------------------- - * Function: H5B2__cache_hdr_load + * Function: H5B2__cache_hdr_get_load_size + * + * Purpose: Compute the size of the data structure on disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * May 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5B2__cache_hdr_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata; /* User data for callback */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(udata); + HDassert(udata->f); + HDassert(image_len); + + if(image == NULL) { + /* Set the image length size */ + *image_len = H5B2_HEADER_SIZE_FILE(udata->f); + } else { + HDassert(actual_len); + HDassert(*actual_len == *actual_len); + } + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5B2__cache_hdr_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_hdr_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5B2__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5B2__cache_hdr_verify_chksum() */ + + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_hdr_deserialize * * Purpose: Loads a B-tree header from the disk. * @@ -152,82 +263,68 @@ const H5AC_class_t H5AC_BT2_LEAF[1] = {{ * *------------------------------------------------------------------------- */ -static H5B2_hdr_t * -H5B2__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5B2__cache_hdr_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, + void *_udata, hbool_t H5_ATTR_UNUSED *dirty) { H5B2_hdr_t *hdr = NULL; /* B-tree header */ H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata; H5B2_create_t cparam; /* B-tree creation parameters */ H5B2_subid_t id; /* ID of B-tree class, as found in file */ uint16_t depth; /* Depth of B-tree */ - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5B2_HDR_BUF_SIZE]; /* Buffer for header */ - uint8_t *buf; /* Pointer to header buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ H5B2_hdr_t *ret_value; /* Return value */ FUNC_ENTER_STATIC /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(image); HDassert(udata); /* Allocate new B-tree header and reset cache info */ if(NULL == (hdr = H5B2__hdr_alloc(udata->f))) HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "allocation failed for B-tree header") - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, NULL, "can't wrap buffer") - - /* Get a pointer to a buffer that's large enough for header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, hdr->hdr_size))) - HGOTO_ERROR(H5E_BTREE, H5E_NOSPACE, NULL, "can't get actual buffer") - - /* Read and validate header from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_BTREE, H5AC_BT2_HDR_ID, addr, hdr->hdr_size, hdr->hdr_size, buf) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "incorrect metadata checksum for v2 B-tree header") - - /* Get temporary pointer to serialized header */ - p = buf; - /* Magic number */ - if(HDmemcmp(p, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree header signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5B2_HDR_VERSION) + if(*image++ != H5B2_HDR_VERSION) HGOTO_ERROR(H5E_BTREE, H5E_BADRANGE, NULL, "wrong B-tree header version") /* B-tree class */ - id = (H5B2_subid_t)*p++; + id = (H5B2_subid_t)*image++; if(id >= H5B2_NUM_BTREE_ID) HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type") /* Node size (in bytes) */ - UINT32DECODE(p, cparam.node_size); + UINT32DECODE(image, cparam.node_size); /* Raw key size (in bytes) */ - UINT16DECODE(p, cparam.rrec_size); + UINT16DECODE(image, cparam.rrec_size); /* Depth of tree */ - UINT16DECODE(p, depth); + UINT16DECODE(image, depth); /* Split & merge %s */ - cparam.split_percent = *p++; - cparam.merge_percent = *p++; + cparam.split_percent = *image++; + cparam.merge_percent = *image++; /* Root node pointer */ - H5F_addr_decode(udata->f, (const uint8_t **)&p, &(hdr->root.addr)); - UINT16DECODE(p, hdr->root.node_nrec); - H5F_DECODE_LENGTH(udata->f, p, hdr->root.all_nrec); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &(hdr->root.addr)); + UINT16DECODE(image, hdr->root.node_nrec); + H5F_DECODE_LENGTH(udata->f, image, hdr->root.all_nrec); + + /* checksum verification already done in verify_chksum cb */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - (const uint8_t *)buf) == (hdr->hdr_size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == hdr->hdr_size); /* Initialize B-tree header info */ cparam.cls = H5B2_client_class_g[id]; @@ -235,152 +332,59 @@ H5B2__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, NULL, "can't initialize B-tree header info") /* Set the B-tree header's address */ - hdr->addr = addr; + hdr->addr = udata->addr; + + /* Sanity check */ + HDassert((size_t)(image - (const uint8_t *)_image) <= len); /* Set return value */ ret_value = hdr; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_BTREE, H5E_CLOSEERROR, NULL, "can't close wrapped buffer") if(!ret_value && hdr) if(H5B2__hdr_free(hdr) < 0) HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, NULL, "can't release v2 B-tree header") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B2__cache_hdr_load() */ /*lint !e818 Can't make udata a pointer to const */ +} /* end H5B2__cache_hdr_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5B2__cache_hdr_flush + * Function: H5B2__cache_hdr_image_len * - * Purpose: Flushes a dirty B-tree header to disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 1 2005 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * May 20, 2010 * *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5B2_hdr_t *hdr, unsigned H5_ATTR_UNUSED * flags_ptr) +H5B2__cache_hdr_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5B2_HDR_BUF_SIZE]; /* Buffer for header */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5B2_hdr_t *hdr = (const H5B2_hdr_t *)_thing; /* Pointer to the B-tree header */ - FUNC_ENTER_STATIC + FUNC_ENTER_STATIC_NOERR /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); HDassert(hdr); + HDassert(image_len); - if(hdr->cache_info.is_dirty) { - uint8_t *buf; /* Pointer to header buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - - /* Set the B-tree header's file context for this operation */ - hdr->f = f; - - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't wrap buffer") - - /* Get a pointer to a buffer that's large enough for header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, hdr->hdr_size))) - HGOTO_ERROR(H5E_BTREE, H5E_NOSPACE, FAIL, "can't get actual buffer") - - /* Get temporary pointer to serialized header */ - p = buf; - - /* Magic number */ - HDmemcpy(p, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5B2_HDR_VERSION; - - /* B-tree type */ - *p++ = hdr->cls->id; - - /* Node size (in bytes) */ - UINT32ENCODE(p, hdr->node_size); - - /* Raw key size (in bytes) */ - UINT16ENCODE(p, hdr->rrec_size); - - /* Depth of tree */ - UINT16ENCODE(p, hdr->depth); - - /* Split & merge %s */ - H5_CHECK_OVERFLOW(hdr->split_percent, /* From: */ unsigned, /* To: */ uint8_t); - *p++ = (uint8_t)hdr->split_percent; - H5_CHECK_OVERFLOW(hdr->merge_percent, /* From: */ unsigned, /* To: */ uint8_t); - *p++ = (uint8_t)hdr->merge_percent; - - /* Root node pointer */ - H5F_addr_encode(f, &p, hdr->root.addr); - UINT16ENCODE(p, hdr->root.node_nrec); - H5F_ENCODE_LENGTH(f, p, hdr->root.all_nrec); - - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (hdr->hdr_size - H5B2_SIZEOF_CHKSUM), 0); - - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); + /* Set the image length size */ + *image_len = hdr->hdr_size; - /* Write the B-tree header. */ - HDassert((size_t)(p - buf) == hdr->hdr_size); - if(H5F_block_write(f, H5FD_MEM_BTREE, addr, hdr->hdr_size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFLUSH, FAIL, "unable to save B-tree header to disk") - - hdr->cache_info.is_dirty = FALSE; - - /* Clear shadowed node lists, as the header has been flushed and all - * nodes must be shadowed again (if doing SWMR writes). Note that this - * algorithm does one extra iteration at the end, as the last node's - * shadowed_next pointer points to itself. */ - while(hdr->shadowed_internal) { - H5B2_internal_t *next = hdr->shadowed_internal->shadowed_next; - - HDassert(!hdr->shadowed_internal->cache_info.is_dirty); - hdr->shadowed_internal->shadowed_next = NULL; - hdr->shadowed_internal->shadowed_prev = NULL; - hdr->shadowed_internal = next; - } /* end while */ - while(hdr->shadowed_leaf) { - H5B2_leaf_t *next = hdr->shadowed_leaf->shadowed_next; - - HDassert(!hdr->shadowed_leaf->cache_info.is_dirty); - hdr->shadowed_leaf->shadowed_next = NULL; - hdr->shadowed_leaf->shadowed_prev = NULL; - hdr->shadowed_leaf = next; - } /* end while */ - } /* end if */ - - if(destroy) - if(H5B2__cache_hdr_dest(f, hdr) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree header") - -done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_BTREE, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") - - FUNC_LEAVE_NOAPI(ret_value) -} /* H5B2__cache_hdr_flush() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5B2__cache_hdr_image_len() */ /*------------------------------------------------------------------------- - * Function: H5B2__cache_hdr_dest + * Function: H5B2__cache_hdr_serialize * - * Purpose: Destroys a B-tree header in memory. + * Purpose: Flushes a dirty B-tree header to disk. * * Return: Non-negative on success/Negative on failure * @@ -391,71 +395,82 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_hdr_dest(H5F_t *f, H5B2_hdr_t *hdr) +H5B2__cache_hdr_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5B2_hdr_t *hdr = (H5B2_hdr_t *)_thing; /* Pointer to the B-tree header */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ - FUNC_ENTER_STATIC + FUNC_ENTER_STATIC_NOERR - /* Check arguments */ + /* check arguments */ + HDassert(f); + HDassert(image); HDassert(hdr); - HDassert(hdr->rc == 0); - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!hdr->cache_info.free_file_space_on_destroy || H5F_addr_defined(hdr->cache_info.addr)); + /* Magic number */ + HDmemcpy(image, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Check for freeing file space for B-tree header */ - if(hdr->cache_info.free_file_space_on_destroy) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_BTREE, H5AC_dxpl_id, hdr->cache_info.addr, (hsize_t)hdr->hdr_size) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free v2 B-tree header") - } /* end if */ + /* Version # */ + *image++ = H5B2_HDR_VERSION; - /* Release B-tree header info */ - if(H5B2__hdr_free(hdr) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free v2 B-tree header info") + /* B-tree type */ + *image++ = hdr->cls->id; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B2__cache_hdr_dest() */ + /* Node size (in bytes) */ + UINT32ENCODE(image, hdr->node_size); - -/*------------------------------------------------------------------------- - * Function: H5B2__cache_hdr_clear - * - * Purpose: Mark a B-tree header in memory as non-dirty. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 1 2005 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5B2__cache_hdr_clear(H5F_t *f, H5B2_hdr_t *hdr, hbool_t destroy) -{ - herr_t ret_value = SUCCEED; /* Return value */ + /* Raw key size (in bytes) */ + UINT16ENCODE(image, hdr->rrec_size); - FUNC_ENTER_STATIC + /* Depth of tree */ + UINT16ENCODE(image, hdr->depth); - /* - * Check arguments. - */ - HDassert(hdr); + /* Split & merge %s */ + H5_CHECK_OVERFLOW(hdr->split_percent, /* From: */ unsigned, /* To: */ uint8_t); + *image++ = (uint8_t)hdr->split_percent; + H5_CHECK_OVERFLOW(hdr->merge_percent, /* From: */ unsigned, /* To: */ uint8_t); + *image++ = (uint8_t)hdr->merge_percent; - /* Reset the dirty flag. */ - hdr->cache_info.is_dirty = FALSE; + /* Root node pointer */ + H5F_addr_encode(f, &image, hdr->root.addr); + UINT16ENCODE(image, hdr->root.node_nrec); + H5F_ENCODE_LENGTH(f, image, hdr->root.all_nrec); - if(destroy) - if(H5B2__cache_hdr_dest(f, hdr) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree header") + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (hdr->hdr_size - H5B2_SIZEOF_CHKSUM), 0); -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B2__cache_hdr_clear() */ + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= len); + + /* Clear shadowed node lists, as the header has been flushed and all + * nodes must be shadowed again (if doing SWMR writes). Note that this + * algorithm does one extra iteration at the end, as the last node's + * shadowed_next pointer points to itself. */ + while(hdr->shadowed_internal) { + H5B2_internal_t *next = hdr->shadowed_internal->shadowed_next; + + HDassert(!hdr->shadowed_internal->cache_info.is_dirty); + hdr->shadowed_internal->shadowed_next = NULL; + hdr->shadowed_internal->shadowed_prev = NULL; + hdr->shadowed_internal = next; + } /* end while */ + while(hdr->shadowed_leaf) { + H5B2_leaf_t *next = hdr->shadowed_leaf->shadowed_next; + + HDassert(!hdr->shadowed_leaf->cache_info.is_dirty); + hdr->shadowed_leaf->shadowed_next = NULL; + hdr->shadowed_leaf->shadowed_prev = NULL; + hdr->shadowed_leaf = next; + } /* end while */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5B2__cache_hdr_serialize() */ /*------------------------------------------------------------------------- @@ -472,9 +487,10 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_hdr_notify(H5AC_notify_action_t action, H5B2_hdr_t *hdr) +H5B2__cache_hdr_notify(H5AC_notify_action_t action, void *_thing) { - herr_t ret_value = SUCCEED; + H5B2_hdr_t *hdr = (H5B2_hdr_t *)_thing; + herr_t ret_value = SUCCEED; FUNC_ENTER_STATIC @@ -488,14 +504,21 @@ H5B2__cache_hdr_notify(H5AC_notify_action_t action, H5B2_hdr_t *hdr) HDassert(hdr->parent); switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: /* Create flush dependency on parent */ if(H5B2__create_flush_depend((H5AC_info_t *)hdr->parent, (H5AC_info_t *)hdr) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency") break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ - break; + /* Destroy flush dependency on parent */ + if(H5B2__destroy_flush_depend((H5AC_info_t *)hdr->parent, (H5AC_info_t *)hdr) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency") + break; default: #ifdef NDEBUG @@ -512,41 +535,122 @@ done: /*------------------------------------------------------------------------- - * Function: H5B2__cache_hdr_size + * Function: H5B2__cache_hdr_free_icr + * + * Purpose: Destroy/release an "in core representation" of a data + * structure + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Mike McGreevy + * mcgreevy@hdfgroup.org + * June 18, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5B2__cache_hdr_free_icr(void *thing) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Check arguments */ + HDassert(thing); + + /* Destroy v2 B-tree header */ + if(H5B2__hdr_free((H5B2_hdr_t *)thing) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free v2 B-tree header") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5B2__cache_hdr_free_icr() */ + + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_int_get_load_size * - * Purpose: Compute the size in bytes of a B-tree header - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Compute the size of the data structure on disk. * - * Return: SUCCEED (Can't fail) + * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@hdfgroup.org - * Feb 1 2005 + * May 18, 2010 * *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_hdr_size(const H5F_t H5_ATTR_UNUSED *f, const H5B2_hdr_t *hdr, size_t *size_ptr) +H5B2__cache_int_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* User data for callback */ + + FUNC_ENTER_STATIC_NOERR /* Check arguments */ - HDassert(f); - HDassert(hdr); - HDassert(size_ptr); + HDassert(udata); + HDassert(udata->hdr); + HDassert(image_len); - /* Set size value */ - *size_ptr = hdr->hdr_size; + if(image == NULL) { + /* Set the image length size */ + *image_len = udata->hdr->node_size; + } else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5B2__cache_hdr_size() */ +} /* end H5B2__cache_int_get_load_size() */ + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_int_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5B2__cache_int_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */ + size_t chk_size; /* Exact size of the node with checksum at the end */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + HDassert(udata); + + /* Internal node prefix header + records + child pointer triplets: size with checksum at the end */ + chk_size = H5B2_INT_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size) + ((size_t)(udata->nrec + 1) * H5B2_INT_POINTER_SIZE(udata->hdr, udata->depth)); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5B2__cache_int_verify_chksum() */ /*------------------------------------------------------------------------- - * Function: H5B2__cache_internal_load + * Function: H5B2__cache_int_deserialize * - * Purpose: Loads a B-tree internal node from the disk. + * Purpose: Deserialize a B-tree internal node from the disk. * * Return: Success: Pointer to a new B-tree internal node. * Failure: NULL @@ -557,23 +661,23 @@ H5B2__cache_hdr_size(const H5F_t H5_ATTR_UNUSED *f, const H5B2_hdr_t *hdr, size_ * *------------------------------------------------------------------------- */ -static H5B2_internal_t * -H5B2__cache_internal_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5B2__cache_int_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, + void *_udata, hbool_t H5_ATTR_UNUSED *dirty) { H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */ H5B2_internal_t *internal = NULL; /* Internal node read */ - const uint8_t *p; /* Pointer into raw data buffer */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint8_t *native; /* Pointer to native record info */ H5B2_node_ptr_t *int_node_ptr; /* Pointer to node pointer info */ + uint32_t stored_chksum; /* Stored metadata checksum value */ unsigned u; /* Local index variable */ - size_t chk_size; /* Exact size of the node with checksum at the end */ H5B2_internal_t *ret_value; /* Return value */ FUNC_ENTER_STATIC /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(image); HDassert(udata); /* Allocate new internal node and reset cache info */ @@ -581,9 +685,6 @@ H5B2__cache_internal_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") HDmemset(&internal->cache_info, 0, sizeof(H5AC_info_t)); - /* Set the B-tree header's file context for this operation */ - udata->hdr->f = f; - /* Increment ref. count on B-tree header */ if(H5B2__hdr_incr(udata->hdr) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment ref. count on B-tree header") @@ -594,25 +695,17 @@ H5B2__cache_internal_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) internal->shadowed_next = NULL; internal->shadowed_prev = NULL; - /* Internal node prefix header + records + child pointer triplets: size with checksum at the end */ - chk_size = H5B2_INT_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size) + ((size_t)(udata->nrec + 1) * H5B2_INT_POINTER_SIZE(udata->hdr, udata->depth)); - /* Read and validate internal node from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_BTREE, H5AC_BT2_INT_ID, addr, (size_t)udata->hdr->node_size, chk_size, udata->hdr->page) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "incorrect metadata checksum for v2 internal node") - - p = udata->hdr->page; - /* Magic number */ - if(HDmemcmp(p, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC)) HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree internal node signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5B2_INT_VERSION) + if(*image++ != H5B2_INT_VERSION) HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, NULL, "wrong B-tree internal node version") /* B-tree type */ - if(*p++ != (uint8_t)udata->hdr->cls->id) + if(*image++ != (uint8_t)udata->hdr->cls->id) HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type") /* Allocate space for the native keys in memory */ @@ -631,11 +724,11 @@ H5B2__cache_internal_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) native = internal->int_native; for(u = 0; u < internal->nrec; u++) { /* Decode record */ - if((udata->hdr->cls->decode)(p, native, udata->hdr->cb_ctx) < 0) + if((udata->hdr->cls->decode)(image, native, udata->hdr->cb_ctx) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode B-tree record") /* Move to next record */ - p += udata->hdr->rrec_size; + image += udata->hdr->rrec_size; native += udata->hdr->cls->nrec_size; } /* end for */ @@ -643,10 +736,10 @@ H5B2__cache_internal_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) int_node_ptr = internal->node_ptrs; for(u = 0; u < (unsigned)(internal->nrec + 1); u++) { /* Decode node pointer */ - H5F_addr_decode(udata->f, (const uint8_t **)&p, &(int_node_ptr->addr)); - UINT64DECODE_VAR(p, int_node_ptr->node_nrec, udata->hdr->max_nrec_size); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &(int_node_ptr->addr)); + UINT64DECODE_VAR(image, int_node_ptr->node_nrec, udata->hdr->max_nrec_size); if(udata->depth > 1) - UINT64DECODE_VAR(p, int_node_ptr->all_nrec, udata->hdr->node_info[udata->depth - 1].cum_max_nrec_size) + UINT64DECODE_VAR(image, int_node_ptr->all_nrec, udata->hdr->node_info[udata->depth - 1].cum_max_nrec_size) else int_node_ptr->all_nrec = int_node_ptr->node_nrec; @@ -654,10 +747,13 @@ H5B2__cache_internal_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) int_node_ptr++; } /* end for */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check parsing */ - HDassert((size_t)(p - (const uint8_t *)udata->hdr->page) <= (udata->hdr->node_size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) <= len); /* Set return value */ ret_value = internal; @@ -668,214 +764,127 @@ done: HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree internal node") FUNC_LEAVE_NOAPI(ret_value) -} /* H5B2__cache_internal_load() */ /*lint !e818 Can't make udata a pointer to const */ +} /* H5B2__cache_int_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5B2__cache_internal_flush + * Function: H5B2__cache_int_image_len * - * Purpose: Flushes a dirty B-tree internal node to disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 3 2005 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * May 20, 2010 * *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_internal_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_internal_t *internal, unsigned H5_ATTR_UNUSED * flags_ptr) +H5B2__cache_int_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const H5B2_internal_t *internal = (const H5B2_internal_t *)_thing; /* Pointer to the B-tree internal node */ - FUNC_ENTER_STATIC + FUNC_ENTER_STATIC_NOERR /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); HDassert(internal); HDassert(internal->hdr); + HDassert(image_len); - if(internal->cache_info.is_dirty) { - uint8_t *p; /* Pointer into raw data buffer */ - uint8_t *native; /* Pointer to native record info */ - H5B2_node_ptr_t *int_node_ptr; /* Pointer to node pointer info */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - unsigned u; /* Local index variable */ - - /* Set the B-tree header's file context for this operation */ - internal->hdr->f = f; - - p = internal->hdr->page; - - /* Magic number */ - HDmemcpy(p, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5B2_INT_VERSION; - - /* B-tree type */ - *p++ = internal->hdr->cls->id; - HDassert((size_t)(p - internal->hdr->page) == (H5B2_INT_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM)); - - /* Serialize records for internal node */ - native = internal->int_native; - for(u = 0; u < internal->nrec; u++) { - /* Encode record */ - if((internal->hdr->cls->encode)(p, native, internal->hdr->cb_ctx) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record") - - /* Move to next record */ - p += internal->hdr->rrec_size; - native += internal->hdr->cls->nrec_size; - } /* end for */ - - /* Serialize node pointers for internal node */ - int_node_ptr = internal->node_ptrs; - for(u = 0; u < (unsigned)(internal->nrec + 1); u++) { - /* Encode node pointer */ - H5F_addr_encode(f, &p, int_node_ptr->addr); - UINT64ENCODE_VAR(p, int_node_ptr->node_nrec, internal->hdr->max_nrec_size); - if(internal->depth > 1) - UINT64ENCODE_VAR(p, int_node_ptr->all_nrec, internal->hdr->node_info[internal->depth - 1].cum_max_nrec_size); - - /* Move to next node pointer */ - int_node_ptr++; - } /* end for */ - - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(internal->hdr->page, (size_t)(p - internal->hdr->page), 0); - - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); - - /* Write the B-tree internal node */ - HDassert((size_t)(p - internal->hdr->page) <= internal->hdr->node_size); - if(H5F_block_write(f, H5FD_MEM_BTREE, addr, (size_t)internal->hdr->node_size, dxpl_id, internal->hdr->page) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFLUSH, FAIL, "unable to save B-tree internal node to disk") - - internal->cache_info.is_dirty = FALSE; - } /* end if */ - - if(destroy) - if(H5B2__cache_internal_dest(f, internal) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree internal node") + /* Set the image length size */ + *image_len = internal->hdr->node_size; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5B2__cache_internal_flush() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5B2__cache_int_image_len() */ /*------------------------------------------------------------------------- - * Function: H5B2__cache_internal_dest + * Function: H5B2__cache_int_serialize * - * Purpose: Destroys a B-tree internal node in memory. + * Purpose: Serializes a B-tree internal node for writing to disk. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu - * Feb 2 2005 + * Feb 3 2005 * *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_internal_dest(H5F_t *f, H5B2_internal_t *internal) +H5B2__cache_int_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5B2_internal_t *internal = (H5B2_internal_t *)_thing; /* Pointer to the B-tree internal node */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint8_t *native; /* Pointer to native record info */ + H5B2_node_ptr_t *int_node_ptr; /* Pointer to node pointer info */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC - /* Check arguments */ + /* check arguments */ HDassert(f); + HDassert(image); HDassert(internal); HDassert(internal->hdr); - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!internal->cache_info.free_file_space_on_destroy || H5F_addr_defined(internal->cache_info.addr)); - - /* Unlink from shadowed list */ - if(internal->shadowed_next) { - if(internal->shadowed_next != internal) { - internal->shadowed_next->shadowed_prev = internal->shadowed_prev; - - if(internal->shadowed_prev) - internal->shadowed_prev->shadowed_next = internal->shadowed_next; - else { - HDassert(internal->hdr->shadowed_internal = internal); - - internal->hdr->shadowed_internal = internal->shadowed_next; - } /* end else */ - } /* end if */ - else { - if(internal->shadowed_prev) - internal->shadowed_prev->shadowed_next = internal->shadowed_prev; - else { - HDassert(internal->hdr->shadowed_internal = internal); + /* Magic number */ + HDmemcpy(image, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - internal->hdr->shadowed_internal = NULL; - } /* end else */ - } /* end else */ - } /* end if */ + /* Version # */ + *image++ = H5B2_INT_VERSION; - /* Check for freeing file space for B-tree internal node */ - if(internal->cache_info.free_file_space_on_destroy) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_BTREE, H5AC_dxpl_id, internal->cache_info.addr, (hsize_t)internal->hdr->node_size) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free v2 B-tree internal node") - } /* end if */ + /* B-tree type */ + *image++ = internal->hdr->cls->id; + HDassert((size_t)(image - (uint8_t *)_image) == (H5B2_INT_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM)); - /* Release v2 b-tree internal node */ - if(H5B2__internal_free(internal) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release v2 B-tree internal node") + /* Serialize records for internal node */ + native = internal->int_native; + for(u = 0; u < internal->nrec; u++) { + /* Encode record */ + if((internal->hdr->cls->encode)(image, native, internal->hdr->cb_ctx) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record") -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B2__cache_internal_dest() */ + /* Move to next record */ + image += internal->hdr->rrec_size; + native += internal->hdr->cls->nrec_size; + } /* end for */ - -/*------------------------------------------------------------------------- - * Function: H5B2__cache_internal_clear - * - * Purpose: Mark a B-tree internal node in memory as non-dirty. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 2 2005 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5B2__cache_internal_clear(H5F_t *f, H5B2_internal_t *internal, hbool_t destroy) -{ - herr_t ret_value = SUCCEED; + /* Serialize node pointers for internal node */ + int_node_ptr = internal->node_ptrs; + for(u = 0; u < (unsigned)(internal->nrec + 1); u++) { + /* Encode node pointer */ + H5F_addr_encode(f, &image, int_node_ptr->addr); + UINT64ENCODE_VAR(image, int_node_ptr->node_nrec, internal->hdr->max_nrec_size); + if(internal->depth > 1) + UINT64ENCODE_VAR(image, int_node_ptr->all_nrec, internal->hdr->node_info[internal->depth - 1].cum_max_nrec_size); - FUNC_ENTER_STATIC + /* Move to next node pointer */ + int_node_ptr++; + } /* end for */ - /* - * Check arguments. - */ - HDassert(internal); + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); - /* Reset the dirty flag. */ - internal->cache_info.is_dirty = FALSE; + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); - if(destroy) - if(H5B2__cache_internal_dest(f, internal) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree internal node") + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= len); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B2__cache_internal_clear() */ +} /* H5B2__cache_int_serialize() */ /*------------------------------------------------------------------------- - * Function: H5B2__cache_internal_notify + * Function: H5B2__cache_int_notify * * Purpose: Handle cache action notifications * @@ -888,9 +897,10 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_internal_notify(H5AC_notify_action_t action, H5B2_internal_t *internal) +H5B2__cache_int_notify(H5AC_notify_action_t action, void *_thing) { - herr_t ret_value = SUCCEED; + H5B2_internal_t *internal = (H5B2_internal_t *)_thing; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NOINIT @@ -904,13 +914,21 @@ H5B2__cache_internal_notify(H5AC_notify_action_t action, H5B2_internal_t *intern HDassert(internal->parent); switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: /* Create flush dependency on parent */ if(H5B2__create_flush_depend((H5AC_info_t *)internal->parent, (H5AC_info_t *)internal) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency") break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ + /* Destroy flush dependency on parent */ + if(H5B2__destroy_flush_depend((H5AC_info_t *)internal->parent, (H5AC_info_t *)internal) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency") + break; default: @@ -924,45 +942,153 @@ H5B2__cache_internal_notify(H5AC_notify_action_t action, H5B2_internal_t *intern done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B2__cache_internal_notify() */ +} /* end H5B2__cache_int_notify() */ /*------------------------------------------------------------------------- - * Function: H5B2__cache_internal_size + * Function: H5B2__cache_int_free_icr * - * Purpose: Compute the size in bytes of a B-tree internal node - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Destroy/release an "in core representation" of a data + * structure * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 2 2005 + * Programmer: Mike McGreevy + * mcgreevy@hdfgroup.org + * June 18, 2008 * *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_internal_size(const H5F_t H5_ATTR_UNUSED *f, const H5B2_internal_t *internal, size_t *size_ptr) +H5B2__cache_int_free_icr(void *_thing) { - FUNC_ENTER_STATIC_NOERR + H5B2_internal_t *internal = (H5B2_internal_t *)_thing; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC /* Check arguments */ HDassert(internal); HDassert(internal->hdr); - HDassert(size_ptr); - /* Set size value */ - *size_ptr = internal->hdr->node_size; + /* Unlink from shadowed list */ + if(internal->shadowed_next) { + if(internal->shadowed_next != internal) { + internal->shadowed_next->shadowed_prev = internal->shadowed_prev; + + if(internal->shadowed_prev) + internal->shadowed_prev->shadowed_next = internal->shadowed_next; + else { + HDassert(internal->hdr->shadowed_internal = internal); + + internal->hdr->shadowed_internal = internal->shadowed_next; + } /* end else */ + } /* end if */ + else { + if(internal->shadowed_prev) + internal->shadowed_prev->shadowed_next = internal->shadowed_prev; + else { + HDassert(internal->hdr->shadowed_internal = internal); + + internal->hdr->shadowed_internal = NULL; + } /* end else */ + } /* end else */ + } /* end if */ + + /* Release v2 B-tree internal node */ + if(H5B2__internal_free(internal) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release v2 B-tree internal node") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5B2__cache_int_free_icr() */ + + + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_leaf_get_load_size + * + * Purpose: Compute the size of the data structure on disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * May 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5B2__cache_leaf_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata; /* User data for callback */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(udata); + HDassert(udata->hdr); + HDassert(image_len); + + if(image == NULL) { + /* Set the image length size */ + *image_len = udata->hdr->node_size; + } else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5B2__cache_internal_size() */ +} /* end H5B2__cache_leaf_get_load_size() */ + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_leaf_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5B2__cache_leaf_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */ + size_t chk_size; /* Exact size of the node with checksum at the end */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + HDassert(udata); + + /* Leaf node prefix header + records: size with checksum at the end */ + chk_size = H5B2_LEAF_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5B2__cache_leaf_verify_chksum() */ /*------------------------------------------------------------------------- - * Function: H5B2__cache_leaf_load + * Function: H5B2__cache_leaf_deserialize * - * Purpose: Loads a B-tree leaf from the disk. + * Purpose: Deserialize a B-tree leaf from the disk. * * Return: Success: Pointer to a new B-tree leaf node. * Failure: NULL @@ -973,22 +1099,22 @@ H5B2__cache_internal_size(const H5F_t H5_ATTR_UNUSED *f, const H5B2_internal_t * * *------------------------------------------------------------------------- */ -static H5B2_leaf_t * -H5B2__cache_leaf_load(H5F_t H5_ATTR_UNUSED *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5B2__cache_leaf_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, + void *_udata, hbool_t H5_ATTR_UNUSED *dirty) { H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata; H5B2_leaf_t *leaf = NULL; /* Pointer to lead node loaded */ - const uint8_t *p; /* Pointer into raw data buffer */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint8_t *native; /* Pointer to native keys */ + uint32_t stored_chksum; /* Stored metadata checksum value */ unsigned u; /* Local index variable */ - size_t chk_size; /* Exact size of the node with checksum at the end */ H5B2_leaf_t *ret_value; /* Return value */ FUNC_ENTER_STATIC /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(image); HDassert(udata); /* Allocate new leaf node and reset cache info */ @@ -996,9 +1122,6 @@ H5B2__cache_leaf_load(H5F_t H5_ATTR_UNUSED *f, hid_t dxpl_id, haddr_t addr, void HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed") HDmemset(&leaf->cache_info, 0, sizeof(H5AC_info_t)); - /* Set the B-tree header's file context for this operation */ - udata->hdr->f = udata->f; - /* Increment ref. count on B-tree header */ if(H5B2__hdr_incr(udata->hdr) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment ref. count on B-tree header") @@ -1009,26 +1132,17 @@ H5B2__cache_leaf_load(H5F_t H5_ATTR_UNUSED *f, hid_t dxpl_id, haddr_t addr, void leaf->shadowed_next = NULL; leaf->shadowed_prev = NULL; - /* Leaf node prefix header + records: size with checksum at the end */ - chk_size = H5B2_LEAF_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size); - - /* Read and validate leaf node from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_BTREE, H5AC_BT2_LEAF_ID, addr, (size_t)udata->hdr->node_size, chk_size, udata->hdr->page) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "incorrect metadata checksum for v2 leaf node") - - p = udata->hdr->page; - /* Magic number */ - if(HDmemcmp(p, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC)) HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree leaf node signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5B2_LEAF_VERSION) + if(*image++ != H5B2_LEAF_VERSION) HGOTO_ERROR(H5E_BTREE, H5E_BADRANGE, NULL, "wrong B-tree leaf node version") /* B-tree type */ - if(*p++ != (uint8_t)udata->hdr->cls->id) + if(*image++ != (uint8_t)udata->hdr->cls->id) HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type") /* Allocate space for the native keys in memory */ @@ -1042,18 +1156,24 @@ H5B2__cache_leaf_load(H5F_t H5_ATTR_UNUSED *f, hid_t dxpl_id, haddr_t addr, void native = leaf->leaf_native; for(u = 0; u < leaf->nrec; u++) { /* Decode record */ - if((udata->hdr->cls->decode)(p, native, udata->hdr->cb_ctx) < 0) + if((udata->hdr->cls->decode)(image, native, udata->hdr->cb_ctx) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, NULL, "unable to decode B-tree record") /* Move to next record */ - p += udata->hdr->rrec_size; + image += udata->hdr->rrec_size; native += udata->hdr->cls->nrec_size; } /* end for */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check parsing */ - HDassert((size_t)(p - (const uint8_t *)udata->hdr->page) <= (udata->hdr->node_size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) <= udata->hdr->node_size); + + /* Sanity check */ + HDassert((size_t)(image - (const uint8_t *)_image) <= len); /* Set return value */ ret_value = leaf; @@ -1064,96 +1184,46 @@ done: HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree leaf node") FUNC_LEAVE_NOAPI(ret_value) -} /* H5B2__cache_leaf_load() */ /*lint !e818 Can't make udata a pointer to const */ +} /* H5B2__cache_leaf_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5B2__cache_leaf_flush + * Function: H5B2__cache_leaf_image_len * - * Purpose: Flushes a dirty B-tree leaf node to disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 2 2005 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * May 20, 2010 * *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_leaf_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_leaf_t *leaf, unsigned H5_ATTR_UNUSED * flags_ptr) +H5B2__cache_leaf_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const H5B2_leaf_t *leaf = (const H5B2_leaf_t *)_thing; /* Pointer to the B-tree leaf node */ - FUNC_ENTER_STATIC + FUNC_ENTER_STATIC_NOERR /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); HDassert(leaf); HDassert(leaf->hdr); + HDassert(image_len); - if(leaf->cache_info.is_dirty) { - uint8_t *p; /* Pointer into raw data buffer */ - uint8_t *native; /* Pointer to native keys */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - unsigned u; /* Local index variable */ - - /* Set the B-tree header's file context for this operation */ - leaf->hdr->f = f; - - p = leaf->hdr->page; - - /* magic number */ - HDmemcpy(p, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* version # */ - *p++ = H5B2_LEAF_VERSION; - - /* b-tree type */ - *p++ = leaf->hdr->cls->id; - HDassert((size_t)(p - leaf->hdr->page) == (H5B2_LEAF_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM)); - - /* Serialize records for leaf node */ - native = leaf->leaf_native; - for(u = 0; u < leaf->nrec; u++) { - /* Encode record */ - if((leaf->hdr->cls->encode)(p, native, leaf->hdr->cb_ctx) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record") - - /* Move to next record */ - p += leaf->hdr->rrec_size; - native += leaf->hdr->cls->nrec_size; - } /* end for */ - - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(leaf->hdr->page, (size_t)(p - leaf->hdr->page), 0); + /* Set the image length size */ + *image_len = leaf->hdr->node_size; - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); - - /* Write the B-tree leaf node */ - HDassert((size_t)(p - leaf->hdr->page) <= leaf->hdr->node_size); - if(H5F_block_write(f, H5FD_MEM_BTREE, addr, (size_t)leaf->hdr->node_size, dxpl_id, leaf->hdr->page) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFLUSH, FAIL, "unable to save B-tree leaf node to disk") - - leaf->cache_info.is_dirty = FALSE; - } /* end if */ - - if(destroy) - if(H5B2__cache_leaf_dest(f, leaf) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree leaf node") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5B2__cache_leaf_flush() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5B2__cache_leaf_image_len() */ /*------------------------------------------------------------------------- - * Function: H5B2__cache_leaf_dest + * Function: H5B2__cache_leaf_serialize * - * Purpose: Destroys a B-tree leaf node in memory. + * Purpose: Serializes a B-tree leaf node for writing to disk. * * Return: Non-negative on success/Negative on failure * @@ -1164,96 +1234,59 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_leaf_dest(H5F_t *f, H5B2_leaf_t *leaf) +H5B2__cache_leaf_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing; /* Pointer to the B-tree leaf node */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint8_t *native; /* Pointer to native keys */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC - /* Check arguments */ + /* check arguments */ HDassert(f); + HDassert(image); HDassert(leaf); HDassert(leaf->hdr); - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!leaf->cache_info.free_file_space_on_destroy || H5F_addr_defined(leaf->cache_info.addr)); - - /* Unlink from shadowed list */ - if(leaf->shadowed_next) { - if(leaf->shadowed_next != leaf) { - leaf->shadowed_next->shadowed_prev = leaf->shadowed_prev; - - if(leaf->shadowed_prev) - leaf->shadowed_prev->shadowed_next = leaf->shadowed_next; - else { - HDassert(leaf->hdr->shadowed_leaf = leaf); - - leaf->hdr->shadowed_leaf = leaf->shadowed_next; - } /* end else */ - } /* end if */ - else { - if(leaf->shadowed_prev) - leaf->shadowed_prev->shadowed_next = leaf->shadowed_prev; - else { - HDassert(leaf->hdr->shadowed_leaf = leaf); - - leaf->hdr->shadowed_leaf = NULL; - } /* end else */ - } /* end else */ - } /* end if */ + /* magic number */ + HDmemcpy(image, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Check for freeing file space for B-tree leaf node */ - if(leaf->cache_info.free_file_space_on_destroy) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_BTREE, H5AC_dxpl_id, leaf->cache_info.addr, (hsize_t)leaf->hdr->node_size) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free v2 B-tree leaf node") - } /* end if */ + /* version # */ + *image++ = H5B2_LEAF_VERSION; - /* Destroy v2 b-tree leaf node */ - if(H5B2__leaf_free(leaf) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree leaf node") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B2__cache_leaf_dest() */ + /* B-tree type */ + *image++ = leaf->hdr->cls->id; + HDassert((size_t)(image - (uint8_t *)_image) == (H5B2_LEAF_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM)); - -/*------------------------------------------------------------------------- - * Function: H5B2__cache_leaf_clear - * - * Purpose: Mark a B-tree leaf node in memory as non-dirty. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 2 2005 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5B2__cache_leaf_clear(H5F_t *f, H5B2_leaf_t *leaf, hbool_t destroy) -{ - herr_t ret_value = SUCCEED; + /* Serialize records for leaf node */ + native = leaf->leaf_native; + for(u = 0; u < leaf->nrec; u++) { + /* Encode record */ + if((leaf->hdr->cls->encode)(image, native, leaf->hdr->cb_ctx) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record") - FUNC_ENTER_STATIC + /* Move to next record */ + image += leaf->hdr->rrec_size; + native += leaf->hdr->cls->nrec_size; + } /* end for */ - /* - * Check arguments. - */ - HDassert(leaf); + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)((const uint8_t *)image - (const uint8_t *)_image), 0); - /* Reset the dirty flag. */ - leaf->cache_info.is_dirty = FALSE; + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); - if(destroy) - if(H5B2__cache_leaf_dest(f, leaf) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree leaf node") + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= len); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B2__cache_leaf_clear() */ +} /* H5B2__cache_leaf_serialize() */ /*------------------------------------------------------------------------- @@ -1270,8 +1303,9 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_leaf_notify(H5AC_notify_action_t action, H5B2_leaf_t *leaf) +H5B2__cache_leaf_notify(H5AC_notify_action_t action, void *_thing) { + H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NOINIT @@ -1286,13 +1320,20 @@ H5B2__cache_leaf_notify(H5AC_notify_action_t action, H5B2_leaf_t *leaf) HDassert(leaf->parent); switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: /* Create flush dependency on parent */ if(H5B2__create_flush_depend((H5AC_info_t *)leaf->parent, (H5AC_info_t *)leaf) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency") break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ + /* Destroy flush dependency on parent */ + if(H5B2__destroy_flush_depend((H5AC_info_t *)leaf->parent, (H5AC_info_t *)leaf) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency") break; default: @@ -1310,33 +1351,60 @@ done: /*------------------------------------------------------------------------- - * Function: H5B2__cache_leaf_size + * Function: H5B2__cache_leaf_free_icr * - * Purpose: Compute the size in bytes of a B-tree leaf node - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Destroy/release an "in core representation" of a data + * structure * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 2 2005 + * Programmer: Mike McGreevy + * mcgreevy@hdfgroup.org + * June 18, 2008 * *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_leaf_size(const H5F_t H5_ATTR_UNUSED *f, const H5B2_leaf_t *leaf, size_t *size_ptr) +H5B2__cache_leaf_free_icr(void *_thing) { - FUNC_ENTER_STATIC_NOERR + H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing; + herr_t ret_value = SUCCEED; /* Return value */ - /* check arguments */ + FUNC_ENTER_STATIC + + /* Check arguments */ HDassert(leaf); HDassert(leaf->hdr); - HDassert(size_ptr); - /* Set size value */ - *size_ptr = leaf->hdr->node_size; + /* Unlink from shadowed list */ + if(leaf->shadowed_next) { + if(leaf->shadowed_next != leaf) { + leaf->shadowed_next->shadowed_prev = leaf->shadowed_prev; - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5B2__cache_leaf_size() */ + if(leaf->shadowed_prev) + leaf->shadowed_prev->shadowed_next = leaf->shadowed_next; + else { + HDassert(leaf->hdr->shadowed_leaf = leaf); + + leaf->hdr->shadowed_leaf = leaf->shadowed_next; + } /* end else */ + } /* end if */ + else { + if(leaf->shadowed_prev) + leaf->shadowed_prev->shadowed_next = leaf->shadowed_prev; + else { + HDassert(leaf->hdr->shadowed_leaf = leaf); + + leaf->hdr->shadowed_leaf = NULL; + } /* end else */ + } /* end else */ + } /* end if */ + + /* Destroy v2 B-tree leaf node */ + if(H5B2__leaf_free(leaf) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree leaf node") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5B2__cache_leaf_free_icr() */ diff --git a/src/H5B2dbg.c b/src/H5B2dbg.c index 19bd2cd..20c0a5f 100644 --- a/src/H5B2dbg.c +++ b/src/H5B2dbg.c @@ -123,9 +123,10 @@ H5B2__hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, * Load the B-tree header. */ cache_udata.f = f; + cache_udata.addr = addr; cache_udata.ctx_udata = dbg_ctx; cache_udata.parent = NULL; - if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, &cache_udata, H5AC_READ))) + if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, "unable to load B-tree header") /* Set file pointer for this B-tree operation */ @@ -242,9 +243,10 @@ H5B2__int_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, * Load the B-tree header. */ cache_udata.f = f; + cache_udata.addr = hdr_addr; cache_udata.ctx_udata = dbg_ctx; cache_udata.parent = NULL; - if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, hdr_addr, &cache_udata, H5AC_READ))) + if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, hdr_addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, "unable to load B-tree header") /* Set file pointer for this B-tree operation */ @@ -255,7 +257,7 @@ H5B2__int_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, */ H5_CHECK_OVERFLOW(nrec, unsigned, uint16_t); H5_CHECK_OVERFLOW(depth, unsigned, uint16_t); - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, addr, NULL, (uint16_t)nrec, (uint16_t)depth, H5AC_READ))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, addr, NULL, (uint16_t)nrec, (uint16_t)depth, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, FAIL, "unable to load B-tree internal node") /* Print opening message */ @@ -377,9 +379,10 @@ H5B2__leaf_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent * Load the B-tree header. */ cache_udata.f = f; + cache_udata.addr = hdr_addr; cache_udata.ctx_udata = dbg_ctx; cache_udata.parent = NULL; - if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, hdr_addr, &cache_udata, H5AC_READ))) + if(NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_BT2_HDR, hdr_addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree header") /* Set file pointer for this B-tree operation */ @@ -389,7 +392,7 @@ H5B2__leaf_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent * Load the B-tree leaf node */ H5_CHECK_OVERFLOW(nrec, unsigned, uint16_t); - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, addr, NULL, (uint16_t)nrec, H5AC_READ))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, addr, NULL, (uint16_t)nrec, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Print opening message */ diff --git a/src/H5B2int.c b/src/H5B2int.c index daf5003..7f53264 100644 --- a/src/H5B2int.c +++ b/src/H5B2int.c @@ -223,9 +223,9 @@ H5B2__split1(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, right_addr = internal->node_ptrs[idx + 1].addr; /* Protect both leaves */ - if(NULL == (left_int = H5B2__protect_internal(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (left_int = H5B2__protect_internal(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") - if(NULL == (right_int = H5B2__protect_internal(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (right_int = H5B2__protect_internal(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Shadow the left node if doing SWMR writes */ @@ -259,9 +259,9 @@ H5B2__split1(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, right_addr = internal->node_ptrs[idx + 1].addr; /* Protect both leaves */ - if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC_WRITE))) + if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") - if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, H5AC_WRITE))) + if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Shadow the left node if doing SWMR writes */ @@ -356,7 +356,7 @@ H5B2__split1(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *grandchild_int = NULL; /* Protect grandchild */ - if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, (depth - 2), H5AC_WRITE))) + if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, (depth - 2), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") grandchild_class = H5AC_BT2_INT; grandchild = grandchild_int; @@ -372,7 +372,7 @@ H5B2__split1(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *grandchild_leaf = NULL; /* Protect grandchild */ - if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, H5AC_WRITE))) + if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") grandchild_class = H5AC_BT2_LEAF; grandchild = grandchild_leaf; @@ -494,7 +494,7 @@ H5B2__split_root(H5B2_hdr_t *hdr, hid_t dxpl_id) HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to create new internal node") /* Protect new root node */ - if(NULL == (new_root = H5B2__protect_internal(hdr, dxpl_id, hdr->root.addr, hdr, hdr->root.node_nrec, hdr->depth, H5AC_WRITE))) + if(NULL == (new_root = H5B2__protect_internal(hdr, dxpl_id, hdr->root.addr, hdr, hdr->root.node_nrec, hdr->depth, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Set first node pointer in root node to old root node pointer info */ @@ -562,9 +562,9 @@ H5B2__redistribute2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, right_addr = internal->node_ptrs[idx + 1].addr; /* Lock left & right B-tree child nodes */ - if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") - if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Shadow both nodes if doing SWMR writes */ @@ -597,9 +597,9 @@ H5B2__redistribute2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, right_addr = internal->node_ptrs[idx + 1].addr; /* Lock left & right B-tree child nodes */ - if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC_WRITE))) + if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") - if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, H5AC_WRITE))) + if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Shadow both nodes if doing SWMR writes */ @@ -684,7 +684,7 @@ H5B2__redistribute2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *grandchild_int = NULL; /* Protect grandchild */ - if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, (depth - 2), H5AC_WRITE))) + if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, (depth - 2), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") grandchild_class = H5AC_BT2_INT; grandchild = grandchild_int; @@ -700,7 +700,7 @@ H5B2__redistribute2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *grandchild_leaf = NULL; /* Protect grandchild */ - if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, H5AC_WRITE))) + if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") grandchild_class = H5AC_BT2_LEAF; grandchild = grandchild_leaf; @@ -791,7 +791,7 @@ H5B2__redistribute2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *grandchild_int = NULL; /* Protect grandchild */ - if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, (depth - 2), H5AC_WRITE))) + if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, (depth - 2), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") grandchild_class = H5AC_BT2_INT; grandchild = grandchild_int; @@ -807,7 +807,7 @@ H5B2__redistribute2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *grandchild_leaf = NULL; /* Protect grandchild */ - if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, H5AC_WRITE))) + if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") grandchild_class = H5AC_BT2_LEAF; grandchild = grandchild_leaf; @@ -952,11 +952,11 @@ H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, right_addr = internal->node_ptrs[idx + 1].addr; /* Lock B-tree child nodes */ - if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx - 1].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx - 1].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") - if(NULL == (middle_internal = H5B2__protect_internal(hdr, dxpl_id, middle_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (middle_internal = H5B2__protect_internal(hdr, dxpl_id, middle_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") - if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Shadow all nodes if doing SWMR writes */ @@ -998,11 +998,11 @@ H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, right_addr = internal->node_ptrs[idx + 1].addr; /* Lock B-tree child nodes */ - if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx - 1].node_nrec, H5AC_WRITE))) + if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx - 1].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") - if(NULL == (middle_leaf = H5B2__protect_leaf(hdr, dxpl_id, middle_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC_WRITE))) + if(NULL == (middle_leaf = H5B2__protect_leaf(hdr, dxpl_id, middle_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") - if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, H5AC_WRITE))) + if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Shadow all nodes if doing SWMR writes */ @@ -1096,7 +1096,7 @@ H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *grandchild_int = NULL; /* Protect grandchild */ - if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, (depth - 2), H5AC_WRITE))) + if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, (depth - 2), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") grandchild_class = H5AC_BT2_INT; grandchild = grandchild_int; @@ -1112,7 +1112,7 @@ H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *grandchild_leaf = NULL; /* Protect grandchild */ - if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, H5AC_WRITE))) + if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") grandchild_class = H5AC_BT2_LEAF; grandchild = grandchild_leaf; @@ -1197,7 +1197,7 @@ H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *grandchild_int = NULL; /* Protect grandchild */ - if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, (depth - 2), H5AC_WRITE))) + if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, (depth - 2), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") grandchild_class = H5AC_BT2_INT; grandchild = grandchild_int; @@ -1213,7 +1213,7 @@ H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *grandchild_leaf = NULL; /* Protect grandchild */ - if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, H5AC_WRITE))) + if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, right_child, right_node_ptrs[u].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") grandchild_class = H5AC_BT2_LEAF; grandchild = grandchild_leaf; @@ -1298,7 +1298,7 @@ H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *grandchild_int = NULL; /* Protect grandchild */ - if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, (depth - 2), H5AC_WRITE))) + if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, (depth - 2), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") grandchild_class = H5AC_BT2_INT; grandchild = grandchild_int; @@ -1314,7 +1314,7 @@ H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *grandchild_leaf = NULL; /* Protect grandchild */ - if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, H5AC_WRITE))) + if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") grandchild_class = H5AC_BT2_LEAF; grandchild = grandchild_leaf; @@ -1398,7 +1398,7 @@ H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *grandchild_int = NULL; /* Protect grandchild */ - if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, (depth - 2), H5AC_WRITE))) + if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, (depth - 2), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") grandchild_class = H5AC_BT2_INT; grandchild = grandchild_int; @@ -1414,7 +1414,7 @@ H5B2__redistribute3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *grandchild_leaf = NULL; /* Protect grandchild */ - if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, H5AC_WRITE))) + if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") grandchild_class = H5AC_BT2_LEAF; grandchild = grandchild_leaf; @@ -1601,9 +1601,9 @@ H5B2__merge2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, right_addr = internal->node_ptrs[idx + 1].addr; /* Lock left & right B-tree child nodes */ - if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") - if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Shadow the left node if doing SWMR writes */ @@ -1633,9 +1633,9 @@ H5B2__merge2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, right_addr = internal->node_ptrs[idx + 1].addr; /* Lock left & right B-tree child nodes */ - if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC_WRITE))) + if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") - if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, H5AC_WRITE))) + if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Shadow the left node if doing SWMR writes */ @@ -1680,7 +1680,7 @@ H5B2__merge2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *grandchild_int = NULL; /* Protect grandchild */ - if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, (depth - 2), H5AC_WRITE))) + if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, (depth - 2), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") grandchild_class = H5AC_BT2_INT; grandchild = grandchild_int; @@ -1696,7 +1696,7 @@ H5B2__merge2(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *grandchild_leaf = NULL; /* Protect grandchild */ - if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, H5AC_WRITE))) + if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") grandchild_class = H5AC_BT2_LEAF; grandchild = grandchild_leaf; @@ -1849,11 +1849,11 @@ H5B2__merge3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, right_addr = internal->node_ptrs[idx + 1].addr; /* Lock B-tree child nodes */ - if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx - 1].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (left_internal = H5B2__protect_internal(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx - 1].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") - if(NULL == (middle_internal = H5B2__protect_internal(hdr, dxpl_id, middle_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (middle_internal = H5B2__protect_internal(hdr, dxpl_id, middle_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") - if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, (uint16_t)(depth - 1), H5AC_WRITE))) + if(NULL == (right_internal = H5B2__protect_internal(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Shadow left and middle nodes if doing SWMR writes */ @@ -1892,11 +1892,11 @@ H5B2__merge3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, right_addr = internal->node_ptrs[idx + 1].addr; /* Lock B-tree child nodes */ - if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx - 1].node_nrec, H5AC_WRITE))) + if(NULL == (left_leaf = H5B2__protect_leaf(hdr, dxpl_id, left_addr, internal, internal->node_ptrs[idx - 1].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") - if(NULL == (middle_leaf = H5B2__protect_leaf(hdr, dxpl_id, middle_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC_WRITE))) + if(NULL == (middle_leaf = H5B2__protect_leaf(hdr, dxpl_id, middle_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") - if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, H5AC_WRITE))) + if(NULL == (right_leaf = H5B2__protect_leaf(hdr, dxpl_id, right_addr, internal, internal->node_ptrs[idx + 1].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Shadow left and middle nodes if doing SWMR writes */ @@ -1969,7 +1969,7 @@ H5B2__merge3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *grandchild_int = NULL; /* Protect grandchild */ - if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, (depth - 2), H5AC_WRITE))) + if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, (depth - 2), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") grandchild_class = H5AC_BT2_INT; grandchild = grandchild_int; @@ -1985,7 +1985,7 @@ H5B2__merge3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *grandchild_leaf = NULL; /* Protect grandchild */ - if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, H5AC_WRITE))) + if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, left_child, left_node_ptrs[u].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") grandchild_class = H5AC_BT2_LEAF; grandchild = grandchild_leaf; @@ -2050,7 +2050,7 @@ H5B2__merge3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *grandchild_int = NULL; /* Protect grandchild */ - if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, (depth - 2), H5AC_WRITE))) + if(NULL == (grandchild_int = H5B2__protect_internal(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, (depth - 2), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") grandchild_class = H5AC_BT2_INT; grandchild = grandchild_int; @@ -2066,7 +2066,7 @@ H5B2__merge3(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *grandchild_leaf = NULL; /* Protect grandchild */ - if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, H5AC_WRITE))) + if(NULL == (grandchild_leaf = H5B2__protect_leaf(hdr, dxpl_id, grandchild_addr, middle_child, middle_node_ptrs[u].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") grandchild_class = H5AC_BT2_LEAF; grandchild = grandchild_leaf; @@ -2209,7 +2209,7 @@ H5B2__swap_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, child_addr = internal->node_ptrs[idx].addr; /* Lock B-tree child nodes */ - if(NULL == (child_internal = H5B2__protect_internal(hdr, dxpl_id, child_addr, internal, internal->node_ptrs[idx].node_nrec, (depth - 1), H5AC_WRITE))) + if(NULL == (child_internal = H5B2__protect_internal(hdr, dxpl_id, child_addr, internal, internal->node_ptrs[idx].node_nrec, (uint16_t)(depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* More setup for accessing child node information */ @@ -2224,7 +2224,7 @@ H5B2__swap_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, child_addr = internal->node_ptrs[idx].addr; /* Lock B-tree child node */ - if(NULL == (child_leaf = H5B2__protect_leaf(hdr, dxpl_id, child_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC_WRITE))) + if(NULL == (child_leaf = H5B2__protect_leaf(hdr, dxpl_id, child_addr, internal, internal->node_ptrs[idx].node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* More setup for accessing child node information */ @@ -2287,7 +2287,7 @@ H5B2__insert_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, H5B2_node_ptr_t *curr_node_ptr HDassert(H5F_addr_defined(curr_node_ptr->addr)); /* Lock current B-tree node */ - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr->addr, parent, curr_node_ptr->node_nrec, H5AC_WRITE))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr->addr, parent, curr_node_ptr->node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Shadow the node if doing SWMR writes */ @@ -2391,7 +2391,7 @@ H5B2__insert_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, HDassert(H5F_addr_defined(curr_node_ptr->addr)); /* Lock current B-tree node */ - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr->addr, parent, curr_node_ptr->node_nrec, depth, H5AC_WRITE))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr->addr, parent, curr_node_ptr->node_nrec, depth, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Shadow the node if doing SWMR writes */ @@ -2599,8 +2599,8 @@ done: *------------------------------------------------------------------------- */ H5B2_leaf_t * -H5B2__protect_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, haddr_t addr, void *parent, - uint16_t nrec, H5AC_protect_t rw) +H5B2__protect_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, haddr_t addr, void *parent, + uint16_t nrec, unsigned flags) { H5B2_leaf_cache_ud_t udata; /* User-data for callback */ H5B2_leaf_t *ret_value; /* Return value */ @@ -2611,6 +2611,9 @@ H5B2__protect_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, haddr_t addr, void *parent, HDassert(hdr); HDassert(H5F_addr_defined(addr)); + /* only H5AC__READ_ONLY_FLAG may appear in flags */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Set up user data for callback */ udata.f = hdr->f; udata.hdr = hdr; @@ -2618,7 +2621,7 @@ H5B2__protect_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, haddr_t addr, void *parent, H5_CHECKED_ASSIGN(udata.nrec, uint16_t, nrec, unsigned) /* Protect the leaf node */ - if(NULL == (ret_value = (H5B2_leaf_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_BT2_LEAF, addr, &udata, rw))) + if(NULL == (ret_value = (H5B2_leaf_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_BT2_LEAF, addr, &udata, flags))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to protect B-tree leaf node") done: @@ -2727,7 +2730,7 @@ done: */ H5B2_internal_t * H5B2__protect_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, haddr_t addr, - void *parent, uint16_t nrec, uint16_t depth, H5AC_protect_t rw) + void *parent, uint16_t nrec, uint16_t depth, unsigned flags) { H5B2_internal_cache_ud_t udata; /* User data to pass through to cache 'deserialize' callback */ H5B2_internal_t *ret_value; /* Return value */ @@ -2739,6 +2742,9 @@ H5B2__protect_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, haddr_t addr, HDassert(H5F_addr_defined(addr)); HDassert(depth > 0); + /* only H5AC__READ_ONLY_FLAG may appear in flags */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Set up user data for callback */ udata.f = hdr->f; udata.hdr = hdr; @@ -2747,7 +2753,7 @@ H5B2__protect_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, haddr_t addr, udata.depth = depth; /* Protect the internal node */ - if(NULL == (ret_value = (H5B2_internal_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_BT2_INT, addr, &udata, rw))) + if(NULL == (ret_value = (H5B2_internal_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_BT2_INT, addr, &udata, flags))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to protect B-tree internal node") done: @@ -2798,7 +2804,7 @@ H5B2__iterate_node(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_internal_t *internal; /* Pointer to internal node */ /* Lock the current B-tree node */ - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node->addr, parent, curr_node->node_nrec, depth, H5AC_READ))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node->addr, parent, curr_node->node_nrec, depth, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Set up information about current node */ @@ -2817,7 +2823,7 @@ H5B2__iterate_node(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *leaf; /* Pointer to leaf node */ /* Lock the current B-tree node */ - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node->addr, parent, curr_node->node_nrec, H5AC_READ))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node->addr, parent, curr_node->node_nrec, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Set up information about current node */ @@ -2909,7 +2915,7 @@ H5B2__remove_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, H5B2_node_ptr_t *curr_node_ptr /* Lock current B-tree node */ leaf_addr = curr_node_ptr->addr; - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, leaf_addr, parent, curr_node_ptr->node_nrec, H5AC_WRITE))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, leaf_addr, parent, curr_node_ptr->node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Sanity check number of records */ @@ -3029,7 +3035,7 @@ H5B2__remove_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, hbool_t *depth_decreased, /* Lock current B-tree node */ internal_addr = curr_node_ptr->addr; - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, internal_addr, parent_cache_info, curr_node_ptr->node_nrec, depth, H5AC_WRITE))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, internal_addr, parent_cache_info, curr_node_ptr->node_nrec, depth, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Determine the correct number of records to merge at */ @@ -3063,7 +3069,7 @@ H5B2__remove_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, hbool_t *depth_decreased, H5B2_internal_t *new_root_int = NULL; /* Protect new root */ - if(NULL == (new_root_int = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr->addr, hdr, curr_node_ptr->node_nrec, (depth - 1), H5AC_WRITE))) + if(NULL == (new_root_int = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr->addr, hdr, curr_node_ptr->node_nrec, (depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") new_root_class = H5AC_BT2_INT; new_root = new_root_int; @@ -3079,7 +3085,7 @@ H5B2__remove_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, hbool_t *depth_decreased, H5B2_leaf_t *new_root_leaf = NULL; /* Protect new root */ - if(NULL == (new_root_leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr->addr, hdr, curr_node_ptr->node_nrec, H5AC_WRITE))) + if(NULL == (new_root_leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr->addr, hdr, curr_node_ptr->node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") new_root_class = H5AC_BT2_LEAF; new_root = new_root_leaf; @@ -3312,7 +3318,7 @@ H5B2__remove_leaf_by_idx(H5B2_hdr_t *hdr, hid_t dxpl_id, /* Lock B-tree leaf node */ leaf_addr = curr_node_ptr->addr; - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, leaf_addr, parent, curr_node_ptr->node_nrec, H5AC_WRITE))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, leaf_addr, parent, curr_node_ptr->node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Sanity check number of records */ @@ -3431,7 +3437,7 @@ H5B2__remove_internal_by_idx(H5B2_hdr_t *hdr, hid_t dxpl_id, /* Lock current B-tree node */ internal_addr = curr_node_ptr->addr; - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, internal_addr, parent_cache_info, curr_node_ptr->node_nrec, depth, H5AC_WRITE))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, internal_addr, parent_cache_info, curr_node_ptr->node_nrec, depth, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") HDassert(internal->nrec == curr_node_ptr->node_nrec); HDassert(depth == hdr->depth || internal->nrec > 1); @@ -3468,7 +3474,7 @@ H5B2__remove_internal_by_idx(H5B2_hdr_t *hdr, hid_t dxpl_id, H5B2_internal_t *new_root_int = NULL; /* Protect new root */ - if(NULL == (new_root_int = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr->addr, hdr, curr_node_ptr->node_nrec, (depth - 1), H5AC_WRITE))) + if(NULL == (new_root_int = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr->addr, hdr, curr_node_ptr->node_nrec, (depth - 1), H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") new_root_class = H5AC_BT2_INT; new_root = new_root_int; @@ -3484,7 +3490,7 @@ H5B2__remove_internal_by_idx(H5B2_hdr_t *hdr, hid_t dxpl_id, H5B2_leaf_t *new_root_leaf = NULL; /* Protect new root */ - if(NULL == (new_root_leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr->addr, hdr, curr_node_ptr->node_nrec, H5AC_WRITE))) + if(NULL == (new_root_leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr->addr, hdr, curr_node_ptr->node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") new_root_class = H5AC_BT2_LEAF; new_root = new_root_leaf; @@ -3781,7 +3787,7 @@ H5B2__neighbor_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, H5B2_node_ptr_t *curr_node_p HDassert(op); /* Lock current B-tree node */ - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr->addr, parent, curr_node_ptr->node_nrec, H5AC_READ))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr->addr, parent, curr_node_ptr->node_nrec, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Locate node pointer for child */ @@ -3868,7 +3874,7 @@ H5B2__neighbor_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, HDassert(op); /* Lock current B-tree node */ - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr->addr, parent, curr_node_ptr->node_nrec, depth, H5AC_READ))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr->addr, parent, curr_node_ptr->node_nrec, depth, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Locate node pointer for child */ @@ -3942,7 +3948,7 @@ H5B2__delete_node(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, unsigned u; /* Local index */ /* Lock the current B-tree node */ - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node->addr, parent, curr_node->node_nrec, depth, H5AC_WRITE))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node->addr, parent, curr_node->node_nrec, depth, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Set up information about current node */ @@ -3959,7 +3965,7 @@ H5B2__delete_node(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, H5B2_leaf_t *leaf; /* Pointer to leaf node */ /* Lock the current B-tree node */ - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node->addr, parent, curr_node->node_nrec, H5AC_WRITE))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node->addr, parent, curr_node->node_nrec, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Set up information about current node */ @@ -4018,7 +4024,7 @@ H5B2__node_size(H5B2_hdr_t *hdr, hid_t dxpl_id, uint16_t depth, HDassert(depth > 0); /* Lock the current B-tree node */ - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node->addr, parent, curr_node->node_nrec, depth, H5AC_READ))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node->addr, parent, curr_node->node_nrec, depth, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") /* Recursively descend into child nodes, if we are above the "twig" level in the B-tree */ @@ -4203,7 +4209,7 @@ H5B2_shadow_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, unsigned depth, /* Re-protect node at new address. Should have the same location in * memory. */ - if(*internal != H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr->addr, (*internal)->parent, curr_node_ptr->node_nrec, depth, H5AC_WRITE)) + if(*internal != H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr->addr, (*internal)->parent, curr_node_ptr->node_nrec, depth, H5AC__NO_FLAGS_SET)) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node") node_protected = TRUE; @@ -4303,7 +4309,7 @@ H5B2_shadow_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, /* Re-protect node at new address. Should have the same location in * memory. */ - if(*leaf != H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr->addr, (*leaf)->parent, curr_node_ptr->node_nrec, H5AC_WRITE)) + if(*leaf != H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr->addr, (*leaf)->parent, curr_node_ptr->node_nrec, H5AC__NO_FLAGS_SET)) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") node_protected = TRUE; diff --git a/src/H5B2pkg.h b/src/H5B2pkg.h index 9c5c693..9702ae0 100644 --- a/src/H5B2pkg.h +++ b/src/H5B2pkg.h @@ -242,6 +242,7 @@ typedef enum H5B2_nodepos_t { typedef struct H5B2_hdr_cache_ud_t { H5F_t *f; /* File that v2 b-tree header is within */ void *parent; /* Flush dependency parent */ + haddr_t addr; /* Address of B-tree header in the file */ void *ctx_udata; /* User-data for protecting */ } H5B2_hdr_cache_ud_t; @@ -324,11 +325,11 @@ H5_DLL herr_t H5B2__hdr_delete(H5B2_hdr_t *hdr, hid_t dxpl_id); /* Routines for operating on leaf nodes */ H5B2_leaf_t *H5B2__protect_leaf(H5B2_hdr_t *hdr, hid_t dxpl_id, haddr_t addr, - void *parent, uint16_t nrec, H5AC_protect_t rw); + void *parent, uint16_t nrec, unsigned flags); /* Routines for operating on internal nodes */ H5_DLL H5B2_internal_t *H5B2__protect_internal(H5B2_hdr_t *hdr, hid_t dxpl_id, - haddr_t addr, void *parent, uint16_t nrec, uint16_t depth, H5AC_protect_t rw); + haddr_t addr, void *parent, uint16_t nrec, uint16_t depth, unsigned flags); /* Routines for allocating nodes */ H5_DLL herr_t H5B2__split_root(H5B2_hdr_t *hdr, hid_t dxpl_id); diff --git a/src/H5B2test.c b/src/H5B2test.c index 45b53a6..5890fb8 100644 --- a/src/H5B2test.c +++ b/src/H5B2test.c @@ -435,7 +435,7 @@ H5B2_get_node_info_test(H5B2_t *bt2, hid_t dxpl_id, void *udata, H5B2_node_ptr_t next_node_ptr; /* Node pointer info for next node */ /* Lock B-tree current node */ - if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, depth, H5AC_READ))) + if(NULL == (internal = H5B2__protect_internal(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, depth, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree internal node") /* Unpin parent if necessary */ @@ -486,7 +486,7 @@ H5B2_get_node_info_test(H5B2_t *bt2, hid_t dxpl_id, void *udata, H5B2_leaf_t *leaf; /* Pointer to leaf node in B-tree */ /* Lock B-tree leaf node */ - if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, H5AC_READ))) + if(NULL == (leaf = H5B2__protect_leaf(hdr, dxpl_id, curr_node_ptr.addr, parent, curr_node_ptr.node_nrec, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node") /* Unpin parent if necessary */ diff --git a/src/H5Bcache.c b/src/H5Bcache.c index 923880f..2a188f8 100644 --- a/src/H5Bcache.c +++ b/src/H5Bcache.c @@ -37,7 +37,6 @@ #include "H5private.h" /* Generic Functions */ #include "H5Bpkg.h" /* B-link trees */ #include "H5Eprivate.h" /* Error handling */ -#include "H5MFprivate.h" /* File memory management */ /****************/ @@ -55,11 +54,15 @@ /********************/ /* Metadata cache callbacks */ -static H5B_t *H5B__load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5B__flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B_t *b, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5B__dest(H5F_t *f, H5B_t *bt); -static herr_t H5B__clear(H5F_t *f, H5B_t *b, hbool_t destroy); -static herr_t H5B__compute_size(const H5F_t *f, const H5B_t *bt, size_t *size_ptr); +static herr_t H5B__get_load_size(const void *image, void *udata, size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static void *H5B__deserialize(const void *image, size_t len, void *udata, + hbool_t *dirty); +static herr_t H5B__image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5B__serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5B__free_icr(void *thing); /*********************/ @@ -68,13 +71,20 @@ static herr_t H5B__compute_size(const H5F_t *f, const H5B_t *bt, size_t *size_pt /* H5B inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_BT[1] = {{ - H5AC_BT_ID, - (H5AC_load_func_t)H5B__load, - (H5AC_flush_func_t)H5B__flush, - (H5AC_dest_func_t)H5B__dest, - (H5AC_clear_func_t)H5B__clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5B__compute_size, + H5AC_BT_ID, /* Metadata client ID */ + "v1 B-tree", /* Metadata client name (for debugging) */ + H5FD_MEM_BTREE, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5B__get_load_size, /* 'get_load_size' callback */ + NULL, /* 'verify_chksum' callback */ + H5B__deserialize, /* 'deserialize' callback */ + H5B__image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5B__serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5B__free_icr, /* 'free_icr' callback */ + NULL, /* 'clear" callback */ + NULL, /* 'fsf_size' callback */ }}; /*******************/ @@ -84,35 +94,78 @@ const H5AC_class_t H5AC_BT[1] = {{ /*------------------------------------------------------------------------- - * Function: H5B__load + * Function: H5B__get_load_size * - * Purpose: Loads a B-tree node from the disk. + * Purpose: Compute the size of the data structure on disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * May 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5B__get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into image buffer */ + H5B_cache_ud_t *udata = (H5B_cache_ud_t *)_udata; /* User data for callback */ + H5B_shared_t *shared; /* Pointer to shared B-tree info */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(udata); + HDassert(image_len); + + if(image == NULL) { + /* Get shared info for B-tree */ + shared = (H5B_shared_t *)H5UC_GET_OBJ(udata->rc_shared); + HDassert(shared); + + /* Set the image length size */ + *image_len = shared->sizeof_rnode; + } else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5B__get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5B__deserialize + * + * Purpose: Deserialize the data structure from disk. * * Return: Success: Pointer to a new B-tree node. * Failure: NULL * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Jun 23 1997 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 24, 2008 * *------------------------------------------------------------------------- */ -static H5B_t * -H5B__load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5B__deserialize(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { H5B_t *bt = NULL; /* Pointer to the deserialized B-tree node */ H5B_cache_ud_t *udata = (H5B_cache_ud_t *)_udata; /* User data for callback */ H5B_shared_t *shared; /* Pointer to shared B-tree info */ - const uint8_t *p; /* Pointer into raw data buffer */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into image buffer */ uint8_t *native; /* Pointer to native keys */ unsigned u; /* Local index variable */ H5B_t *ret_value; /* Return value */ FUNC_ENTER_STATIC - /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* check arguments */ + HDassert(image); HDassert(udata); /* Allocate the B-tree node in memory */ @@ -134,53 +187,50 @@ H5B__load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) if(NULL == (bt->child = H5FL_SEQ_MALLOC(haddr_t, (size_t)shared->two_k))) HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "can't allocate buffer for child addresses") - if(H5F_block_read(f, H5FD_MEM_BTREE, addr, shared->sizeof_rnode, dxpl_id, shared->page) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_READERROR, NULL, "can't read B-tree node") - - /* Set the pointer into the raw data buffer */ - p = shared->page; - /* magic number */ - if(HDmemcmp(p, H5B_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5B_MAGIC, (size_t)H5_SIZEOF_MAGIC)) HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree signature") - p += 4; + image += H5_SIZEOF_MAGIC; /* node type and level */ - if(*p++ != (uint8_t)udata->type->id) + if(*image++ != (uint8_t)udata->type->id) HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, NULL, "incorrect B-tree node type") - bt->level = *p++; + bt->level = *image++; /* entries used */ - UINT16DECODE(p, bt->nchildren); + UINT16DECODE(image, bt->nchildren); /* Check if bt->nchildren is greater than two_k */ if(bt->nchildren > shared->two_k) HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "number of children is greater than maximum") /* sibling pointers */ - H5F_addr_decode(udata->f, (const uint8_t **)&p, &(bt->left)); - H5F_addr_decode(udata->f, (const uint8_t **)&p, &(bt->right)); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &(bt->left)); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &(bt->right)); /* the child/key pairs */ native = bt->native; for(u = 0; u < bt->nchildren; u++) { /* Decode native key value */ - if((udata->type->decode)(shared, p, native) < 0) + if((udata->type->decode)(shared, image, native) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode key") - p += shared->sizeof_rkey; + image += shared->sizeof_rkey; native += udata->type->sizeof_nkey; /* Decode address value */ - H5F_addr_decode(udata->f, (const uint8_t **)&p, bt->child + u); + H5F_addr_decode(udata->f, (const uint8_t **)&image, bt->child + u); } /* end for */ /* Decode final key */ if(bt->nchildren > 0) { /* Decode native key value */ - if((udata->type->decode)(shared, p, native) < 0) + if((udata->type->decode)(shared, image, native) < 0) HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode key") } /* end if */ + /* Sanity check */ + HDassert((size_t)((const uint8_t *)image - (const uint8_t *)_image) <= len); + /* Set return value */ ret_value = bt; @@ -190,223 +240,150 @@ done: HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree node") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B__load() */ /*lint !e818 Can't make udata a pointer to const */ +} /* end H5B__deserialize() */ /*------------------------------------------------------------------------- - * Function: H5B__flush + * Function: H5B__image_len * - * Purpose: Flushes a dirty B-tree node to disk. + * Purpose: Compute the size of the data structure on disk. * * Return: Non-negative on success/Negative on failure * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Jun 23 1997 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * May 20, 2010 * *------------------------------------------------------------------------- */ static herr_t -H5B__flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B_t *bt, unsigned H5_ATTR_UNUSED * flags_ptr) +H5B__image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { + const H5B_t *bt = (const H5B_t *)_thing; /* Pointer to the B-tree node */ H5B_shared_t *shared; /* Pointer to shared B-tree info */ - herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC + FUNC_ENTER_STATIC_NOERR - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(bt); + HDassert(image_len); + + /* Get shared info for B-tree */ shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared); HDassert(shared); - HDassert(shared->type); - HDassert(shared->type->encode); - - if(bt->cache_info.is_dirty) { - uint8_t *p; /* Pointer into raw data buffer */ - uint8_t *native; /* Pointer to native keys */ - unsigned u; /* Local index variable */ - - p = shared->page; - - /* magic number */ - HDmemcpy(p, H5B_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += 4; - - /* node type and level */ - *p++ = (uint8_t)shared->type->id; - H5_CHECK_OVERFLOW(bt->level, unsigned, uint8_t); - *p++ = (uint8_t)bt->level; - - /* entries used */ - UINT16ENCODE(p, bt->nchildren); - - /* sibling pointers */ - H5F_addr_encode(f, &p, bt->left); - H5F_addr_encode(f, &p, bt->right); - - /* child keys and pointers */ - native = bt->native; - for(u = 0; u < bt->nchildren; ++u) { - /* encode the key */ - if(shared->type->encode(shared, p, native) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree key") - p += shared->sizeof_rkey; - native += shared->type->sizeof_nkey; - - /* encode the child address */ - H5F_addr_encode(f, &p, bt->child[u]); - } /* end for */ - if(bt->nchildren > 0) { - /* Encode the final key */ - if(shared->type->encode(shared, p, native) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree key") - } /* end if */ - - /* - * Write the disk page. We always write the header, but we don't - * bother writing data for the child entries that don't exist or - * for the final unchanged children. - */ - if(H5F_block_write(f, H5FD_MEM_BTREE, addr, shared->sizeof_rnode, dxpl_id, shared->page) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFLUSH, FAIL, "unable to save B-tree node to disk") - - bt->cache_info.is_dirty = FALSE; - } /* end if */ - if(destroy) - if(H5B__dest(f, bt) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree node") + /* Set the image length size */ + *image_len = shared->sizeof_rnode; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B__flush() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5B__image_len() */ /*------------------------------------------------------------------------- - * Function: H5B__dest + * Function: H5B__serialize * - * Purpose: Destroys a B-tree node in memory. + * Purpose: Serialize the data structure for writing to disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Jan 15 2003 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 24, 2008 * *------------------------------------------------------------------------- */ static herr_t -H5B__dest(H5F_t *f, H5B_t *bt) +H5B__serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5B_t *bt = (H5B_t *)_thing; /* Pointer to the B-tree node */ + H5B_shared_t *shared; /* Pointer to shared B-tree info */ + uint8_t *image = (uint8_t *)_image; /* Pointer into image buffer */ + uint8_t *native; /* Pointer to native keys */ + unsigned u; /* Local index counter */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC - /* - * Check arguments. - */ - HDassert(f); + /* check arguments */ + HDassert(image); HDassert(bt); HDassert(bt->rc_shared); + shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared); + HDassert(shared); + HDassert(shared->type); + HDassert(shared->type->encode); - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!bt->cache_info.free_file_space_on_destroy || H5F_addr_defined(bt->cache_info.addr)); + /* magic number */ + HDmemcpy(image, H5B_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += 4; - /* Check for freeing file space for B-tree node */ - if(bt->cache_info.free_file_space_on_destroy) { - H5B_shared_t *shared; /* Pointer to shared B-tree info */ + /* node type and level */ + *image++ = (uint8_t)shared->type->id; + H5_CHECK_OVERFLOW(bt->level, unsigned, uint8_t); + *image++ = (uint8_t)bt->level; - /* Get the pointer to the shared B-tree info */ - shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared); - HDassert(shared); + /* entries used */ + UINT16ENCODE(image, bt->nchildren); - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_BTREE, H5AC_dxpl_id, bt->cache_info.addr, (hsize_t)shared->sizeof_rnode) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free B-tree node") + /* sibling pointers */ + H5F_addr_encode(f, &image, bt->left); + H5F_addr_encode(f, &image, bt->right); + + /* child keys and pointers */ + native = bt->native; + for(u = 0; u < bt->nchildren; ++u) { + /* encode the key */ + if(shared->type->encode(shared, image, native) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree key") + image += shared->sizeof_rkey; + native += shared->type->sizeof_nkey; + + /* encode the child address */ + H5F_addr_encode(f, &image, bt->child[u]); + } /* end for */ + if(bt->nchildren > 0) { + /* Encode the final key */ + if(shared->type->encode(shared, image, native) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree key") } /* end if */ - /* Destroy B-tree node */ - if(H5B__node_dest(bt) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree node") + /* Sanity check */ + HDassert((size_t)((const uint8_t *)image - (const uint8_t *)_image) <= len); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B__dest() */ +} /* end H5B__serialize() */ /*------------------------------------------------------------------------- - * Function: H5B__clear + * Function: H5B__free_icr * - * Purpose: Mark a B-tree node in memory as non-dirty. + * Purpose: Destroy/release an "in core representation" of a data structure * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 20 2003 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Mar 26, 2008 * *------------------------------------------------------------------------- */ static herr_t -H5B__clear(H5F_t *f, H5B_t *bt, hbool_t destroy) +H5B__free_icr(void *thing) { - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC - /* - * Check arguments. - */ - HDassert(bt); - - /* Reset the dirty flag. */ - bt->cache_info.is_dirty = FALSE; + /* Check arguments */ + HDassert(thing); - if(destroy) - if(H5B__dest(f, bt) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree node") + /* Destroy B-tree node */ + if(H5B__node_dest((H5B_t *)thing) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree node") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B__clear() */ - - -/*------------------------------------------------------------------------- - * Function: H5B__compute_size - * - * Purpose: Compute the size in bytes of the specified instance of - * H5B_t on disk, and return it in *len_ptr. On failure, - * the value of *len_ptr is undefined. - * - * Return: SUCCEED (Can't fail) - * - * Programmer: John Mainzer - * 5/13/04 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5B__compute_size(const H5F_t H5_ATTR_UNUSED *f, const H5B_t *bt, size_t *size_ptr) -{ - H5B_shared_t *shared; /* Pointer to shared B-tree info */ - - FUNC_ENTER_NOAPI_NOINIT_NOERR - - /* check arguments */ - HDassert(f); - HDassert(bt); - HDassert(bt->rc_shared); - shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared); - HDassert(shared); - HDassert(shared->type); - HDassert(size_ptr); - - /* Set size value */ - *size_ptr = shared->sizeof_rnode; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5B__compute_size() */ - +} /* end H5B__free_icr() */ diff --git a/src/H5Bdbg.c b/src/H5Bdbg.c index 276156e..34e8465 100644 --- a/src/H5Bdbg.c +++ b/src/H5Bdbg.c @@ -93,7 +93,7 @@ H5B_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int f cache_udata.type = type; cache_udata.rc_shared = rc_shared; cache_udata.parent = NULL; - if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ))) + if(NULL == (bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node") /* @@ -210,7 +210,7 @@ H5B__assert(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type, void cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; - bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC_READ); + bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG); HDassert(bt); shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared); HDassert(shared); @@ -231,7 +231,7 @@ H5B__assert(H5F_t *f, hid_t dxpl_id, haddr_t addr, const H5B_class_t *type, void * test. */ for(ncell = 0; cur; ncell++) { - bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, cur->addr, &cache_udata, H5AC_READ); + bt = (H5B_t *)H5AC_protect(f, dxpl_id, H5AC_BT, cur->addr, &cache_udata, H5AC__READ_ONLY_FLAG); HDassert(bt); /* Check node header */ @@ -86,12 +86,23 @@ #include "H5FDprivate.h" /* File drivers */ #include "H5FLprivate.h" /* Free Lists */ #include "H5Iprivate.h" /* IDs */ +#include "H5MFprivate.h" /* File memory management */ #include "H5MMprivate.h" /* Memory management */ #include "H5Pprivate.h" /* Property lists */ #include "H5SLprivate.h" /* Skip lists */ /* + * Private macros. + */ +#if H5C_DO_MEMORY_SANITY_CHECKS +#define H5C_IMAGE_EXTRA_SPACE 8 +#define H5C_IMAGE_SANITY_VALUE "DeadBeef" +#else /* H5C_DO_MEMORY_SANITY_CHECKS */ +#define H5C_IMAGE_EXTRA_SPACE 0 +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + +/* * Private file-scope variables. */ @@ -110,27 +121,21 @@ H5FL_DEFINE_STATIC(haddr_t); */ static herr_t H5C__auto_adjust_cache_size(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - hbool_t write_permitted, - hbool_t * first_flush_ptr); + hid_t dxpl_id, + hbool_t write_permitted); static herr_t H5C__autoadjust__ageout(H5F_t * f, + hid_t dxpl_id, double hit_rate, enum H5C_resize_status * status_ptr, size_t * new_max_cache_size_ptr, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - hbool_t write_permitted, - hbool_t * first_flush_ptr); + hbool_t write_permitted); static herr_t H5C__autoadjust__ageout__cycle_epoch_marker(H5C_t * cache_ptr); static herr_t H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - hbool_t write_permitted, - hbool_t * first_flush_ptr); + hid_t dxpl_id, + hbool_t write_permitted); static herr_t H5C__autoadjust__ageout__insert_new_marker(H5C_t * cache_ptr); @@ -142,19 +147,16 @@ static herr_t H5C__flash_increase_cache_size(H5C_t * cache_ptr, size_t old_entry_size, size_t new_entry_size); -static herr_t H5C_flush_single_entry(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - const H5C_class_t * type_ptr, - haddr_t addr, - unsigned flags, - hbool_t * first_flush_ptr, - hbool_t del_entry_from_slist_on_destroy); +static herr_t H5C_flush_single_entry(const H5F_t * f, + hid_t dxpl_id, + haddr_t addr, + unsigned flags, + hbool_t del_entry_from_slist_on_destroy, + int64_t *entry_size_change_ptr); -static herr_t H5C_flush_invalidate_cache(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - unsigned flags); +static herr_t H5C_flush_invalidate_cache(const H5F_t * f, + hid_t dxpl_id, + unsigned flags); static void * H5C_load_entry(H5F_t * f, hid_t dxpl_id, @@ -163,37 +165,41 @@ static void * H5C_load_entry(H5F_t * f, void * udata); static herr_t H5C_make_space_in_cache(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - size_t space_needed, - hbool_t write_permitted, - hbool_t * first_flush_ptr); + hid_t dxpl_id, + size_t space_needed, + hbool_t write_permitted); static herr_t H5C_tag_entry(H5C_t * cache_ptr, H5C_cache_entry_t * entry_ptr, hid_t dxpl_id); -static herr_t H5C_mark_tagged_entries(H5C_t * cache_ptr, +static herr_t H5C_mark_tagged_entries(H5C_t * cache_ptr, haddr_t tag, hbool_t mark_clean); -static herr_t H5C_mark_tagged_entries_cork(H5C_t *cache_ptr, - haddr_t obj_addr, - hbool_t val); -static herr_t H5C_flush_marked_entries(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - H5C_t * cache_ptr); +static herr_t H5C_mark_tagged_entries_cork(H5C_t *cache_ptr, + haddr_t obj_addr, + hbool_t val); -static herr_t H5C_evict_marked_entries(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, +static herr_t H5C_flush_marked_entries(H5F_t * f, + hid_t dxpl_id, H5C_t * cache_ptr); static herr_t H5C__mark_flush_dep_dirty(H5C_cache_entry_t * entry); static herr_t H5C__mark_flush_dep_clean(H5C_cache_entry_t * entry); +static herr_t H5C_verify_len_eoa (H5F_t *f, + const H5C_class_t * type, + haddr_t addr, + size_t *len, + htri_t actual); + +#if H5C_DO_SLIST_SANITY_CHECKS +static hbool_t H5C_entry_in_skip_list(H5C_t * cache_ptr, + H5C_cache_entry_t *target_ptr); +#endif /* H5C_DO_SLIST_SANITY_CHECKS */ + #if H5C_DO_EXTREME_SANITY_CHECKS static herr_t H5C_validate_lru_list(H5C_t * cache_ptr); static herr_t H5C_validate_pinned_entry_list(H5C_t * cache_ptr); @@ -223,25 +229,61 @@ static void H5C__assert_flush_dep_nocycle(H5C_cache_entry_t * entry, #define H5C__EPOCH_MARKER_TYPE H5C__MAX_NUM_TYPE_IDS -static void *H5C_epoch_marker_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, - void *udata); -static herr_t H5C_epoch_marker_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing, - unsigned *flags_ptr); -static herr_t H5C_epoch_marker_dest(H5F_t *f, void *thing); -static herr_t H5C_epoch_marker_clear(H5F_t *f, void *thing, hbool_t dest); -static herr_t H5C_epoch_marker_notify(H5C_notify_action_t action, void *thing); -static herr_t H5C_epoch_marker_size(const H5F_t *f, const void *thing, size_t *size_ptr); +static herr_t H5C__epoch_marker_get_load_size(const void *image_ptr, + const void *udata_ptr, + size_t *image_len_ptr, + size_t *actual_len, + hbool_t *compressed_ptr, + size_t *compressed_len_ptr); +static htri_t H5C__epoch_marker_verify_chksum(const void *image_ptr, + size_t len, + void *udata_ptr); +static void * H5C__epoch_marker_deserialize(const void * image_ptr, + size_t len, + void * udata, + hbool_t * dirty_ptr); +static herr_t H5C__epoch_marker_image_len(const void * thing, + size_t *image_len_ptr, + hbool_t *compressed_ptr, + size_t *compressed_len_ptr); +static herr_t H5C__epoch_marker_pre_serialize(const H5F_t *f, + hid_t dxpl_id, + void * thing, + haddr_t addr, + size_t len, + size_t compressed_len, + haddr_t * new_addr_ptr, + size_t * new_len_ptr, + size_t * new_compressed_len_ptr, + unsigned * flags_ptr); +static herr_t H5C__epoch_marker_serialize(const H5F_t *f, + void * image_ptr, + size_t len, + void * thing); +static herr_t H5C__epoch_marker_notify(H5C_notify_action_t action, void *thing); +static herr_t H5C__epoch_marker_free_icr(void * thing); + +static herr_t H5C__epoch_marker_clear(const H5F_t *f, void * thing, + hbool_t about_to_destroy); +static herr_t H5C__epoch_marker_fsf_size(const void H5_ATTR_UNUSED * thing, + size_t H5_ATTR_UNUSED * fsf_size_ptr); const H5C_class_t epoch_marker_class = { - /* id = */ H5C__EPOCH_MARKER_TYPE, - /* load = */ &H5C_epoch_marker_load, - /* flush = */ &H5C_epoch_marker_flush, - /* dest = */ &H5C_epoch_marker_dest, - /* clear = */ &H5C_epoch_marker_clear, - /* notify = */&H5C_epoch_marker_notify, - /* size = */ &H5C_epoch_marker_size + /* id = */ H5C__EPOCH_MARKER_TYPE, + /* name = */ "epoch marker", + /* mem_type = */ H5FD_MEM_DEFAULT, /* value doesn't matter */ + /* flags = */ H5AC__CLASS_NO_FLAGS_SET, + /* get_load_size = */ H5C__epoch_marker_get_load_size, + /* verify_chksum = */ H5C__epoch_marker_verify_chksum, + /* deserialize = */ H5C__epoch_marker_deserialize, + /* image_len = */ H5C__epoch_marker_image_len, + /* pre_serialize = */ H5C__epoch_marker_pre_serialize, + /* serialize = */ H5C__epoch_marker_serialize, + /* notify = */ H5C__epoch_marker_notify, + /* free_icr = */ H5C__epoch_marker_free_icr, + /* clear = */ H5C__epoch_marker_clear, + /* fsf_size = */ H5C__epoch_marker_fsf_size, }; @@ -254,107 +296,127 @@ const H5C_class_t epoch_marker_class = * JRM - 11/16/04 * ***************************************************************************/ - -static void * -H5C_epoch_marker_load(H5F_t H5_ATTR_UNUSED * f, - hid_t H5_ATTR_UNUSED dxpl_id, - haddr_t H5_ATTR_UNUSED addr, - void H5_ATTR_UNUSED * udata) +static herr_t +H5C__epoch_marker_get_load_size(const void H5_ATTR_UNUSED *image_ptr, const void H5_ATTR_UNUSED *udata_ptr, + size_t H5_ATTR_UNUSED *image_len_ptr, size_t H5_ATTR_UNUSED *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_len_ptr) { - void * ret_value = NULL; /* Return value */ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ - FUNC_ENTER_NOAPI_NOINIT + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "called unreachable fcn.") + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__epoch_marker_get_load_size() */ -done: + +static htri_t +H5C__epoch_marker_verify_chksum(const void H5_ATTR_UNUSED *image_ptr, size_t H5_ATTR_UNUSED len, + void H5_ATTR_UNUSED *udata_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ - FUNC_LEAVE_NOAPI(ret_value) -} + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + FUNC_LEAVE_NOAPI(FALSE) +} /* end H5C__epoch_marker_verify_chksum() */ -static herr_t -H5C_epoch_marker_flush(H5F_t H5_ATTR_UNUSED *f, - hid_t H5_ATTR_UNUSED dxpl_id, - hbool_t H5_ATTR_UNUSED dest, - haddr_t H5_ATTR_UNUSED addr, - void H5_ATTR_UNUSED *thing, - unsigned H5_ATTR_UNUSED * flags_ptr) +static void * +H5C__epoch_marker_deserialize(const void H5_ATTR_UNUSED * image_ptr, size_t H5_ATTR_UNUSED len, + void H5_ATTR_UNUSED * udata, hbool_t H5_ATTR_UNUSED * dirty_ptr) { - herr_t ret_value = FAIL; /* Return value */ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ - FUNC_ENTER_NOAPI_NOINIT + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "called unreachable fcn.") + FUNC_LEAVE_NOAPI(NULL) +} /* end H5C__epoch_marker_deserialize() */ -done: + +static herr_t +H5C__epoch_marker_image_len(const void H5_ATTR_UNUSED *thing, + size_t H5_ATTR_UNUSED *image_len_ptr, hbool_t H5_ATTR_UNUSED *compressed_ptr, + size_t H5_ATTR_UNUSED *compressed_len_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ - FUNC_LEAVE_NOAPI(ret_value) -} + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__epoch_marker_image_len() */ static herr_t -H5C_epoch_marker_dest(H5F_t H5_ATTR_UNUSED * f, - void H5_ATTR_UNUSED * thing) +H5C__epoch_marker_pre_serialize(const H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, + void H5_ATTR_UNUSED *thing, haddr_t H5_ATTR_UNUSED addr, size_t H5_ATTR_UNUSED len, + size_t H5_ATTR_UNUSED compressed_len, haddr_t H5_ATTR_UNUSED *new_addr_ptr, + size_t H5_ATTR_UNUSED *new_len_ptr, size_t H5_ATTR_UNUSED *new_compressed_len_ptr, + unsigned H5_ATTR_UNUSED *flags_ptr) { - herr_t ret_value = FAIL; /* Return value */ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ - FUNC_ENTER_NOAPI_NOINIT - - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "called unreachable fcn.") - -done: + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); - FUNC_LEAVE_NOAPI(ret_value) -} + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__epoch_marker_pre_serialize() */ + static herr_t -H5C_epoch_marker_clear(H5F_t H5_ATTR_UNUSED * f, - void H5_ATTR_UNUSED * thing, - hbool_t H5_ATTR_UNUSED dest) +H5C__epoch_marker_serialize(const H5F_t H5_ATTR_UNUSED *f, void H5_ATTR_UNUSED *image_ptr, + size_t H5_ATTR_UNUSED len, void H5_ATTR_UNUSED *thing) { - herr_t ret_value = FAIL; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT - - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "called unreachable fcn.") + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ -done: + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); - FUNC_LEAVE_NOAPI(ret_value) -} + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__epoch_marker_serialize() */ + static herr_t -H5C_epoch_marker_notify(H5C_notify_action_t H5_ATTR_UNUSED action, +H5C__epoch_marker_notify(H5C_notify_action_t H5_ATTR_UNUSED action, void H5_ATTR_UNUSED * thing) { - herr_t ret_value = FAIL; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "called unreachable fcn.") + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); -done: - FUNC_LEAVE_NOAPI(ret_value) -} + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__epoch_marker_notify() */ + static herr_t -H5C_epoch_marker_size(const H5F_t H5_ATTR_UNUSED * f, - const void H5_ATTR_UNUSED * thing, - size_t H5_ATTR_UNUSED * size_ptr) +H5C__epoch_marker_free_icr(void H5_ATTR_UNUSED * thing) { - herr_t ret_value = FAIL; /* Return value */ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ - FUNC_ENTER_NOAPI_NOINIT + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "called unreachable fcn.") + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__epoch_marker_free_icr() */ -done: + +static herr_t +H5C__epoch_marker_clear(const H5F_t H5_ATTR_UNUSED *f, void H5_ATTR_UNUSED * thing, hbool_t H5_ATTR_UNUSED about_to_destroy) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__epoch_marker_clear() */ + + +static herr_t +H5C__epoch_marker_fsf_size(const void H5_ATTR_UNUSED * thing, size_t H5_ATTR_UNUSED *fsf_size_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__epoch_marker_fsf_size() */ - FUNC_LEAVE_NOAPI(ret_value) -} /*------------------------------------------------------------------------- @@ -438,21 +500,46 @@ done: * Programmer: John Mainzer * 3/17/10 * + * Changes: Ported code to detect next entry status changes as the + * the result of a flush from the serial code in the scan of + * the LRU. Also added code to detect and adapt to the + * removal from the cache of the next entry in the scan of + * the LRU. + * + * Note that at present, all of these changes should not + * be required as the operations on entries as they are + * flushed that can cause these condiditions are not premitted + * in the parallel case. However, Quincey indicates that + * this may change, and thus has requested the modification. + * + * Note the assert(FALSE) in the if statement whose body + * restarts the scan of the LRU. As the body of the if + * statement should be unreachable, it should never be + * triggered until the constraints on the parallel case + * are relaxed. Please remove the assertion at that time. + * + * Also added warning on the Pinned Entry List scan, as it + * is potentially subject to the same issue. As there is + * no cognate of this scan in the serial code, I don't have + * a fix to port to it. + * + * JRM -- 4/10/19 + * *------------------------------------------------------------------------- */ #ifdef H5_HAVE_PARALLEL #define H5C_APPLY_CANDIDATE_LIST__DEBUG 0 herr_t H5C_apply_candidate_list(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, + hid_t dxpl_id, H5C_t * cache_ptr, int num_candidates, haddr_t * candidates_list_ptr, int mpi_rank, int mpi_size) { - hbool_t first_flush = FALSE; + hbool_t restart_scan; + hbool_t prev_is_dirty; int i; int m; int n; @@ -472,6 +559,7 @@ H5C_apply_candidate_list(H5F_t * f, int * candidate_assignment_table = NULL; haddr_t addr; H5C_cache_entry_t * clear_ptr = NULL; + H5C_cache_entry_t * next_ptr = NULL; H5C_cache_entry_t * entry_ptr = NULL; H5C_cache_entry_t * flush_ptr = NULL; H5C_cache_entry_t * delayed_ptr = NULL; @@ -649,16 +737,29 @@ H5C_apply_candidate_list(H5F_t * f, * should be reworked to account for additional cases. * ===================================================================== */ + HDassert(entries_to_flush >= 0); + + restart_scan = FALSE; entries_examined = 0; initial_list_len = cache_ptr->LRU_list_len; entry_ptr = cache_ptr->LRU_tail_ptr; /* Examine each entry in the LRU list */ - while((entry_ptr != NULL) && (entries_examined <= initial_list_len) && - ((entries_cleared + entries_flushed) < num_candidates)) { + while ( ( entry_ptr != NULL ) + && + ( entries_examined <= (entries_to_flush + 1) * initial_list_len ) + && + ( (entries_cleared + entries_flushed) < num_candidates ) ) { + + if ( entry_ptr->prev != NULL ) + prev_is_dirty = entry_ptr->prev->is_dirty; /* If this process needs to clear this entry. */ if(entry_ptr->clear_on_unprotect) { + + HDassert(entry_ptr->is_dirty); + + next_ptr = entry_ptr->next; entry_ptr->clear_on_unprotect = FALSE; clear_ptr = entry_ptr; entry_ptr = entry_ptr->prev; @@ -669,20 +770,26 @@ H5C_apply_candidate_list(H5F_t * f, (long long)clear_ptr->addr); #endif /* H5C_APPLY_CANDIDATE_LIST__DEBUG */ + /* No need to check for the next entry in the scan being + * removed from the cache, as this call to H5C_flush_single_entry() + * will not call either the pre_serialize or serialize callbacks. + */ + if(H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - clear_ptr->type, + dxpl_id, clear_ptr->addr, H5C__FLUSH_CLEAR_ONLY_FLAG, - &first_flush, - TRUE) < 0) + TRUE, + NULL) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't clear entry.") } /* end if */ /* Else, if this process needs to flush this entry. */ else if (entry_ptr->flush_immediately) { + HDassert(entry_ptr->is_dirty); + + next_ptr = entry_ptr->next; entry_ptr->flush_immediately = FALSE; flush_ptr = entry_ptr; entry_ptr = entry_ptr->prev; @@ -693,22 +800,94 @@ H5C_apply_candidate_list(H5F_t * f, (long long)flush_ptr->addr); #endif /* H5C_APPLY_CANDIDATE_LIST__DEBUG */ + /* reset entries_removed_counter and + * last_entry_removed_ptr prior to the call to + * H5C_flush_single_entry() so that we can spot + * unexpected removals of entries from the cache, + * and set the restart_scan flag if proceeding + * would be likely to cause us to scan an entry + * that is no longer in the cache. + * + * Note that as of this writing (April 2015) this + * case cannot occur in the parallel case. However + * Quincey is making noises about changing this, hence + * the insertion of this test. + * + * Note also that there is no test code to verify + * that this code actually works (although similar code + * in the serial version exists and is tested). + * + * Implementing a test will likely require implementing + * flush op like facilities in the parallel tests. At + * a guess this will not be terribly painful, but it + * will take a bit of time. + */ + cache_ptr->entries_removed_counter = 0; + cache_ptr->last_entry_removed_ptr = NULL; + if(H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - flush_ptr->type, + dxpl_id, flush_ptr->addr, H5C__NO_FLAGS_SET, - &first_flush, - TRUE) < 0) + TRUE, + NULL) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't flush entry.") + + if ( ( cache_ptr->entries_removed_counter > 1 ) || + ( cache_ptr->last_entry_removed_ptr == entry_ptr ) ) + + restart_scan = TRUE; + } /* end else-if */ /* Otherwise, no action to be taken on this entry. Grab the next. */ else { entry_ptr = entry_ptr->prev; + + if ( entry_ptr != NULL ) + next_ptr = entry_ptr->next; + } /* end else */ + if ( ( entry_ptr != NULL ) + && + ( ( restart_scan ) + || + ( entry_ptr->is_dirty != prev_is_dirty ) + || + ( entry_ptr->next != next_ptr ) + || + ( entry_ptr->is_protected ) + || + ( entry_ptr->is_pinned ) + ) + ) { + + /* something has happened to the LRU -- start over + * from the tail. + * + * Recall that this code should be un-reachable at present, + * as all the operations by entries on flush that could cause + * it to be reachable are disallowed in the parallel case at + * present. Hence the following assertion which should be + * removed if the above changes. + */ + + HDassert( ! restart_scan ); + HDassert( entry_ptr->is_dirty == prev_is_dirty ); + HDassert( entry_ptr->next == next_ptr ); + HDassert( ! entry_ptr->is_protected ); + HDassert( ! entry_ptr->is_pinned ); + + HDassert(FALSE); /* see comment above */ + + restart_scan = FALSE; + entry_ptr = cache_ptr->LRU_tail_ptr; +/* + H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr) +*/ + } + entries_examined++; } /* end while */ @@ -720,6 +899,30 @@ H5C_apply_candidate_list(H5F_t * f, /* It is also possible that some of the cleared entries are on the * pinned list. Must scan that also. + * + * WARNING: + * + * As we now allow unpinning, and removal of other entries as a side + * effect of flushing an entry, it is possible that the next entry + * in a PEL scan could either be no longer pinned, or no longer in + * the cache by the time we get to it. + * + * At present, this is not possible in this case, as we disallow such + * operations in the parallel version of the library. However, Quincey + * has been making noises about relaxing this. If and when he does, + * we have a potential problem here. + * + * The same issue exists in the serial cache, and there are tests + * to detect this problem when it occurs, and adjust to it. As seen + * above in the LRU scan, I have ported such tests to the parallel + * code where a close cognate exists in the serial code. + * + * I haven't done so here, as there are no PEL scans where the problem + * can occur in the serial code. Needless to say, this will have to + * be repaired if the constraints on pre_serialize and serialize + * callbacks are relaxed in the parallel version of the metadata cache. + * + * JRM -- 4/1/15 */ #if H5C_APPLY_CANDIDATE_LIST__DEBUG @@ -787,14 +990,12 @@ H5C_apply_candidate_list(H5F_t * f, #endif /* H5C_APPLY_CANDIDATE_LIST__DEBUG */ if(H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - clear_ptr->type, - clear_ptr->addr, - H5C__FLUSH_CLEAR_ONLY_FLAG, - &first_flush, - TRUE) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't clear entry.") + dxpl_id, + clear_ptr->addr, + H5C__FLUSH_CLEAR_ONLY_FLAG, + TRUE, + NULL) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't clear entry.") } /* end else-if */ /* Else, if this process needs to independently flush this entry. */ @@ -810,14 +1011,12 @@ H5C_apply_candidate_list(H5F_t * f, #endif /* H5C_APPLY_CANDIDATE_LIST__DEBUG */ if(H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - flush_ptr->type, - flush_ptr->addr, - H5C__NO_FLAGS_SET, - &first_flush, - TRUE) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't flush entry.") + dxpl_id, + flush_ptr->addr, + H5C__NO_FLAGS_SET, + TRUE, + NULL) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't clear entry.") } /* end else-if */ } /* end if */ @@ -858,13 +1057,11 @@ H5C_apply_candidate_list(H5F_t * f, } /* end if */ if(H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - delayed_ptr->type, + dxpl_id, delayed_ptr->addr, H5C__NO_FLAGS_SET, - &first_flush, - TRUE) < 0) + TRUE, + NULL) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't flush entry collectively.") @@ -1208,6 +1405,9 @@ H5C_create(size_t max_cache_size, /* Tagging Field Initializations */ cache_ptr->ignore_tags = FALSE; + cache_ptr->slist_changed = FALSE; + cache_ptr->slist_change_in_pre_serialize = FALSE; + cache_ptr->slist_change_in_serialize = FALSE; cache_ptr->slist_len = 0; cache_ptr->slist_size = (size_t)0; @@ -1221,6 +1421,9 @@ H5C_create(size_t max_cache_size, (cache_ptr->index)[i] = NULL; } + cache_ptr->entries_removed_counter = 0; + cache_ptr->last_entry_removed_ptr = NULL; + cache_ptr->pl_len = 0; cache_ptr->pl_size = (size_t)0; cache_ptr->pl_head_ptr = NULL; @@ -1295,11 +1498,8 @@ H5C_create(size_t max_cache_size, /* Set non-zero/FALSE/NULL fields for epoch markers */ for ( i = 0; i < H5C__MAX_EPOCH_MARKERS; i++ ) { - (cache_ptr->epoch_marker_active)[i] = FALSE; -#ifndef NDEBUG ((cache_ptr->epoch_markers)[i]).magic = H5C__H5C_CACHE_ENTRY_T_MAGIC; -#endif /* NDEBUG */ ((cache_ptr->epoch_markers)[i]).addr = (haddr_t)i; ((cache_ptr->epoch_markers)[i]).type = &epoch_marker_class; } @@ -1586,9 +1786,7 @@ H5C_free_cork_list_cb(void *_item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *------------------------------------------------------------------------- */ herr_t -H5C_dest(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id) +H5C_dest(H5F_t * f, hid_t dxpl_id) { H5C_t * cache_ptr = f->shared->cache; herr_t ret_value = SUCCEED; /* Return value */ @@ -1600,8 +1798,7 @@ H5C_dest(H5F_t * f, HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); /* Flush and invalidate all cache entries */ - if(H5C_flush_invalidate_cache(f, primary_dxpl_id, secondary_dxpl_id, - H5C__NO_FLAGS_SET) < 0 ) + if(H5C_flush_invalidate_cache(f, dxpl_id, H5C__NO_FLAGS_SET) < 0 ) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache") if(cache_ptr->slist_ptr != NULL) { @@ -1631,7 +1828,9 @@ H5C_dest(H5F_t * f, #endif /* H5C_DO_SANITY_CHECKS */ #endif /* NDEBUG */ +#ifndef NDEBUG cache_ptr->magic = 0; +#endif /* NDEBUG */ cache_ptr = H5FL_FREE(H5C_t, cache_ptr); @@ -1652,9 +1851,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5C_evict(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id) +H5C_evict(H5F_t * f, hid_t dxpl_id) { H5C_t *cache_ptr = f->shared->cache; herr_t ret_value = SUCCEED; /* Return value */ @@ -1666,8 +1863,7 @@ H5C_evict(H5F_t * f, HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); /* Flush and invalidate all cache entries except the pinned entries */ - if(H5C_flush_invalidate_cache(f, primary_dxpl_id, secondary_dxpl_id, - H5C__EVICT_ALLOW_LAST_PINS_FLAG) < 0 ) + if(H5C_flush_invalidate_cache(f, dxpl_id, H5C__EVICT_ALLOW_LAST_PINS_FLAG) < 0 ) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to evict entries in the cache") done: @@ -1690,17 +1886,16 @@ done: *------------------------------------------------------------------------- */ herr_t -H5C_expunge_entry(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - const H5C_class_t * type, - haddr_t addr, - unsigned flags) +H5C_expunge_entry(H5F_t *f, hid_t dxpl_id, const H5C_class_t *type, + haddr_t addr, unsigned flags) { H5C_t * cache_ptr; - herr_t result; - hbool_t first_flush = TRUE; H5C_cache_entry_t * entry_ptr = NULL; + unsigned flush_flags = (H5C__FLUSH_INVALIDATE_FLAG | H5C__FLUSH_CLEAR_ONLY_FLAG); +#if H5C_DO_SANITY_CHECKS + hbool_t entry_was_dirty; + hsize_t entry_size; +#endif /* H5C_DO_SANITY_CHECKS */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) @@ -1711,8 +1906,6 @@ H5C_expunge_entry(H5F_t * f, HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(type); - HDassert(type->clear); - HDassert(type->dest); HDassert(H5F_addr_defined(addr)); #if H5C_DO_EXTREME_SANITY_CHECKS @@ -1736,27 +1929,34 @@ H5C_expunge_entry(H5F_t * f, if(entry_ptr->is_pinned) HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "Target entry is pinned.") - /* Pass along 'free file space' flag to cache client */ - entry_ptr->free_file_space_on_destroy = ( (flags & H5C__FREE_FILE_SPACE_FLAG) != 0 ); - /* If we get this far, call H5C_flush_single_entry() with the * H5C__FLUSH_INVALIDATE_FLAG and the H5C__FLUSH_CLEAR_ONLY_FLAG. * This will clear the entry, and then delete it from the cache. */ - result = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - entry_ptr->type, - entry_ptr->addr, - H5C__FLUSH_INVALIDATE_FLAG | H5C__FLUSH_CLEAR_ONLY_FLAG, - &first_flush, - TRUE); - if ( result < 0 ) { + /* Pass along 'free file space' flag to cache client. */ + flush_flags |= (flags & H5C__FREE_FILE_SPACE_FLAG); + +#if H5C_DO_SANITY_CHECKS + entry_was_dirty = entry_ptr->is_dirty; + entry_size = entry_ptr->size; +#endif /* H5C_DO_EXTREME_SANITY_CHECKS */ - HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, \ - "H5C_flush_single_entry() failed.") + if(H5C_flush_single_entry(f, dxpl_id, entry_ptr->addr, flush_flags, TRUE, NULL) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "H5C_flush_single_entry() failed.") + +#if H5C_DO_SANITY_CHECKS + if ( entry_was_dirty ) + { + /* we have just removed an entry from the skip list. Thus + * we must touch up cache_ptr->slist_len_increase and + * cache_ptr->slist_size_increase to keep from skewing + * the sanity checks on flushes. + */ + cache_ptr->slist_len_increase -= 1; + cache_ptr->slist_size_increase -= (int64_t)(entry_size); } +#endif /* H5C_DO_SANITY_CHECKS */ done: #if H5C_DO_EXTREME_SANITY_CHECKS @@ -1793,10 +1993,24 @@ done: * Programmer: John Mainzer * 6/2/04 * + * Changes: Modified function to test for slist chamges in + * pre_serialize and serialize callbacks, and re-start + * scans through the slist when such changes occur. + * + * This has been a potential problem for some time, + * and there has been code in this function to deal + * with elements of this issue. However the shift + * to the V3 cache in combination with the activities + * of some of the cache clients (in particular the + * free space manager and the fractal heap) have + * made this re-work necessary. + * + * JRM -- 12/13/14 + * *------------------------------------------------------------------------- */ herr_t -H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsigned flags) +H5C_flush_cache(H5F_t *f, hid_t dxpl_id, unsigned flags) { H5C_t * cache_ptr = f->shared->cache; herr_t status; @@ -1804,9 +2018,9 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign hbool_t destroy; hbool_t flushed_entries_last_pass; hbool_t flush_marked_entries; - hbool_t first_flush = TRUE; hbool_t ignore_protected; hbool_t tried_to_flush_protected_entry = FALSE; + hbool_t restart_slist_scan; int32_t protected_entries = 0; H5SL_node_t * node_ptr = NULL; H5C_cache_entry_t * entry_ptr = NULL; @@ -1816,6 +2030,10 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign int64_t flushed_entries_size = 0; int64_t initial_slist_len = 0; size_t initial_slist_size = 0; + int64_t entry_size_change; + int64_t * entry_size_change_ptr = &entry_size_change; +#else /* H5C_DO_SANITY_CHECKS */ + int64_t * entry_size_change_ptr = NULL; #endif /* H5C_DO_SANITY_CHECKS */ FUNC_ENTER_NOAPI(FAIL) @@ -1852,10 +2070,7 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign if ( destroy ) { - status = H5C_flush_invalidate_cache(f, - primary_dxpl_id, - secondary_dxpl_id, - flags); + status = H5C_flush_invalidate_cache(f, dxpl_id, flags); if ( status < 0 ) { @@ -1874,23 +2089,23 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign flushed_entries_last_pass = TRUE; + /* set the cache_ptr->slist_change_in_pre_serialize and + * cache_ptr->slist_change_in_serialize to false. + * + * These flags are set to TRUE by H5C_flush_single_entry if the + * slist is modified by a pre_serialize or serialize call respectively. + * H5C_flush_cache uses these flags to detect any modifications + * to the slist that might corrupt the scan of the slist -- and + * restart the scan in this event. + */ + cache_ptr->slist_change_in_pre_serialize = FALSE; + cache_ptr->slist_change_in_serialize = FALSE; + while ( ( cache_ptr->slist_len != 0 ) && ( protected_entries == 0 ) && ( flushed_entries_last_pass ) ) { - flushed_entries_last_pass = FALSE; - - /* Start at beginning of skip list each time */ - node_ptr = H5SL_first(cache_ptr->slist_ptr); - HDassert( node_ptr != NULL ); - - /* Get cache entry for this node */ - next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); - 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 ); + flushed_entries_last_pass = FALSE; #if H5C_DO_SANITY_CHECKS /* For sanity checking, try to verify that the skip list has @@ -1900,9 +2115,11 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign * Doing this get a bit tricky, as depending on flags, we may * or may not flush all the entries in the slist. * - * To make things more entertaining, with the advent of the - * fractal heap, the entry flush callback can cause entries - * to be dirtied, resized, and/or moved. + * To make things more entertaining, with the advent of the + * fractal heap, the entry serialize callback can cause entries + * to be dirtied, resized, and/or moved. Also, the + * pre_serialize callback can result in an entry being + * removed from the cache via the take ownership flag. * * To deal with this, we first make note of the initial * skip list length and size: @@ -1917,7 +2134,8 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign flushed_entries_size = 0; /* As mentioned above, there is the possibility that - * entries will be dirtied, resized, and/or flushed during + * entries will be dirtied, resized, flushed, or removed + * from the cache via the take ownership flag during * our pass through the skip list. To capture the number * of entries added, and the skip list size delta, * zero the slist_len_increase and slist_size_increase of @@ -1934,53 +2152,57 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign */ #endif /* H5C_DO_SANITY_CHECKS */ - while ( node_ptr != NULL ) + restart_slist_scan = TRUE; + + while ( ( restart_slist_scan ) || ( node_ptr != NULL ) ) { - entry_ptr = next_entry_ptr; + if ( restart_slist_scan ) + { + restart_slist_scan = FALSE; - /* With the advent of the fractal heap, it is possible - * that the flush callback will dirty and/or resize - * other entries in the cache. In particular, while - * Quincey has promised me that this will never happen, - * it is possible that the flush callback for an - * entry may protect an entry that is not in the cache, - * perhaps causing the cache to flush and possibly - * evict the entry associated with node_ptr to make - * space for the new entry. - * - * Thus we do a bit of extra sanity checking on entry_ptr, - * and break out of this scan of the skip list if we - * detect minor problems. We have a bit of leaway on the - * number of passes though the skip list, so this shouldn't - * be an issue in the flush in and of itself, as it should - * be all but impossible for this to happen more than once - * in any flush. - * - * Observe that that breaking out of the scan early - * shouldn't break the sanity checks just after the end - * of this while loop. - * - * If an entry has merely been marked clean and removed from - * the s-list, we simply break out of the scan. - * - * If the entry has been evicted, we flag an error and - * exit. - */ -#ifndef NDEBUG - if ( entry_ptr->magic != H5C__H5C_CACHE_ENTRY_T_MAGIC ) { + /* Start at beginning of skip list */ + node_ptr = H5SL_first(cache_ptr->slist_ptr); - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "entry_ptr->magic is invalid ?!?!") + if ( node_ptr == NULL ) + { + /* the slist is empty -- break out of inner loop */ + break; + } + HDassert( node_ptr != NULL ); - } else -#endif /* NDEBUG */ - if ( ( ! entry_ptr->is_dirty ) || - ( ! entry_ptr->in_slist ) ) { + /* Get cache entry for this node */ + next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); - /* the s-list has been modified out from under us. - * break out of the loop. - */ - goto end_of_inner_loop;; - } + 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 ); + } + + entry_ptr = next_entry_ptr; + + /* With the advent of the fractal heap, the free space + * manager, and the version 3 cache, it is possible + * that the pre-serialize or serialize callback will + * dirty, resize, or take ownership of other entries + * in the cache. + * + * To deal with this, I have inserted code to detect any + * change in the skip list not directly under the control + * of this function. If such modifications are detected, + * we must re-start the scan of the skip list to avoid + * the possibility that the target of the next_entry_ptr + * may have been flushed or deleted from the cache. + * + * To verify that all such possibilities have been dealt + * with, we do a bit of extra sanity checking on + * entry_ptr. + */ + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(entry_ptr->in_slist); + HDassert(entry_ptr->is_dirty); /* increment node pointer now, before we delete its target * from the slist. @@ -1994,6 +2216,7 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign HDassert( next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC ); HDassert( next_entry_ptr->is_dirty ); HDassert( next_entry_ptr->in_slist ); + HDassert( entry_ptr != next_entry_ptr ); } else { next_entry_ptr = NULL; } @@ -2013,11 +2236,10 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign ( entry_ptr->flush_dep_ndirty_children == 0 ) ) ) ) { if ( entry_ptr->is_protected ) { - - /* we probably have major problems -- but lets flush - * everything we can before we decide whether to flag - * an error. - */ + /* we probably have major problems -- but lets + * flush everything we can before we decide + * whether to flag an error. + */ tried_to_flush_protected_entry = TRUE; protected_entries++; @@ -2025,15 +2247,14 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign #if H5C_DO_SANITY_CHECKS flushed_entries_count++; flushed_entries_size += (int64_t)entry_ptr->size; + entry_size_change = 0; #endif /* H5C_DO_SANITY_CHECKS */ status = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - NULL, - entry_ptr->addr, - flags, - &first_flush, - FALSE); + dxpl_id, + entry_ptr->addr, + flags, + FALSE, + entry_size_change_ptr); if ( status < 0 ) { /* This shouldn't happen -- if it does, we are toast @@ -2042,21 +2263,45 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ "dirty pinned entry flush failed.") } /* end if */ +#if H5C_DO_SANITY_CHECKS + /* it is possible that the entry size changed + * during flush -- update flushed_entries_size + * to account for this. + */ + flushed_entries_size += entry_size_change; +#endif /* H5C_DO_SANITY_CHECKS */ + + if ((cache_ptr->slist_change_in_serialize) || + (cache_ptr->slist_change_in_pre_serialize)) + { + /* The slist has been modified by something + * other than the simple removal of the + * of the flushed entry after the flush. + * + * This has the potential to corrupt the + * scan through the slist, so restart it. + */ + restart_slist_scan = TRUE; + cache_ptr->slist_change_in_pre_serialize = FALSE; + cache_ptr->slist_change_in_serialize = FALSE; + + H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr) + } + flushed_entries_last_pass = TRUE; } /* end if */ else { #if H5C_DO_SANITY_CHECKS flushed_entries_count++; flushed_entries_size += (int64_t)entry_ptr->size; + entry_size_change = 0; #endif /* H5C_DO_SANITY_CHECKS */ status = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - NULL, - entry_ptr->addr, - flags, - &first_flush, - FALSE); + dxpl_id, + entry_ptr->addr, + flags, + FALSE, + entry_size_change_ptr); if ( status < 0 ) { /* This shouldn't happen -- if it does, we are @@ -2065,14 +2310,36 @@ H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, unsign HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ "Can't flush entry.") } - flushed_entries_last_pass = TRUE; + +#if H5C_DO_SANITY_CHECKS + /* it is possible that the entry size changed + * during flush -- update flushed_entries_size + * to account for this. + */ + flushed_entries_size += entry_size_change; +#endif /* H5C_DO_SANITY_CHECKS */ + if ((cache_ptr->slist_change_in_serialize) || + (cache_ptr->slist_change_in_pre_serialize)) + { + /* The slist has been modified by something + * other than the simple removal of the + * of the flushed entry after the flush. + * + * This has the potential to corrupt the + * scan through the slist, so restart it. + */ + restart_slist_scan = TRUE; + cache_ptr->slist_change_in_pre_serialize = FALSE; + cache_ptr->slist_change_in_serialize = FALSE; + + H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr) + } + + flushed_entries_last_pass = TRUE; } /* end else */ } /* end if */ - } /* while ( node_ptr != NULL ) */ -/* Note the extra ; is necessary so the label is not at the end of the compound - * statement (the while loop), which is illegal */ -end_of_inner_loop:; - + } /* while ( ( restart_slist_scan ) || ( node_ptr != NULL ) ) */ + #if H5C_DO_SANITY_CHECKS /* Verify that the slist size and length are as expected. */ @@ -2140,12 +2407,10 @@ done: */ herr_t H5C_flush_to_min_clean(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id) + hid_t dxpl_id) { H5C_t * cache_ptr; herr_t result; - hbool_t first_flush = TRUE; hbool_t write_permitted; #if 0 /* modified code -- commented out for now */ int i; @@ -2188,11 +2453,9 @@ H5C_flush_to_min_clean(H5F_t * f, } #if 1 /* original code */ result = H5C_make_space_in_cache(f, - primary_dxpl_id, - secondary_dxpl_id, + dxpl_id, (size_t)0, - write_permitted, - &first_flush); + write_permitted); if ( result < 0 ) { @@ -3008,8 +3271,7 @@ done: */ herr_t H5C_insert_entry(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, + hid_t dxpl_id, const H5C_class_t * type, haddr_t addr, void * thing, @@ -3017,7 +3279,6 @@ H5C_insert_entry(H5F_t * f, { H5C_t * cache_ptr; herr_t result; - hbool_t first_flush = TRUE; hbool_t insert_pinned; hbool_t flush_last; #ifdef H5_HAVE_PARALLEL @@ -3040,8 +3301,6 @@ H5C_insert_entry(H5F_t * f, HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); HDassert( type ); - HDassert( type->flush ); - HDassert( type->size ); HDassert( H5F_addr_defined(addr) ); HDassert( thing ); @@ -3080,15 +3339,16 @@ H5C_insert_entry(H5F_t * f, HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "duplicate entry in cache.") } /* end if */ -#ifndef NDEBUG entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC; -#endif /* NDEBUG */ entry_ptr->cache_ptr = cache_ptr; entry_ptr->addr = addr; entry_ptr->type = type; + entry_ptr->image_ptr = NULL; + entry_ptr->image_up_to_date = FALSE; + /* Apply tag to newly inserted entry */ - if(H5C_tag_entry(cache_ptr, entry_ptr, primary_dxpl_id) < 0) + if(H5C_tag_entry(cache_ptr, entry_ptr, dxpl_id) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "Cannot tag entry") /* Set the entry's cork status */ @@ -3113,10 +3373,27 @@ H5C_insert_entry(H5F_t * f, /* not protected, so can't be dirtied */ entry_ptr->dirtied = FALSE; - /* Retrieve the size of the thing */ - if((type->size)(f, thing, &(entry_ptr->size)) < 0) + /* Retrieve the size of the thing. Set the compressed field to FALSE + * and the compressed_size field to zero first, as they may not be + * initialized by the image_len call. + */ + entry_ptr->compressed = FALSE; + entry_ptr->compressed_size = 0; + if((type->image_len)(thing, &(entry_ptr->size), &(entry_ptr->compressed), + &(entry_ptr->compressed_size)) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGETSIZE, FAIL, "Can't get size of thing") HDassert(entry_ptr->size > 0 && entry_ptr->size < H5C_MAX_ENTRY_SIZE); + HDassert(((type->flags & H5C__CLASS_COMPRESSED_FLAG) != 0) || + (entry_ptr->compressed == FALSE)); + + /* entry has just been inserted -- thus compressed size cannot have + * been computed yet. Thus if entry_ptr->compressed is TRUE, + * entry_ptr->size must equal entry_ptr->compressed_size. + */ + HDassert((entry_ptr->compressed == FALSE) || + (entry_ptr->size == entry_ptr->compressed_size)); + HDassert((entry_ptr->compressed == TRUE) || + (entry_ptr->compressed_size == 0)); entry_ptr->in_slist = FALSE; @@ -3127,7 +3404,6 @@ H5C_insert_entry(H5F_t * f, entry_ptr->flush_in_progress = FALSE; entry_ptr->destroy_in_progress = FALSE; - entry_ptr->free_file_space_on_destroy = FALSE; /* Initialize flush dependency height fields */ entry_ptr->flush_dep_parent = NULL; @@ -3227,11 +3503,9 @@ H5C_insert_entry(H5F_t * f, */ result = H5C_make_space_in_cache(f, - primary_dxpl_id, - secondary_dxpl_id, + dxpl_id, space_needed, - write_permitted, - &first_flush); + write_permitted); if ( result < 0 ) { @@ -3323,18 +3597,39 @@ done: * Programmer: John Mainzer * 7/5/05 * + * Changes: Tidied up code, removeing some old commented out + * code that had been left in pending success of the + * new version. + * + * Note that unlike H5C_apply_candidate_list(), + * H5C_mark_entries_as_clean() makes all its calls to + * H6C_flush_single_entry() with the + * H5C__FLUSH_CLEAR_ONLY_FLAG set. As a result, + * the pre_serialize() and serialize calls are not made. + * + * This then implies that (assuming such actions were + * permitted in the parallel case) no loads, dirties, + * resizes, or removals of other entries can occur as + * a side effect of the flush. Hence, there is no need + * for the checks for entry removal / status change + * that I ported to H5C_apply_candidate_list(). + * + * However, if (in addition to allowing such operations + * in the parallel case), we allow such operations outside + * of the pre_serialize / serialize routines, this may + * cease to be the case -- requiring a review of this + * function. + * *------------------------------------------------------------------------- */ #ifdef H5_HAVE_PARALLEL herr_t H5C_mark_entries_as_clean(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, + hid_t dxpl_id, int32_t ce_array_len, haddr_t * ce_array_ptr) { H5C_t * cache_ptr; - hbool_t first_flush = TRUE; int entries_cleared; int entries_examined; int i; @@ -3428,27 +3723,9 @@ H5C_mark_entries_as_clean(H5F_t * f, #endif /* H5C_DO_SANITY_CHECKS */ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "Listed entry not dirty?!?!?.") -#if 0 /* original code */ - } else if ( entry_ptr->is_protected ) { - - entry_ptr->clear_on_unprotect = TRUE; } else { - if ( H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - entry_ptr->type, - addr, - H5C__FLUSH_CLEAR_ONLY_FLAG, - &first_flush, - TRUE) < 0 ) { - - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't clear entry.") - } - } -#else /* modified code */ - } else { /* Mark the entry to be cleared on unprotect. We will * scan the LRU list shortly, and clear all those entries * not currently protected. @@ -3469,13 +3746,32 @@ H5C_mark_entries_as_clean(H5F_t * f, } #endif /* H5C_DO_SANITY_CHECKS */ } -#endif /* end modified code */ } -#if 1 /* modified code */ + /* Scan through the LRU list from back to front, and flush the * entries whose clear_on_unprotect flags are set. Observe that * any protected entries will not be on the LRU, and therefore * will not be flushed at this time. + * + * Note that unlike H5C_apply_candidate_list(), + * H5C_mark_entries_as_clean() makes all its calls to + * H6C_flush_single_entry() with the H5C__FLUSH_CLEAR_ONLY_FLAG + * set. As a result, the pre_serialize() and serialize calls are + * not made. + * + * This then implies that (assuming such actions were + * permitted in the parallel case) no loads, dirties, + * resizes, or removals of other entries can occur as + * a side effect of the flush. Hence, there is no need + * for the checks for entry removal / status change + * that I ported to H5C_apply_candidate_list(). + * + * However, if (in addition to allowing such operations + * in the parallel case), we allow such operations outside + * of the pre_serialize / serialize routines, this may + * cease to be the case -- requiring a review of this + * point. + * JRM -- 4/7/15 */ entries_cleared = 0; @@ -3495,13 +3791,11 @@ H5C_mark_entries_as_clean(H5F_t * f, entries_cleared++; if ( H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - clear_ptr->type, + dxpl_id, clear_ptr->addr, H5C__FLUSH_CLEAR_ONLY_FLAG, - &first_flush, - TRUE) < 0 ) { + TRUE, + NULL) < 0 ) { HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't clear entry.") } @@ -3532,13 +3826,11 @@ H5C_mark_entries_as_clean(H5F_t * f, entries_cleared++; if ( H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - clear_ptr->type, + dxpl_id, clear_ptr->addr, H5C__FLUSH_CLEAR_ONLY_FLAG, - &first_flush, - TRUE) < 0 ) { + TRUE, + NULL) < 0 ) { HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't clear entry.") } @@ -3569,7 +3861,6 @@ H5C_mark_entries_as_clean(H5F_t * f, } HDassert( (entries_cleared + i) == ce_array_len ); #endif /* H5C_DO_SANITY_CHECKS */ -#endif /* modified code */ done: @@ -3645,6 +3936,7 @@ H5C_mark_entry_dirty(void *thing) /* mark the entry as dirty if it isn't already */ entry_ptr->is_dirty = TRUE; + entry_ptr->image_up_to_date = FALSE; /* Propagate the dirty flag up the flush dependency chain if appropriate */ @@ -3701,7 +3993,7 @@ H5C_move_entry(H5C_t * cache_ptr, haddr_t old_addr, haddr_t new_addr) { - hbool_t was_dirty; + hbool_t was_dirty; H5C_cache_entry_t * entry_ptr = NULL; H5C_cache_entry_t * test_entry_ptr = NULL; #if H5C_DO_SANITY_CHECKS @@ -3801,10 +4093,12 @@ H5C_move_entry(H5C_t * cache_ptr, if ( ! ( entry_ptr->destroy_in_progress ) ) { was_dirty = entry_ptr->is_dirty; + entry_ptr->is_dirty = TRUE; - if ( ! ( entry_ptr->flush_in_progress ) ) { + /* This shouldn't be needed, but it keeps the test code happy */ + entry_ptr->image_up_to_date = FALSE; - entry_ptr->is_dirty = TRUE; + if ( ! ( entry_ptr->flush_in_progress ) ) { /* Propagate the dirty flag up the flush dependency chain if * appropriate */ @@ -3824,29 +4118,26 @@ H5C_move_entry(H5C_t * cache_ptr, H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL) - if ( ! ( entry_ptr->flush_in_progress ) ) { - - H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) + H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) #if H5C_DO_SANITY_CHECKS - if ( removed_entry_from_slist ) { + if ( removed_entry_from_slist ) { - /* we just removed the entry from the slist. Thus we - * must touch up cache_ptr->slist_len_increase and - * cache_ptr->slist_size_increase to keep from skewing - * the sanity checks. - */ - HDassert( cache_ptr->slist_len_increase > 1 ); - HDassert( cache_ptr->slist_size_increase > - (int64_t)(entry_ptr->size) ); - - cache_ptr->slist_len_increase -= 1; - cache_ptr->slist_size_increase -= (int64_t)(entry_ptr->size); - } + /* we just removed the entry from the slist. Thus we + * must touch up cache_ptr->slist_len_increase and + * cache_ptr->slist_size_increase to keep from skewing + * the sanity checks. + */ + cache_ptr->slist_len_increase -= 1; + cache_ptr->slist_size_increase -= (int64_t)(entry_ptr->size); + } #endif /* H5C_DO_SANITY_CHECKS */ + if ( ! ( entry_ptr->flush_in_progress ) ) { + + /* skip the update if a flush is in progress */ H5C__UPDATE_RP_FOR_MOVE(cache_ptr, entry_ptr, was_dirty, FAIL) } } @@ -3926,6 +4217,11 @@ H5C_resize_entry(void *thing, size_t new_size) /* mark the entry as dirty if it isn't already */ entry_ptr->is_dirty = TRUE; + entry_ptr->image_up_to_date = FALSE; + + /* Release the current image */ + if( entry_ptr->image_ptr ) + entry_ptr->image_ptr = H5MM_xfree(entry_ptr->image_ptr); /* Propagate the dirty flag up the flush dependency chain if * appropriate */ @@ -4148,18 +4444,6 @@ done: * or flushed -- nor may it be accessed by another call to * H5C_protect. Any attempt to do so will result in a failure. * - * The primary_dxpl_id and secondary_dxpl_id parameters - * specify the dxpl_ids used on the first write occasioned - * by the insertion (primary_dxpl_id), and on all subsequent - * writes (secondary_dxpl_id). This is useful in the - * metadata cache, but may not be needed elsewhere. If so, - * just use the same dxpl_id for both parameters. - * - * All reads are performed with the primary_dxpl_id. - * - * Similarly, the primary_dxpl_id is passed to the - * check_write_permitted function if it is called. - * * Return: Success: Ptr to the desired entry * Failure: NULL * @@ -4181,12 +4465,21 @@ done: * entries long before we actually have to evict something * to make space. * + * JRM -- 9/1/14 + * Replace the old rw parameter with the flags parameter. + * This allows H5C_protect to accept flags other than + * H5C__READ_ONLY_FLAG. + * + * Added support for the H5C__FLUSH_LAST_FLAG and + * H5C__FLUSH_COLLECTIVELY_FLAG flags. At present, these + * flags are only applied if the entry is not in cache, and + * is loaded into the cache as a result of this call. + * *------------------------------------------------------------------------- */ void * H5C_protect(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, + hid_t dxpl_id, const H5C_class_t * type, haddr_t addr, void * udata, @@ -4194,9 +4487,12 @@ H5C_protect(H5F_t * f, { H5C_t * cache_ptr; hbool_t hit; - hbool_t first_flush; hbool_t have_write_permitted = FALSE; hbool_t read_only = FALSE; + hbool_t flush_last; +#ifdef H5_HAVE_PARALLEL + hbool_t flush_collectively; +#endif /* H5_HAVE_PARALLEL */ hbool_t write_permitted; herr_t result; size_t empty_space; @@ -4215,8 +4511,6 @@ H5C_protect(H5F_t * f, HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); HDassert( type ); - HDassert( type->flush ); - HDassert( type->load ); HDassert( H5F_addr_defined(addr) ); #if H5C_DO_EXTREME_SANITY_CHECKS @@ -4230,6 +4524,10 @@ H5C_protect(H5F_t * f, #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ read_only = ( (flags & H5C__READ_ONLY_FLAG) != 0 ); + flush_last = ( (flags & H5C__FLUSH_LAST_FLAG) != 0 ); +#ifdef H5_HAVE_PARALLEL + flush_collectively = ( (flags & H5C__FLUSH_COLLECTIVELY_FLAG) != 0 ); +#endif /* H5_HAVE_PARALLEL */ /* first check to see if the target is in cache */ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, NULL) @@ -4249,17 +4547,17 @@ H5C_protect(H5F_t * f, hit = FALSE; - thing = H5C_load_entry(f, primary_dxpl_id, type, addr, udata); + thing = H5C_load_entry(f, dxpl_id, type, addr, udata); if ( thing == NULL ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "can't load entry") - } + } entry_ptr = (H5C_cache_entry_t *)thing; /* Apply tag to newly protected entry */ - if(H5C_tag_entry(cache_ptr, entry_ptr, primary_dxpl_id) < 0) + if(H5C_tag_entry(cache_ptr, entry_ptr, dxpl_id) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, NULL, "Cannot tag entry") /* Set the entry's cork status */ @@ -4318,7 +4616,6 @@ H5C_protect(H5F_t * f, have_write_permitted = TRUE; - first_flush = TRUE; } } else { @@ -4326,7 +4623,6 @@ H5C_protect(H5F_t * f, have_write_permitted = TRUE; - first_flush = TRUE; } HDassert( entry_ptr->size <= H5C_MAX_ENTRY_SIZE ); @@ -4367,10 +4663,10 @@ H5C_protect(H5F_t * f, * see no point in worrying about the fourth. */ - result = H5C_make_space_in_cache(f, primary_dxpl_id, - secondary_dxpl_id, - space_needed, write_permitted, - &first_flush); + result = H5C_make_space_in_cache(f, + dxpl_id, + space_needed, + write_permitted); if ( result < 0 ) { @@ -4384,7 +4680,24 @@ H5C_protect(H5F_t * f, * * This is no longer true -- due to a bug fix, we may modify * data on load to repair a file. + * + * ******************************************* + * + * Set the flush_last (and possibly flush_collectively) fields + * of the newly loaded entry before inserting it into the + * index. Must do this, as the index tracked the number of + * entries with the flush_last field set, but assumes that + * the field will not change after insertion into the index. + * + * Note that this means that the H5C__FLUSH_LAST_FLAG and + * H5C__FLUSH_COLLECTIVELY_FLAG flags are ignored if the + * entry is already in cache. */ + entry_ptr->flush_me_last = flush_last; +#ifdef H5_HAVE_PARALLEL + entry_ptr->flush_me_collectively = flush_collectively; +#endif + H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, NULL) if ( ( entry_ptr->is_dirty ) && ( ! (entry_ptr->in_slist) ) ) { @@ -4398,6 +4711,13 @@ H5C_protect(H5F_t * f, * code. If we do this often enough, we may want to optimize this. */ H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, NULL) + + /* If the entry's type has a 'notify' callback send a 'after load' + * notice now that the entry is fully integrated into the cache. + */ + if(entry_ptr->type->notify && + (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_LOAD, entry_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, NULL, "can't notify client about entry inserted into cache") } HDassert( entry_ptr->addr == addr ); @@ -4458,7 +4778,6 @@ H5C_protect(H5F_t * f, have_write_permitted = TRUE; - first_flush = TRUE; } } else { @@ -4466,7 +4785,6 @@ H5C_protect(H5F_t * f, have_write_permitted = TRUE; - first_flush = TRUE; } } @@ -4475,10 +4793,8 @@ H5C_protect(H5F_t * f, (cache_ptr->resize_ctl).epoch_length ) ) { result = H5C__auto_adjust_cache_size(f, - primary_dxpl_id, - secondary_dxpl_id, - write_permitted, - &first_flush); + dxpl_id, + write_permitted); if ( result != SUCCEED ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, \ @@ -4512,10 +4828,10 @@ H5C_protect(H5F_t * f, if(cache_ptr->index_size > cache_ptr->max_cache_size) cache_ptr->cache_full = TRUE; - result = H5C_make_space_in_cache(f, primary_dxpl_id, - secondary_dxpl_id, - (size_t)0, write_permitted, - &first_flush); + result = H5C_make_space_in_cache(f, + dxpl_id, + (size_t)0, + write_permitted); if ( result < 0 ) { @@ -4526,14 +4842,16 @@ H5C_protect(H5F_t * f, } } +#ifdef ASK /* If we loaded the entry and the entry's type has a 'notify' callback, send * a 'after insertion' notice now that the entry is fully integrated into * the cache and protected. We must wait until it is protected so it is not * evicted during the notify callback. */ if(!hit && entry_ptr->type->notify && - (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_INSERT, entry_ptr) < 0) + (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_LOAD, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, NULL, "can't notify client about entry inserted into cache") +#endif done: @@ -5060,6 +5378,10 @@ done: * total_entries_skipped_in_msic, total_entries_scanned_in_msic, * and max_entries_skipped_in_msic fields. * + * JRM -- 4/11/15 + * Added code displaying the new slist_scan_restarts, + * LRU_scan_restarts, and hash_bucket_scan_restarts fields; + * *------------------------------------------------------------------------- */ herr_t @@ -5083,6 +5405,7 @@ H5C_stats(H5C_t * cache_ptr, int64_t total_clears = 0; int64_t total_flushes = 0; int64_t total_evictions = 0; + int64_t total_take_ownerships = 0; int64_t total_moves = 0; int64_t total_entry_flush_moves = 0; int64_t total_cache_flush_moves = 0; @@ -5111,6 +5434,8 @@ H5C_stats(H5C_t * cache_ptr, FUNC_ENTER_NOAPI(FAIL) + HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); + /* This would normally be an assert, but we need to use an HGOTO_ERROR * call to shut up the compiler. */ @@ -5137,6 +5462,7 @@ H5C_stats(H5C_t * cache_ptr, total_clears += cache_ptr->clears[i]; total_flushes += cache_ptr->flushes[i]; total_evictions += cache_ptr->evictions[i]; + total_take_ownerships += cache_ptr->take_ownerships[i]; total_moves += cache_ptr->moves[i]; total_entry_flush_moves += cache_ptr->entry_flush_moves[i]; total_cache_flush_moves += cache_ptr->cache_flush_moves[i]; @@ -5288,11 +5614,16 @@ H5C_stats(H5C_t * cache_ptr, (long)max_read_protects); HDfprintf(stdout, - "%s Total clears / flushes / evictions = %ld / %ld / %ld\n", + "%s Total clears / flushes = %ld / %ld\n", cache_ptr->prefix, (long)total_clears, - (long)total_flushes, - (long)total_evictions); + (long)total_flushes); + + HDfprintf(stdout, + "%s Total evictions / take ownerships = %ld / %ld\n", + cache_ptr->prefix, + (long)total_evictions, + (long)total_take_ownerships); HDfprintf(stdout, "%s Total insertions(pinned) / moves = %ld(%ld) / %ld\n", @@ -5364,6 +5695,13 @@ H5C_stats(H5C_t * cache_ptr, (long long)(cache_ptr->total_entries_scanned_in_msic - cache_ptr->entries_scanned_to_make_space)); + HDfprintf(stdout, + "%s slist/LRU/hash bkt scan restarts = %lld / %lld / %lld.\n", + cache_ptr->prefix, + (long long)(cache_ptr->slist_scan_restarts), + (long long)(cache_ptr->LRU_scan_restarts), + (long long)(cache_ptr->hash_bucket_scan_restarts)); + #if H5C_COLLECT_CACHE_ENTRY_STATS HDfprintf(stdout, "%s aggregate max / min accesses = %d / %d\n", @@ -5417,11 +5755,16 @@ H5C_stats(H5C_t * cache_ptr, (int)(cache_ptr->max_read_protects[i])); HDfprintf(stdout, - "%s clears / flushes / evictions = %ld / %ld / %ld\n", + "%s clears / flushes = %ld / %ld\n", cache_ptr->prefix, (long)(cache_ptr->clears[i]), - (long)(cache_ptr->flushes[i]), - (long)(cache_ptr->evictions[i])); + (long)(cache_ptr->flushes[i])); + + HDfprintf(stdout, + "%s evictions / take ownerships = %ld / %ld\n", + cache_ptr->prefix, + (long)(cache_ptr->evictions[i]), + (long)(cache_ptr->take_ownerships[i])); HDfprintf(stdout, "%s insertions(pinned) / moves = %ld(%ld) / %ld\n", @@ -5516,6 +5859,11 @@ done: * total_entries_skipped_in_msic, total_entries_scanned_in_msic, * and max_entries_skipped_in_msic fields. * + * JRM 4/11/15 + * Added code to initialize the new slist_scan_restarts, + * LRU_scan_restarts, hash_bucket_scan_restarts, and + * take_ownerships fields. + * *------------------------------------------------------------------------- */ void @@ -5549,6 +5897,7 @@ H5C_stats__reset(H5C_t H5_ATTR_UNUSED * cache_ptr) cache_ptr->clears[i] = 0; cache_ptr->flushes[i] = 0; cache_ptr->evictions[i] = 0; + cache_ptr->take_ownerships[i] = 0; cache_ptr->moves[i] = 0; cache_ptr->entry_flush_moves[i] = 0; cache_ptr->cache_flush_moves[i] = 0; @@ -5591,6 +5940,10 @@ H5C_stats__reset(H5C_t H5_ATTR_UNUSED * cache_ptr) cache_ptr->max_entries_scanned_in_msic = 0; cache_ptr->entries_scanned_to_make_space = 0; + cache_ptr->slist_scan_restarts = 0; + cache_ptr->LRU_scan_restarts = 0; + cache_ptr->hash_bucket_scan_restarts = 0; + #if H5C_COLLECT_CACHE_ENTRY_STATS for ( i = 0; i <= cache_ptr->max_type_id; i++ ) @@ -5745,6 +6098,107 @@ done: /*------------------------------------------------------------------------- + * Function: H5C_dump_cache_skip_list + * + * Purpose: Debugging routine that prints a summary of the contents of + * the skip list used by the metadata cache metadata cache to + * maintain an address sorted list of dirty entries. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 11/15/14 + * + *------------------------------------------------------------------------- + */ +#if 0 /* debugging routine */ +herr_t +H5C_dump_cache_skip_list(H5C_t * cache_ptr, char * calling_fcn) +{ + herr_t ret_value = SUCCEED; /* Return value */ + int i; + H5C_cache_entry_t * entry_ptr = NULL; + H5SL_node_t * node_ptr = NULL; + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(cache_ptr != NULL); + HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); + HDassert(calling_fcn != NULL); + + HDfprintf(stdout, "\n\nDumping metadata cache skip list from %s.\n", + calling_fcn); + HDfprintf(stdout, " slist len = %d.\n", cache_ptr->slist_len); + HDfprintf(stdout, " slist size = %lld.\n", + (long long)(cache_ptr->slist_size)); + + if ( cache_ptr->slist_len > 0 ) + { + /* If we get this far, all entries in the cache are listed in the + * skip list -- scan the skip list generating the desired output. + */ + + HDfprintf(stdout, + "Num: Addr: Len: Prot/Pind: Dirty: Type:\n"); + + i = 0; + + node_ptr = H5SL_first(cache_ptr->slist_ptr); + + if ( node_ptr != NULL ) { + + entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); + + } else { + + entry_ptr = NULL; + } + + while ( entry_ptr != NULL ) { + + HDassert( entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC ); + + HDfprintf(stdout, + "%s%d 0x%016llx %4lld %d/%d %d %s\n", + cache_ptr->prefix, i, + (long long)(entry_ptr->addr), + (long long)(entry_ptr->size), + (int)(entry_ptr->is_protected), + (int)(entry_ptr->is_pinned), + (int)(entry_ptr->is_dirty), + entry_ptr->type->name); + + HDfprintf(stdout, " node_ptr = 0x%llx, item = 0x%llx\n", + (unsigned long long)node_ptr, + (unsigned long long)H5SL_item(node_ptr)); + + /* increment node_ptr before we delete its target */ + node_ptr = H5SL_next(node_ptr); + + if ( node_ptr != NULL ) { + + entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); + + } else { + + entry_ptr = NULL; + } + + i++; + } + } + + HDfprintf(stdout, "\n\n"); + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C_dump_cache_skip_list() */ +#endif /* debugging routine */ + + +/*------------------------------------------------------------------------- * Function: H5C_unpin_entry_from_client() * * Purpose: Internal routine to unpin a cache entry from a client action. @@ -5900,8 +6354,7 @@ done: */ herr_t H5C_unprotect(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, + hid_t dxpl_id, const H5C_class_t * type, haddr_t addr, void * thing, @@ -5941,8 +6394,6 @@ H5C_unprotect(H5F_t * f, HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); HDassert( type ); - HDassert( type->clear ); - HDassert( type->flush ); HDassert( H5F_addr_defined(addr) ); HDassert( thing ); HDassert( ! ( pin_entry && unpin_entry ) ); @@ -6041,6 +6492,19 @@ H5C_unprotect(H5F_t * f, /* Mark the entry as dirty if appropriate */ entry_ptr->is_dirty = (entry_ptr->is_dirty || dirtied); + /* the image_up_to_date field was introduced to support + * journaling. Until we re-introduce journaling, this + * field should be equal to !entry_ptr->is_dirty. + * + * When journaling is re-enabled it should be set + * to FALSE if dirtied is TRUE. + */ +#if 1 /* JRM */ + entry_ptr->image_up_to_date = FALSE; +#else /* JRM */ + entry_ptr->image_up_to_date = !entry_ptr->is_dirty; +#endif /* JRM */ + /* Update index for newly dirtied entry */ if(was_clean && entry_ptr->is_dirty) { @@ -6109,13 +6573,6 @@ H5C_unprotect(H5F_t * f, * JRM - 5/19/04 */ if ( deleted ) { - - /* the following first flush flag will never be used as we are - * calling H5C_flush_single_entry with both the - * H5C__FLUSH_CLEAR_ONLY_FLAG and H5C__FLUSH_INVALIDATE_FLAG flags. - * However, it is needed for the function call. - */ - hbool_t dummy_first_flush = TRUE; unsigned flush_flags = (H5C__FLUSH_CLEAR_ONLY_FLAG | H5C__FLUSH_INVALIDATE_FLAG); @@ -6137,36 +6594,40 @@ H5C_unprotect(H5F_t * f, "hash table contains multiple entries for addr?!?.") } - /* Pass along 'free file space' flag to cache client */ - - entry_ptr->free_file_space_on_destroy = free_file_space; + /* Set the 'free file space' flag for the flush, if needed */ + if(free_file_space) + flush_flags |= H5C__FREE_FILE_SPACE_FLAG; /* Set the "take ownership" flag for the flush, if needed */ if(take_ownership) flush_flags |= H5C__TAKE_OWNERSHIP_FLAG; if ( H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - type, + dxpl_id, addr, flush_flags, - &dummy_first_flush, - TRUE) < 0 ) { + TRUE, + NULL) < 0 ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Can't flush.") } + +#if H5C_DO_SANITY_CHECKS + if ( ( take_ownership ) && ( ! was_clean ) ) + { + /* we have just removed an entry from the skip list. Thus + * we must touch up cache_ptr->slist_len_increase and + * cache_ptr->slist_size_increase to keep from skewing + * the sanity checks on flushes. + */ + cache_ptr->slist_len_increase -= 1; + cache_ptr->slist_size_increase -= (int64_t)(entry_ptr->size); + } +#endif /* H5C_DO_SANITY_CHECKS */ } #ifdef H5_HAVE_PARALLEL else if ( clear_entry ) { - /* the following first flush flag will never be used as we are - * calling H5C_flush_single_entry with the - * H5C__FLUSH_CLEAR_ONLY_FLAG flag. However, it is needed for - * the function call. - */ - hbool_t dummy_first_flush = TRUE; - /* verify that the target entry is in the cache. */ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL) @@ -6183,13 +6644,11 @@ H5C_unprotect(H5F_t * f, } if ( H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - type, + dxpl_id, addr, H5C__FLUSH_CLEAR_ONLY_FLAG, - &dummy_first_flush, - TRUE) < 0 ) { + TRUE, + NULL) < 0 ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Can't clear.") } @@ -6746,10 +7205,8 @@ done: */ static herr_t H5C__auto_adjust_cache_size(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - hbool_t write_permitted, - hbool_t * first_flush_ptr) + hid_t dxpl_id, + hbool_t write_permitted) { H5C_t * cache_ptr = f->shared->cache; herr_t result; @@ -6950,13 +7407,11 @@ H5C__auto_adjust_cache_size(H5F_t * f, } else { result = H5C__autoadjust__ageout(f, + dxpl_id, hit_rate, &status, &new_max_cache_size, - primary_dxpl_id, - secondary_dxpl_id, - write_permitted, - first_flush_ptr); + write_permitted); if ( result != SUCCEED ) { @@ -7099,13 +7554,11 @@ done: */ static herr_t H5C__autoadjust__ageout(H5F_t * f, + hid_t dxpl_id, double hit_rate, enum H5C_resize_status * status_ptr, size_t * new_max_cache_size_ptr, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - hbool_t write_permitted, - hbool_t * first_flush_ptr) + hbool_t write_permitted) { H5C_t * cache_ptr = f->shared->cache; herr_t result; @@ -7146,8 +7599,7 @@ H5C__autoadjust__ageout(H5F_t * f, if ( cache_ptr->max_cache_size > (cache_ptr->resize_ctl).min_size ){ /* evict aged out cache entries if appropriate... */ - if(H5C__autoadjust__ageout__evict_aged_out_entries(f, primary_dxpl_id, - secondary_dxpl_id, write_permitted, first_flush_ptr) < 0) + if(H5C__autoadjust__ageout__evict_aged_out_entries(f, dxpl_id, write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "error flushing aged out entries.") /* ... and then reduce cache size if appropriate */ @@ -7344,20 +7796,32 @@ done: * * Programmer: John Mainzer, 11/22/04 * + * Changes: Modified function to detect deletions of entries + * during a scan of the LRU, and where appropriate, + * restart the scan to avoid proceeding with a next + * entry that is no longer in the cache. + * + * Note the absence of checks after flushes of clean + * entries. As a second entry can only be removed by + * by a call to the pre_serialize or serialize callback + * of the first, and as these callbacks will not be called + * on clean entries, no checks are needed. + * + * JRM -- 4/6/15 + * *------------------------------------------------------------------------- */ static herr_t H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - hbool_t write_permitted, - hbool_t * first_flush_ptr) + hid_t dxpl_id, + hbool_t write_permitted) { H5C_t * cache_ptr = f->shared->cache; herr_t result; size_t eviction_size_limit; size_t bytes_evicted = 0; hbool_t prev_is_dirty = FALSE; + hbool_t restart_scan; H5C_cache_entry_t * entry_ptr; H5C_cache_entry_t * next_ptr; H5C_cache_entry_t * prev_ptr; @@ -7386,6 +7850,7 @@ H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t * f, if ( write_permitted ) { + restart_scan = FALSE; entry_ptr = cache_ptr->LRU_tail_ptr; while ( ( entry_ptr != NULL ) && @@ -7393,7 +7858,11 @@ H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t * f, ( bytes_evicted < eviction_size_limit ) ) { hbool_t corked = FALSE; + + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert( ! (entry_ptr->is_protected) ); + HDassert( ! (entry_ptr->is_read_only) ); + HDassert( (entry_ptr->ro_ref_count) == 0 ); next_ptr = entry_ptr->next; prev_ptr = entry_ptr->prev; @@ -7409,26 +7878,39 @@ H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t * f, result = TRUE; } else if ( entry_ptr->is_dirty ) { + /* reset entries_removed_counter and + * last_entry_removed_ptr prior to the call to + * H5C_flush_single_entry() so that we can spot + * unexpected removals of entries from the cache, + * and set the restart_scan flag if proceeding + * would be likely to cause us to scan an entry + * that is no longer in the cache. + */ + cache_ptr->entries_removed_counter = 0; + cache_ptr->last_entry_removed_ptr = NULL; + result = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - entry_ptr->type, + dxpl_id, entry_ptr->addr, H5C__NO_FLAGS_SET, - first_flush_ptr, - FALSE); + FALSE, + NULL); + + if ( ( cache_ptr->entries_removed_counter > 1 ) || + ( cache_ptr->last_entry_removed_ptr == prev_ptr ) ) + + restart_scan = TRUE; + } else { bytes_evicted += entry_ptr->size; result = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - entry_ptr->type, + dxpl_id, entry_ptr->addr, H5C__FLUSH_INVALIDATE_FLAG, - first_flush_ptr, - TRUE); + TRUE, + NULL); } if ( result < 0 ) { @@ -7438,32 +7920,28 @@ H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t * f, } if ( prev_ptr != NULL ) { -#ifndef NDEBUG - if ( prev_ptr->magic != H5C__H5C_CACHE_ENTRY_T_MAGIC ) { - - /* something horrible has happened to *prev_ptr -- - * scream and die. - */ - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "*prev_ptr corrupt") - } -#endif /* NDEBUG */ if(corked) { /* dirty corked entry is skipped */ entry_ptr = prev_ptr; - } else if ( ( prev_ptr->is_dirty != prev_is_dirty ) - || - ( prev_ptr->next != next_ptr ) - || - ( prev_ptr->is_protected ) - || - ( prev_ptr->is_pinned ) ) { + + } else if ( ( restart_scan ) + || + ( prev_ptr->is_dirty != prev_is_dirty ) + || + ( prev_ptr->next != next_ptr ) + || + ( prev_ptr->is_protected ) + || + ( prev_ptr->is_pinned ) ) { /* something has happened to the LRU -- start over * from the tail. */ + restart_scan = FALSE; entry_ptr = cache_ptr->LRU_tail_ptr; + H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr) + } else { entry_ptr = prev_ptr; @@ -7522,13 +8000,11 @@ H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t * f, if ( ! (entry_ptr->is_dirty) ) { result = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - entry_ptr->type, + dxpl_id, entry_ptr->addr, H5C__FLUSH_INVALIDATE_FLAG, - first_flush_ptr, - TRUE); + TRUE, + NULL); if ( result < 0 ) { @@ -7538,6 +8014,10 @@ H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t * f, } /* just skip the entry if it is dirty, as we can't do * anything with it now since we can't write. + * + * Since all entries are clean, serialize() will not be called, + * and thus we needn't test to see if the LRU has been changed + * out from under us. */ entry_ptr = prev_ptr; @@ -8001,17 +8481,45 @@ done: * Programmer: John Mainzer * 3/24/065 * + * Changes: Modified function to test for slist chamges in + * pre_serialize and serialize callbacks, and re-start + * scans through the slist when such changes occur. + * + * This has been a potential problem for some time, + * and there has been code in this function to deal + * with elements of this issue. However the shift + * to the V3 cache in combination with the activities + * of some of the cache clients (in particular the + * free space manager and the fractal heap) have + * made this re-work necessary in H5C_flush_cache. + * + * At present, this issue doesn't seem to be causing problems + * in H5C_flush_invalidate_cache(). However, it seems + * prudent to port the H5C_flush_cache changes to this + * function as well. + * + * JRM -- 12/14/14 + * + * Added code to track entry size change during flush single + * entry. This didn't used to be a problem, as the entry + * was largely removed from the cache data structures before + * the flush proper. However, re-entrant calls to the cache + * in the parallel case required a re-factoring of the + * H5C_flush_single_entry() function to keep entries fully + * in the cache until after the pre-serialize and serialize + * calls. + * JRM -- 12/25/14 + * *------------------------------------------------------------------------- */ static herr_t -H5C_flush_invalidate_cache(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, +H5C_flush_invalidate_cache(const H5F_t * f, + hid_t dxpl_id, unsigned flags) { H5C_t * cache_ptr = f->shared->cache; herr_t status; - hbool_t first_flush = TRUE; + hbool_t restart_slist_scan; int32_t protected_entries = 0; int32_t i; int32_t cur_pel_len; @@ -8022,10 +8530,14 @@ H5C_flush_invalidate_cache(H5F_t * f, H5C_cache_entry_t * entry_ptr = NULL; H5C_cache_entry_t * next_entry_ptr = NULL; #if H5C_DO_SANITY_CHECKS - int64_t actual_slist_len = 0; + int64_t flushed_slist_len = 0; int64_t initial_slist_len = 0; - size_t actual_slist_size = 0; + int64_t flushed_slist_size = 0; size_t initial_slist_size = 0; + int64_t entry_size_change; + int64_t * entry_size_change_ptr = &entry_size_change; +#else /* H5C_DO_SANITY_CHECKS */ + int64_t * entry_size_change_ptr = NULL; #endif /* H5C_DO_SANITY_CHECKS */ herr_t ret_value = SUCCEED; @@ -8096,27 +8608,6 @@ H5C_flush_invalidate_cache(H5F_t * f, * that the slist will not be empty after we finish the scan. */ - if ( cache_ptr->slist_len == 0 ) { - - node_ptr = NULL; - HDassert( cache_ptr->slist_size == 0 ); - - } else { - - /* Start at beginning of skip list each time */ - node_ptr = H5SL_first(cache_ptr->slist_ptr); - HDassert( node_ptr != NULL ); - - /* Get cache entry for this node */ - next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); - 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 ); - } - - #if H5C_DO_SANITY_CHECKS /* Depending on circumstances, H5C_flush_single_entry() will * remove dirty entries from the slist as it flushes them. @@ -8137,63 +8628,78 @@ H5C_flush_invalidate_cache(H5F_t * f, cache_ptr->slist_len_increase = 0; cache_ptr->slist_size_increase = 0; - /* Finally, reset the actual_slist_len and actual_slist_size + /* Finally, reset the flushed_slist_len and flushed_slist_size * fields to zero, as these fields are used to accumulate * the slist lenght and size that we see as we scan through * the slist. */ - actual_slist_len = 0; - actual_slist_size = 0; + flushed_slist_len = 0; + flushed_slist_size = 0; #endif /* H5C_DO_SANITY_CHECKS */ - while ( node_ptr != NULL ) + /* set the cache_ptr->slist_change_in_pre_serialize and + * cache_ptr->slist_change_in_serialize to false. + * + * These flags are set to TRUE by H5C_flush_single_entry if the + * slist is modified by a pre_serialize or serialize call + * respectively. + * + * H5C_flush_invalidate_cache() uses these flags to detect any + * modifications to the slist that might corrupt the scan of + * the slist -- and restart the scan in this event. + */ + cache_ptr->slist_change_in_pre_serialize = FALSE; + cache_ptr->slist_change_in_serialize = FALSE; + + /* this done, start the scan of the slist */ + + restart_slist_scan = TRUE; + + while ( ( restart_slist_scan ) || ( node_ptr != NULL ) ) { - entry_ptr = next_entry_ptr; - - /* With the advent of the fractal heap, it is possible - * that the flush callback will dirty and/or resize - * other entries in the cache. In particular, while - * Quincey has promised me that this will never happen, - * it is possible that the flush callback for an - * entry may protect an entry that is not in the cache, - * perhaps causing the cache to flush and possibly - * evict the entry associated with node_ptr to make - * space for the new entry. - * - * Thus we do a bit of extra sanity checking on entry_ptr, - * and break out of this scan of the skip list if we - * detect major problems. We have a bit of leaway on the - * number of passes though the skip list, so this shouldn't - * be an issue in the flush in and of itself, as it should - * be all but impossible for this to happen more than once - * in any flush. - * - * Observe that that breaking out of the scan early - * shouldn't break the sanity checks just after the end - * of this while loop. - * - * If an entry has merely been marked clean and removed from - * the s-list, we simply break out of the scan. - * - * If the entry has been evicted, we flag an error and - * exit. - */ -#ifndef NDEBUG - if ( entry_ptr->magic != H5C__H5C_CACHE_ENTRY_T_MAGIC ) { + if ( restart_slist_scan ) + { + restart_slist_scan = FALSE; - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "entry_ptr->magic is invalid ?!?!") + /* Start at beginning of skip list */ + node_ptr = H5SL_first(cache_ptr->slist_ptr); - } else -#endif /* NDEBUG */ - if ( ( ! entry_ptr->is_dirty ) || - ( ! entry_ptr->in_slist ) ) { + if ( node_ptr == NULL ) + { + /* the slist is empty -- break out of inner loop */ + break; + } + HDassert( node_ptr != NULL ); - /* the s-list has been modified out from under us. - * break out of the loop. - */ - goto end_of_inner_loop;; + /* Get cache entry for this node */ + next_entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); + + 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 ); } + entry_ptr = next_entry_ptr; + + /* It is possible that entries will be dirtied, resized, + * flushed, or removed from the cache via the take ownership + * flag as the result of pre_serialize or serialized callbacks. + * + * This in turn can corrupt the scan through the slist. + * + * We test for slist modifications in the pre_serialize + * and serialize callbacks, and restart the scan of the + * slist if we find them. However, best we do some extra + * sanity checking just in case. + */ + + HDassert( entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC ); + HDassert( entry_ptr->in_slist ); + HDassert( entry_ptr->is_dirty ); + /* increment node pointer now, before we delete its target * from the slist. */ @@ -8206,6 +8712,7 @@ H5C_flush_invalidate_cache(H5F_t * f, HDassert( next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC ); HDassert( next_entry_ptr->is_dirty ); HDassert( next_entry_ptr->in_slist ); + HDassert( entry_ptr != next_entry_ptr ); } else { next_entry_ptr = NULL; } @@ -8230,21 +8737,6 @@ H5C_flush_invalidate_cache(H5F_t * f, cache_ptr->slist_len ) ) ) && ( entry_ptr->flush_dep_nchildren == 0 ) ) { -#if H5C_DO_SANITY_CHECKS - /* update actual_slist_len & actual_slist_size before - * the flush. Note that the entry will be removed - * from the slist after the flush, and thus may be - * resized by the flush callback. This is OK, as - * we will catch the size delta in - * cache_ptr->slist_size_increase. - * - * Note that we include pinned entries in this count, even - * though we will not actually flush them. - */ - actual_slist_len++; - actual_slist_size += entry_ptr->size; -#endif /* H5C_DO_SANITY_CHECKS */ - if ( entry_ptr->is_protected ) { /* we have major problems -- but lets flush @@ -8254,14 +8746,26 @@ H5C_flush_invalidate_cache(H5F_t * f, } else if ( entry_ptr->is_pinned ) { +#if H5C_DO_SANITY_CHECKS + /* update flushed_slist_len & flushed_slist_size + * before the flush. Note that the entry will + * be removed from the slist after the flush, + * and thus may be resized by the flush callback. + * This is OK, as we will catch the size delta in + * cache_ptr->slist_size_increase. + * + */ + flushed_slist_len++; + flushed_slist_size += (int64_t)entry_ptr->size; + entry_size_change = 0; +#endif /* H5C_DO_SANITY_CHECKS */ + status = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - NULL, - entry_ptr->addr, - H5C__NO_FLAGS_SET, - &first_flush, - FALSE); + dxpl_id, + entry_ptr->addr, + H5C__NO_FLAGS_SET, + FALSE, + entry_size_change_ptr); if ( status < 0 ) { /* This shouldn't happen -- if it does, we are toast @@ -8271,17 +8775,52 @@ H5C_flush_invalidate_cache(H5F_t * f, HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ "dirty pinned entry flush failed.") } /* end if */ + +#if H5C_DO_SANITY_CHECKS + /* entry size may have changed during the flush. + * Update flushed_slist_size to account for this. + */ + flushed_slist_size += entry_size_change; +#endif /* H5C_DO_SANITY_CHECKS */ + + if ( ( cache_ptr->slist_change_in_serialize ) || + ( cache_ptr->slist_change_in_pre_serialize ) ) + { + /* The slist has been modified by something + * other than the simple removal of the + * of the flushed entry after the flush. + * + * This has the potential to corrupt the + * scan through the slist, so restart it. + */ + restart_slist_scan = TRUE; + cache_ptr->slist_change_in_pre_serialize = FALSE; + cache_ptr->slist_change_in_serialize = FALSE; + H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr); + } } /* end if */ else { +#if H5C_DO_SANITY_CHECKS + /* update flushed_slist_len & flushed_slist_size + * before the flush. Note that the entry will + * be removed from the slist after the flush, + * and thus may be resized by the flush callback. + * This is OK, as we will catch the size delta in + * cache_ptr->slist_size_increase. + * + */ + flushed_slist_len++; + flushed_slist_size += (int64_t)entry_ptr->size; + entry_size_change = 0; +#endif /* H5C_DO_SANITY_CHECKS */ + status = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - NULL, + dxpl_id, entry_ptr->addr, (cooked_flags | H5C__FLUSH_INVALIDATE_FLAG), - &first_flush, - TRUE); + TRUE, + entry_size_change_ptr); if ( status < 0 ) { /* This shouldn't happen -- if it does, we are toast so @@ -8291,6 +8830,30 @@ H5C_flush_invalidate_cache(H5F_t * f, HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ "dirty entry flush destroy failed.") } /* end if */ + +#if H5C_DO_SANITY_CHECKS + /* entry size may have changed during the flush. + * Update flushed_slist_size to account for this. + */ + flushed_slist_size += entry_size_change; +#endif /* H5C_DO_SANITY_CHECKS */ + + if ((cache_ptr->slist_change_in_serialize) || + (cache_ptr->slist_change_in_pre_serialize)) + { + /* The slist has been modified by something + * other than the simple removal of the + * of the flushed entry after the flush. + * + * This has the potential to corrupt the + * scan through the slist, so restart it. + */ + restart_slist_scan = TRUE; + cache_ptr->slist_change_in_pre_serialize = FALSE; + cache_ptr->slist_change_in_serialize = FALSE; + H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr) + } + } /* end else */ } /* end if */ } /* end while loop scanning skip list */ @@ -8307,11 +8870,10 @@ H5C_flush_invalidate_cache(H5F_t * f, if ( node_ptr == NULL ) { - HDassert( (actual_slist_len + cache_ptr->slist_len) == + HDassert( (flushed_slist_len + cache_ptr->slist_len) == (initial_slist_len + cache_ptr->slist_len_increase) ); - HDassert( (actual_slist_size + cache_ptr->slist_size) == - (initial_slist_size + - (size_t)(cache_ptr->slist_size_increase)) ); + HDassert( (flushed_slist_size + (int64_t)cache_ptr->slist_size) == + ((int64_t)initial_slist_size + cache_ptr->slist_size_increase) ); } #endif /* H5C_DO_SANITY_CHECKS */ @@ -8333,9 +8895,7 @@ H5C_flush_invalidate_cache(H5F_t * f, while ( next_entry_ptr != NULL ) { entry_ptr = next_entry_ptr; -#ifndef NDEBUG HDassert( entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC ); -#endif /* NDEBUG */ next_entry_ptr = entry_ptr->ht_next; HDassert ( ( next_entry_ptr == NULL ) || @@ -8359,15 +8919,39 @@ H5C_flush_invalidate_cache(H5F_t * f, HDassert( !(entry_ptr->is_dirty) ); } } else if ( ! ( entry_ptr->is_pinned ) ) { + /* if *entry_ptr is dirty, it is possible + * that one or more other entries may be + * either removed from the cache, loaded + * into the cache, or moved to a new location + * in the file as a side effect of the flush. + * + * If this happens, and one of the target + * entries happens to be the next entry in + * the hash bucket, we could find ourselves + * either find ourselves either scanning a + * non-existant entry, scanning through a + * different bucket, or skipping an entry. + * + * Neither of these are good, so restart the + * the scan at the head of the hash bucket + * after the flush if *entry_ptr was dirty, + * on the off chance that the next entry was + * a target. + * + * This is not as inefficient at it might seem, + * as hash buckets typically have at most two + * or three entries. + */ + hbool_t entry_was_dirty; + + entry_was_dirty = entry_ptr->is_dirty; status = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - NULL, + dxpl_id, entry_ptr->addr, (cooked_flags | H5C__FLUSH_INVALIDATE_FLAG), - &first_flush, - TRUE); + TRUE, + NULL); if ( status < 0 ) { /* This shouldn't happen -- if it does, we are toast so @@ -8377,6 +8961,17 @@ H5C_flush_invalidate_cache(H5F_t * f, HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ "Entry flush destroy failed.") } + + if ( entry_was_dirty ) { + + /* update stats for hash bucket scan + * restart here. + * -- JRM + */ + next_entry_ptr = cache_ptr->index[i]; + H5C__UPDATE_STATS_FOR_HASH_BUCKET_SCAN_RESTART(cache_ptr) + } + } /* end if */ } /* end if */ /* We can't do anything if the entry is pinned. The @@ -8387,7 +8982,7 @@ H5C_flush_invalidate_cache(H5F_t * f, * of pinned entries from pass to pass. If it stops * shrinking before it hits zero, we scream and die. */ - /* if the flush function on the entry we last evicted + /* if the serialize function on the entry we last evicted * loaded an entry into cache (as Quincey has promised me * it never will), and if the cache was full, it is * possible that *next_entry_ptr was flushed or evicted. @@ -8396,8 +8991,13 @@ H5C_flush_invalidate_cache(H5F_t * f, * test is triggred, we are accessing a deallocated piece * of dynamically allocated memory, so we just scream and * die. + * + * Update: The code to restart the scan after flushes + * of dirty entries should make it impossible + * to satisfy the following test. Leave it in + * in case I am wrong. + * -- JRM */ -#ifndef NDEBUG if ( ( next_entry_ptr != NULL ) && ( next_entry_ptr->magic != H5C__H5C_CACHE_ENTRY_T_MAGIC ) ) { @@ -8408,10 +9008,8 @@ H5C_flush_invalidate_cache(H5F_t * f, HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "next_entry_ptr->magic is invalid?!?!?.") } -#endif /* NDEBUG */ } /* end while loop scanning hash table bin */ } /* end for loop scanning hash table */ -end_of_inner_loop: old_pel_len = cur_pel_len; cur_pel_len = cache_ptr->pel_len; @@ -8490,22 +9088,9 @@ done: * Attempts to flush a protected entry will result in an * error. * - * *first_flush_ptr should be true if only one - * flush is contemplated before the next load, or if this - * is the first of a sequence of flushes that will be - * completed before the next load. *first_flush_ptr is set - * to false if a flush actually takes place, and should be - * left false until the end of the sequence. - * - * The primary_dxpl_id is used if *first_flush_ptr is TRUE - * on entry, and a flush actually takes place. The - * secondary_dxpl_id is used in any subsequent flush where - * *first_flush_ptr is FALSE on entry. - * * If the H5C__FLUSH_INVALIDATE_FLAG flag is set, the entry will - * be cleared and not flushed -- in the case *first_flush_ptr, - * primary_dxpl_id, and secondary_dxpl_id are all irrelevent, - * and the call can't be part of a sequence of flushes. + * be cleared and not flushed, and the call can't be part of a + * sequence of flushes. * * If the caller knows the address of the skip list node at * which the target entry resides, it can avoid a lookup @@ -8522,26 +9107,57 @@ done: * * Programmer: John Mainzer, 5/5/04 * + * Changes: Refactored function to remove the type_ptr parameter. + * + * JRM -- 8/7/14 + * + * Added code to check for slist changes in pre_serialize and + * serialize calls, and set + * cache_ptr->slist_change_in_pre_serialize and + * cache_ptr->slist_change_in_serialize as appropriate. + * + * JRM -- 12/13/14 + * + * Refactored function to delay all modifications of the + * metadata cache data structures until after any calls + * to the pre-serialize or serialize callbacks. + * + * Need to do this, as some pre-serialize or serialize + * calls result in calls to the metadata cache and + * modifications to its data structures. Thus, at the + * time of any such call, the target entry flags and + * the metadata cache must all be consistant. + * + * Also added the entry_size_change_ptr parameter, which + * allows the function to report back any change in the size + * of the entry during the flush. Such size changes may + * occur during the pre-serialize callback. + * + * JRM -- 12/24/14 + * *------------------------------------------------------------------------- */ static herr_t -H5C_flush_single_entry(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - const H5C_class_t * type_ptr, - haddr_t addr, - unsigned flags, - hbool_t * first_flush_ptr, - hbool_t del_entry_from_slist_on_destroy) +H5C_flush_single_entry(const H5F_t * f, + hid_t dxpl_id, + haddr_t addr, + unsigned flags, + hbool_t del_entry_from_slist_on_destroy, + int64_t * entry_size_change_ptr) { H5C_t * cache_ptr = f->shared->cache; hbool_t destroy; /* external flag */ hbool_t clear_only; /* external flag */ + hbool_t free_file_space; /* external flag */ hbool_t take_ownership; /* external flag */ + hbool_t write_entry; /* internal flag */ + hbool_t destroy_entry; /* internal flag */ hbool_t was_dirty; - hbool_t destroy_entry; herr_t status; - unsigned flush_flags = H5C_CALLBACK__NO_FLAGS_SET; + haddr_t new_addr = HADDR_UNDEF; + haddr_t old_addr = HADDR_UNDEF; + size_t new_len = 0; + size_t new_compressed_len = 0; H5C_cache_entry_t * entry_ptr = NULL; herr_t ret_value = SUCCEED; /* Return value */ @@ -8551,11 +9167,15 @@ H5C_flush_single_entry(H5F_t * f, HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); HDassert( H5F_addr_defined(addr) ); - HDassert( first_flush_ptr ); + + /* If defined, initialize *entry_size_change_ptr to 0 */ + if(entry_size_change_ptr != NULL) + *entry_size_change_ptr = 0; /* setup external flags from the flags parameter */ destroy = ((flags & H5C__FLUSH_INVALIDATE_FLAG) != 0); clear_only = ((flags & H5C__FLUSH_CLEAR_ONLY_FLAG) != 0); + free_file_space = ((flags & H5C__FREE_FILE_SPACE_FLAG) != 0); take_ownership = ((flags & H5C__TAKE_OWNERSHIP_FLAG) != 0); /* Set the flag for destroying the entry, based on the 'take ownership' @@ -8569,6 +9189,14 @@ 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) + /* we will write the entry to disk if it exists, is dirty, and if the + * clear only flag is not set. + */ + if ( ( entry_ptr != NULL ) && ( entry_ptr->is_dirty ) && ( ! clear_only ) ) + write_entry = TRUE; + else + write_entry = FALSE; + /* run initial sanity checks */ #if H5C_DO_SANITY_CHECKS if ( entry_ptr != NULL ) { @@ -8577,6 +9205,8 @@ H5C_flush_single_entry(H5F_t * f, if ( entry_ptr->in_slist ) { + HDassert(entry_ptr->is_dirty); + if ( ( ( entry_ptr->flush_marker ) && ( ! entry_ptr->is_dirty ) ) || ( entry_ptr->addr != addr ) ) { @@ -8585,6 +9215,10 @@ H5C_flush_single_entry(H5F_t * f, } } else { + HDassert(!entry_ptr->is_dirty); + HDassert(!entry_ptr->flush_marker); + HDassert(entry_ptr->addr == addr); + if ( ( entry_ptr->is_dirty ) || ( entry_ptr->flush_marker ) || ( entry_ptr->addr != addr ) ) { @@ -8598,22 +9232,32 @@ H5C_flush_single_entry(H5F_t * f, if ( ( entry_ptr != NULL ) && ( entry_ptr->is_protected ) ) { + HDassert(!entry_ptr->is_protected); /* Attempt to flush a protected entry -- scream and die. */ HGOTO_ERROR(H5E_CACHE, H5E_PROTECT, FAIL, \ "Attempt to flush a protected entry.") } - if ( ( entry_ptr != NULL ) && - ( ( type_ptr == NULL ) || ( type_ptr->id == entry_ptr->type->id ) ) ) + /* if the entry exists, set entry_ptr->flush_in_progress = TRUE + * and set entry_ptr->flush_marker = FALSE + * + * in the parallel case, do some sanity checking in passing. + */ + if ( entry_ptr != NULL ) { /* we have work to do */ + HDassert(entry_ptr->type); + + was_dirty = entry_ptr->is_dirty; /* needed later for logging */ /* We will set flush_in_progress back to FALSE at the end if the * entry still exists at that point. */ entry_ptr->flush_in_progress = TRUE; + entry_ptr->flush_marker = FALSE; + #ifdef H5_HAVE_PARALLEL #ifndef NDEBUG /* If MPI based VFD is used, do special parallel I/O sanity checks. @@ -8627,7 +9271,7 @@ H5C_flush_single_entry(H5F_t * f, unsigned coll_meta; /* Collective metadata write flag */ /* Get the dataset transfer property list */ - if(NULL == (dxpl = H5I_object(primary_dxpl_id))) + if(NULL == (dxpl = H5I_object(dxpl_id))) HGOTO_ERROR(H5E_CACHE, H5E_BADTYPE, FAIL, "not a dataset transfer property list") /* Get the collective metadata write property */ @@ -8639,174 +9283,112 @@ H5C_flush_single_entry(H5F_t * f, } /* end if */ #endif /* NDEBUG */ #endif /* H5_HAVE_PARALLEL */ + } - was_dirty = entry_ptr->is_dirty; - - entry_ptr->flush_marker = FALSE; - - if ( clear_only ) { - H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) - } else { - H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) - } - - if ( destroy ) { - H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) - } + if ( ( entry_ptr != NULL ) && ( write_entry ) ) + { + /* serialize the entry if necessary, and then write it to disk. */ - /* If the entry's type has a 'notify' callback and the entry is about - * to be removed from the cache, send a 'before eviction' notice while - * the entry is still fully integrated in the cache. - */ - if(destroy) { - if(entry_ptr->type->notify && - (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_BEFORE_EVICT, entry_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry to evict") - } /* end if */ + unsigned serialize_flags = H5C__SERIALIZE_NO_FLAGS_SET; - /* Always remove the entry from the hash table on a destroy. On a - * 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 slist only if requested. - * - * We must do deletions now as the callback routines will free the - * entry if destroy is true. + /* The entry is dirty, and we are doing either a flush, + * or a flush destroy. In either case, serialize the + * entry and write it to disk. * - * Note that it is possible that the entry will be moved during - * its call to flush. This will upset H5C_move_entry() if we - * don't tell it that it doesn't have to worry about updating the - * index and SLIST. Use the destroy_in_progress field for this - * purpose. - */ - if ( destroy ) { - - entry_ptr->destroy_in_progress = TRUE; - - H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr) - - if ( ( entry_ptr->in_slist ) && - ( del_entry_from_slist_on_destroy ) ) { - - H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) - } - } - - /* Update the replacement policy for the flush or eviction. - * Again, do this now so we don't have to reference freed - * memory in the destroy case. + * Note that this may cause the entry to be re-sized and/or + * moved in the cache. + * + * As we will not update the metadata cache's data structures + * until we we finish the write, we must touch up these + * data structures for size and location changes even if we + * are about to delete the entry from the cache (i.e. on a + * flush destroy). */ - if ( destroy ) { /* AKA eviction */ - - H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, FAIL) - - } else { - - H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, FAIL) - } - - /* Destroy parent flush dependencies and free flush dependency parent - * array, if necessary */ - if ( destroy ) { - HDassert( entry_ptr->flush_dep_nchildren == 0 ); - - if ( entry_ptr->flush_dep_parent_nalloc > 0 ) { + HDassert(entry_ptr->is_dirty); - while ( entry_ptr->flush_dep_nparents > 0 ) { +#if H5C_DO_SANITY_CHECKS + if ( ( cache_ptr->check_write_permitted == NULL ) && + ( !(cache_ptr->write_permitted) ) ) - /* Since the flush_dep_parent array willbe resized every - * a flush dependency is destroyed, we do not have to - * iterate over all indices. Instead, always destroy the - * last dependency so we can skip the memmove() in - * H5C_destroy_flush_dependency(). */ - if ( H5C_destroy_flush_dependency(entry_ptr->flush_dep_parent[entry_ptr->flush_dep_nparents - 1], - entry_ptr) < 0 ) { + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Write when writes are always forbidden!?!?!") +#endif /* H5C_DO_SANITY_CHECKS */ - HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, \ - "Can't remove flush dependency") - } - } + if ( NULL == entry_ptr->image_ptr ) + { + size_t image_size; - /* H5C_destroy_flush_dependency should have freed the parent - * array when it became empty */ - HDassert( ! (entry_ptr->flush_dep_parent) ); - HDassert( entry_ptr->flush_dep_parent_nalloc == 0 ); - } - } + if ( entry_ptr->compressed ) + image_size = entry_ptr->compressed_size; + else + image_size = entry_ptr->size; - /* Clear the dirty flag only, if requested */ - if ( clear_only ) { + HDassert(image_size > 0); - if ( destroy ) { -#ifndef NDEBUG - /* we are about to call the clear callback with the - * destroy flag set -- this will result in *entry_ptr - * being freed. Set the magic field to bad magic - * so we can detect a freed cache entry if we see - * one. - */ - entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC; -#endif /* NDEBUG */ - entry_ptr->cache_ptr = NULL; - } - /* Call the callback routine to clear all dirty flags for object */ - if ( (entry_ptr->type->clear)(f, entry_ptr, destroy_entry) < 0 ) { + entry_ptr->image_ptr = + H5MM_malloc(image_size + H5C_IMAGE_EXTRA_SPACE); - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't clear entry") + if ( NULL == entry_ptr->image_ptr) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, \ + "memory allocation failed for on disk image buffer") } - } else { +#if H5C_DO_MEMORY_SANITY_CHECKS -#if H5C_DO_SANITY_CHECKS - if ( ( entry_ptr->is_dirty ) && - ( cache_ptr->check_write_permitted == NULL ) && - ( ! (cache_ptr->write_permitted) ) ) + HDmemcpy(((uint8_t *)entry_ptr->image_ptr) + image_size, + H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "Write when writes are always forbidden!?!?!") -#endif /* H5C_DO_SANITY_CHECKS */ +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ - if ( destroy ) { -#ifndef NDEBUG - /* we are about to call the flush callback with the - * destroy flag set -- this will result in *entry_ptr - * being freed. Set the magic field to bad magic - * so we can detect a freed cache entry if we see - * one. - */ - entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC; -#endif /* NDEBUG */ - entry_ptr->cache_ptr = NULL; - } + } /* end if */ - /* Only block for all the processes on the first piece of metadata + if ( ! (entry_ptr->image_up_to_date) ) + { + /* reset cache_ptr->slist_changed so we can detect slist + * modifications in the pre_serialize call. */ - - if ( *first_flush_ptr && entry_ptr->is_dirty ) { - - status = (entry_ptr->type->flush)(f, primary_dxpl_id, destroy_entry, - entry_ptr->addr, entry_ptr, - &flush_flags); - *first_flush_ptr = FALSE; - - } else { - - status = (entry_ptr->type->flush)(f, secondary_dxpl_id, - destroy_entry, entry_ptr->addr, - entry_ptr, &flush_flags); - } - - if ( status < 0 ) { - + cache_ptr->slist_changed = FALSE; + + /* make note of the entry's current address */ + old_addr = entry_ptr->addr; + + /* Call client's pre-serialize callback, if there's one */ + if ( ( entry_ptr->type->pre_serialize != NULL ) && + ( (entry_ptr->type->pre_serialize)(f, dxpl_id, + (void *)entry_ptr, + entry_ptr->addr, + entry_ptr->size, + entry_ptr->compressed_size, + &new_addr, &new_len, + &new_compressed_len, + &serialize_flags) < 0 ) ) + { HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ - "unable to flush entry") + "unable to pre-serialize entry") } -#ifdef H5_HAVE_PARALLEL - if ( flush_flags != H5C_CALLBACK__NO_FLAGS_SET ) { + /* set cache_ptr->slist_change_in_pre_serialize if the + * slist was modified. + */ + if ( cache_ptr->slist_changed ) + cache_ptr->slist_change_in_pre_serialize = TRUE; - /* In the parallel case, flush operations can - * cause problems. If they occur, scream and - * die. + /* Check for any flags set in the pre-serialize callback */ + if ( serialize_flags != H5C__SERIALIZE_NO_FLAGS_SET ) + { + /* Check for unexpected flags from serialize callback */ + if ( serialize_flags & ~(H5C__SERIALIZE_RESIZED_FLAG | + H5C__SERIALIZE_MOVED_FLAG | + H5C__SERIALIZE_COMPRESSED_FLAG)) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "unknown serialize flag(s)") + } +#ifdef H5_HAVE_PARALLEL + /* In the parallel case, resizes and moves in + * the serialize operation can cause problems. + * If they occur, scream and die. * * At present, in the parallel case, the aux_ptr * will only be set if there is more than one @@ -8833,106 +9415,387 @@ H5C_flush_single_entry(H5F_t * f, if ( cache_ptr->aux_ptr != NULL ) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "resize/move in serialize occured in parallel case.") + "resize/move in serialize occured in parallel case.") +#endif /* H5_HAVE_PARALLEL */ + + /* Resize the buffer if required */ + if ( ( ( ! entry_ptr->compressed ) && + ( serialize_flags & H5C__SERIALIZE_RESIZED_FLAG ) ) || + ( ( entry_ptr->compressed ) && + ( serialize_flags & H5C__SERIALIZE_COMPRESSED_FLAG ) ) ) + { + size_t new_image_size; + + if ( entry_ptr->compressed ) + new_image_size = new_compressed_len; + else + new_image_size = new_len; + + HDassert(new_image_size > 0); + + /* Release the current image */ + if ( entry_ptr->image_ptr ) + { + entry_ptr->image_ptr = H5MM_xfree(entry_ptr->image_ptr); + } + + /* Allocate a new image buffer */ + entry_ptr->image_ptr = + H5MM_malloc(new_image_size + H5C_IMAGE_EXTRA_SPACE); + + if ( NULL == entry_ptr->image_ptr ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, \ + "memory allocation failed for on disk image buffer") + } + +#if H5C_DO_MEMORY_SANITY_CHECKS + + HDmemcpy(((uint8_t *)entry_ptr->image_ptr) + new_image_size, + H5C_IMAGE_SANITY_VALUE, + H5C_IMAGE_EXTRA_SPACE); + +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + + } /* end if */ + + /* If required, update the entry and the cache data structures + * for a resize. + */ + if ( serialize_flags & H5C__SERIALIZE_RESIZED_FLAG ) { + + H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, \ + entry_ptr, new_len) + + /* update the hash table for the size change*/ + H5C__UPDATE_INDEX_FOR_SIZE_CHANGE(cache_ptr, \ + entry_ptr->size, \ + new_len, entry_ptr, \ + !(entry_ptr->is_dirty)); + + /* The entry can't be protected since we are + * in the process of flushing it. Thus we must + * update the replacement policy data + * structures for the size change. The macro + * deals with the pinned case. + */ + H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_len); + + /* as we haven't updated the cache data structures for + * for the flush or flush destroy yet, the entry should + * be in the slist. Thus update it for the size change. + */ + HDassert(entry_ptr->in_slist); + H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, \ + new_len) + + /* if defined, update *entry_size_change_ptr for the + * change in entry size. + */ + if(entry_size_change_ptr != NULL) + *entry_size_change_ptr = (int64_t)new_len - (int64_t)(entry_ptr->size); + + /* finally, update the entry for its new size */ + entry_ptr->size = new_len; + } /* end if */ + + /* If required, udate the entry and the cache data structures + * for a move + */ + if(serialize_flags & H5C__SERIALIZE_MOVED_FLAG) + { +#if H5C_DO_SANITY_CHECKS + int64_t saved_slist_len_increase; + int64_t saved_slist_size_increase; +#endif /* H5C_DO_SANITY_CHECKS */ + + H5C__UPDATE_STATS_FOR_MOVE(cache_ptr, entry_ptr) + + if ( entry_ptr->addr == old_addr ) + { + /* we must update cache data structures for the + * change in address. + */ + + /* delete the entry from the hash table and the slist */ + H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr) + H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) + + /* update the entry for its new address */ + entry_ptr->addr = new_addr; + + /* and then reinsert in the index and slist */ + H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL) + +#if H5C_DO_SANITY_CHECKS + /* save cache_ptr->slist_len_increase and + * cache_ptr->slist_size_increase before the + * reinsertion into the slist, and restore + * them afterwards to avoid skewing our sanity + * checking. + */ + saved_slist_len_increase = cache_ptr->slist_len_increase; + saved_slist_size_increase = cache_ptr->slist_size_increase; +#endif /* H5C_DO_SANITY_CHECKS */ + + H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) + +#if H5C_DO_SANITY_CHECKS + cache_ptr->slist_len_increase = saved_slist_len_increase; + cache_ptr->slist_size_increase = saved_slist_size_increase; +#endif /* H5C_DO_SANITY_CHECKS */ + } + else /* move is alread done for us -- just do sanity checks */ + { + HDassert(entry_ptr->addr == new_addr); + } + } /* end if */ + + if ( serialize_flags & H5C__SERIALIZE_COMPRESSED_FLAG ) { + /* just save the new compressed entry size in + * entry_ptr->compressed_size. We don't need to + * do more, as compressed size is only used for I/O. + */ + HDassert(entry_ptr->compressed); + entry_ptr->compressed_size = new_compressed_len; + } + } /* end if ( serialize_flags != H5C__SERIALIZE_NO_FLAGS_SET ) */ + + /* Serialize object into buffer */ + { + size_t image_len; + + if ( entry_ptr->compressed ) + image_len = entry_ptr->compressed_size; + else + image_len = entry_ptr->size; + + /* reset cache_ptr->slist_changed so we can detect slist + * modifications in the serialize call. + */ + cache_ptr->slist_changed = FALSE; + + + if ( entry_ptr->type->serialize(f, entry_ptr->image_ptr, + image_len, + (void *)entry_ptr) < 0 ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "unable to serialize entry") + } + + /* set cache_ptr->slist_change_in_serialize if the + * slist was modified. + */ + if ( cache_ptr->slist_changed ) + cache_ptr->slist_change_in_pre_serialize = TRUE; +#if H5C_DO_MEMORY_SANITY_CHECKS + + HDassert(0 == HDmemcmp(((uint8_t *)entry_ptr->image_ptr) + + image_len, + H5C_IMAGE_SANITY_VALUE, + H5C_IMAGE_EXTRA_SPACE)); + +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + + entry_ptr->image_up_to_date = TRUE; + } + } /* end if ( ! (entry_ptr->image_up_to_date) ) */ + + /* Finally, write the image to disk. + * + * Note that if either the H5C__CLASS_NO_IO_FLAG or the + * the H5AC__CLASS_SKIP_WRITES flag is set in the + * in the entry's type, we silently skip the write. This + * flag should only be used in test code. + */ + if ( ( ((entry_ptr->type->flags) & H5C__CLASS_NO_IO_FLAG) == 0 ) && + ( ((entry_ptr->type->flags) & H5C__CLASS_SKIP_WRITES) == 0 ) ) + { + /* If compression is not enabled, the size of the entry on + * disk is entry_prt->size. However if entry_ptr->compressed + * is TRUE, the on disk size is entry_ptr->compressed_size. + */ + size_t image_size; + + if ( entry_ptr->compressed ) + image_size = entry_ptr->compressed_size; + else + image_size = entry_ptr->size; + + if ( ( H5F_block_write(f, entry_ptr->type->mem_type, + entry_ptr->addr, + image_size, dxpl_id, + entry_ptr->image_ptr) < 0 ) ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Can't write image to file.") } -#endif /* H5_HAVE_PARALLEL */ } - if ( ( ! destroy ) && ( entry_ptr->in_slist ) ) { + /* if the entry has a notify callback, notify it that we have + * just flushed the entry. + */ - H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) + if ( ( entry_ptr->type->notify ) && + ( (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_FLUSH, + entry_ptr) < 0 ) ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, \ + "can't notify client of entry flush") + } + } /* if ( ( entry_ptr != NULL ) && ( write_entry ) ) */ + + + /* At this point, all pre-serialize and serialize calls have been + * made if it was appropriate to make them. Similarly, the entry + * has been written to disk if desired. + * + * Thus it is now safe to update the cache data structures for the + * flush. + */ + + if ( entry_ptr != NULL ) + { + /* start by updating the statistics */ + + if ( clear_only ) { + + /* only log a clear if the entry was dirty */ + if ( was_dirty ) { + + H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) + } + } else if ( write_entry ) { + + HDassert( was_dirty ); + + /* only log a flush if we actually wrote to disk */ + H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) } - if ( ( ! destroy ) && ( was_dirty ) ) { + if ( destroy ) + { + if ( take_ownership ) + { + HDassert(!destroy_entry); + } + else + { + HDassert(destroy_entry); + } - H5C__UPDATE_INDEX_FOR_ENTRY_CLEAN(cache_ptr, entry_ptr); + H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr, \ + take_ownership) } - if ( ! destroy ) { /* i.e. if the entry still exists */ + /* If the entry's type has a 'notify' callback and the entry is about + * to be removed from the cache, send a 'before eviction' notice while + * the entry is still fully integrated in the cache. + */ + if ( destroy ) { - HDassert( !(entry_ptr->is_dirty) ); - HDassert( !(entry_ptr->flush_marker) ); - HDassert( !(entry_ptr->in_slist) ); - HDassert( !(entry_ptr->is_protected) ); - HDassert( !(entry_ptr->is_read_only) ); - HDassert( (entry_ptr->ro_ref_count) == 0 ); + if ( ( entry_ptr->type->notify ) && + ( (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_BEFORE_EVICT, + entry_ptr) < 0 ) ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, \ + "can't notify client about entry to evict") + } + } /* end if */ - if ( (flush_flags & H5C_CALLBACK__SIZE_CHANGED_FLAG) != 0 ) { - /* The entry size changed as a result of the flush. - * - * Most likely, the entry was compressed, and the - * new version is of a different size than the old. - * - * In any case, we must update entry and cache size - * accordingly. - */ - size_t new_size; + /* Update the cache internal data structures. */ + if ( destroy ) + { + /* Update the cache internal data structures as appropriate + * for a destroy. Specifically: + * + * 1) Delete it from the index + * + * 2) Delete it from the skip list if requested. + * + * 3) Update the replacement policy for eviction + * + * Finally, if the destroy_entry flag is set, discard the + * entry. + */ - if ( (entry_ptr->type->size)(f, (void *)entry_ptr, &new_size) - < 0 ) { + H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGETSIZE, FAIL, \ - "Can't get entry size after flush") - } + if ( ( entry_ptr->in_slist ) && + ( del_entry_from_slist_on_destroy ) ) { - if ( new_size != entry_ptr->size ) { + H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) + } - HDassert( entry_ptr->size < H5C_MAX_ENTRY_SIZE ); + H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, FAIL) - /* update the hash table for the size change - * We pass TRUE as the was_clean parameter, as we - * have already updated the clean and dirty index - * size fields for the fact that the entry has - * been flushed. (See above call to - * H5C__UPDATE_INDEX_FOR_ENTRY_CLEAN()). - */ - H5C__UPDATE_INDEX_FOR_SIZE_CHANGE((cache_ptr), \ - (entry_ptr->size), \ - (new_size), \ - (entry_ptr), \ - (TRUE)) - - /* The entry can't be protected since we just flushed it. - * Thus we must update the replacement policy data - * structures for the size change. The macro deals - * with the pinned case. - */ - H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, \ - new_size) + /* Destroy parent flush dependencies and free flush dependency parent + * array, if necessary */ + HDassert( entry_ptr->flush_dep_nchildren == 0 ); + if ( entry_ptr->flush_dep_parent_nalloc > 0 ) { - /* The entry can't be in the slist, so no need to update - * the slist for the size change. - */ + while ( entry_ptr->flush_dep_nparents > 0 ) { - /* update stats for the size change */ - H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, \ - entry_ptr, \ - new_size) + /* Since the flush_dep_parent array willbe resized every + * a flush dependency is destroyed, we do not have to + * iterate over all indices. Instead, always destroy the + * last dependency so we can skip the memmove() in + * H5C_destroy_flush_dependency(). */ + if ( H5C_destroy_flush_dependency(entry_ptr->flush_dep_parent[entry_ptr->flush_dep_nparents - 1], + entry_ptr) < 0 ) { - /* finally, update the entry size proper */ - entry_ptr->size = new_size; + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, \ + "Can't remove flush dependency") + } } + + /* H5C_destroy_flush_dependency should have freed the parent + * array when it became empty */ + HDassert( ! (entry_ptr->flush_dep_parent) ); + HDassert( entry_ptr->flush_dep_parent_nalloc == 0 ); } + } + else + { + HDassert(clear_only || write_entry); + HDassert(entry_ptr->is_dirty); + HDassert(entry_ptr->in_slist); + + /* We are either doing a flush or a clear. + * + * A clear and a flush are the same from the point of + * view of the replacement policy and the slist. + * Hence no differentiation between them. + * + * JRM -- 7/7/07 + */ - if ( (flush_flags & H5C_CALLBACK__MOVED_FLAG) != 0 ) { + H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, FAIL) + + H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr) - /* The entry was moved as the result of the flush. - * - * Most likely, the entry was compressed, and the - * new version is larger than the old and thus had - * to be relocated. - * - * At preset, all processing for this case is - * handled elsewhere. But lets keep the if statement - * around just in case. - */ + /* mark the entry as clean and update the index for + * entry clean. Also, call the clear callback + * if defined. + */ + + entry_ptr->is_dirty = FALSE; + + H5C__UPDATE_INDEX_FOR_ENTRY_CLEAN(cache_ptr, entry_ptr); + + if ( ( entry_ptr->type->clear != NULL ) && + ( (entry_ptr->type->clear)(f, (void *)entry_ptr, FALSE) ) ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "unable to clear entry") } - /* Propagate the clean flag up the flush dependency chain if + /* Propagate the clean flag up the flush dependency chain if * appropriate */ if ( was_dirty ) { @@ -8948,9 +9811,159 @@ H5C_flush_single_entry(H5F_t * f, } } - entry_ptr->flush_in_progress = FALSE; } + /* reset the flush_in progress flag */ + + entry_ptr->flush_in_progress = FALSE; + + } /* end if */ + + + /* Internal cache data structures should now be up to date, and + * consistant with the status of the entry. + * + * Now discard the entry if appropriate. + */ + if ( entry_ptr != NULL ) + { + if ( destroy ) + { + /* start by freeing the buffer for the on disk image */ + if(entry_ptr->image_ptr != NULL) + entry_ptr->image_ptr = H5MM_xfree(entry_ptr->image_ptr); + + /* Check whether we should free the space in the file that + * the entry occupies + */ + if ( free_file_space ) + { + + size_t fsf_size; + + /* Sanity checks */ + HDassert(H5F_addr_defined(entry_ptr->addr)); + HDassert(!H5F_IS_TMP_ADDR(f, entry_ptr->addr)); +#ifndef NDEBUG +{ + hbool_t curr_compressed = FALSE; + size_t curr_len; + size_t curr_compressed_len = 0; + + /* Get the actual image size for the thing again */ + entry_ptr->type->image_len((void *)entry_ptr, &curr_len, &curr_compressed, &curr_compressed_len); + HDassert(curr_len == entry_ptr->size); + HDassert(curr_compressed == entry_ptr->compressed); + HDassert(curr_compressed_len == entry_ptr->compressed_size); +} +#endif /* NDEBUG */ + + /* 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->compressed_size if + * entry_ptr->compressed == TRUE, and entry_ptr->size + * if entry_ptr->compressed == FALSE. + */ + 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") + } + } + else if ( entry_ptr->compressed ) /* use compressed size */ + { + fsf_size = entry_ptr->compressed_size; + } + 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, dxpl_id, + entry_ptr->addr, (hsize_t)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. + */ + cache_ptr->last_entry_removed_ptr++; + cache_ptr->last_entry_removed_ptr = entry_ptr; + + /* Check for actually destroying the entry in memory */ + /* (As opposed to taking ownership of it) */ + if ( destroy_entry ) + { + /* if the entry is dirty and it has a clear callback, + * call this callback now. Since this callback exists, + * it follows tht the client maintains its own dirty bits, + * which must be cleared before the entry is freed to avoid + * sanity check failures. Also clear the dirty flag for + * the same reason. + */ + + if ( entry_ptr->is_dirty ) { + + entry_ptr->is_dirty = FALSE; + + if ( ( entry_ptr->type->clear != NULL ) && + ( (entry_ptr->type->clear)(f, (void *)entry_ptr, TRUE) ) ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "unable to clear entry") + } + } + + /* we are about to discard the in core representation -- + * set the magic field to bad magic so we can detect a + * freed entry if we see one. + */ + entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC; + + + /* verify that the image has been freed */ + HDassert( entry_ptr->image_ptr == NULL ); + + if ( entry_ptr->type->free_icr((void *)entry_ptr) < 0 ) + { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "free_icr callback failed.") + } + } + else + { + HDassert(take_ownership); + + /* client is taking ownership of the entry. + * set bad magic here too so the cache will choke + * unless the entry is re-inserted properly + */ + entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC; + } + } /* if ( destroy ) */ + } + + if ( entry_ptr != NULL ) + { if ( cache_ptr->log_flush ) { status = (cache_ptr->log_flush)(cache_ptr, addr, was_dirty, flags); @@ -8964,14 +9977,94 @@ H5C_flush_single_entry(H5F_t * f, } done: - HDassert( ( destroy ) || + + HDassert( ( ret_value != SUCCEED ) || ( destroy_entry ) || ( ( entry_ptr ) && ( ! entry_ptr->flush_in_progress ) ) ); + + HDassert( ( ret_value != SUCCEED ) || ( destroy_entry ) || + ( take_ownership ) || + ( ( entry_ptr ) && ( ! entry_ptr->is_dirty ) ) ); + FUNC_LEAVE_NOAPI(ret_value) } /* H5C_flush_single_entry() */ /*------------------------------------------------------------------------- * + * Function: H5C_verify_len_eoa + * + * Purpose: Verify that 'len' does not exceed eoa when 'actual' is + * false i.e. 'len" is the initial speculative length from + * get_load_size callback with null image pointer. + * If exceed, adjust 'len' accordingly. + * + * Verify that 'len' should not exceed eoa when 'actual' is + * true i.e. 'len' is the actual length from get_load_size + * callback with non-null image pointer. + * If exceed, return error. + * + * The coding is copied and moved from H5C_load_entry(). + * + * Return: FAIL if error is detected, SUCCEED otherwise. + * + * Programmer: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C_verify_len_eoa (H5F_t * f, + const H5C_class_t * type, + haddr_t addr, + size_t *len, + htri_t actual) +{ + haddr_t eoa; /* End-of-allocation in the file */ + H5FD_mem_t cooked_type; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* if type == H5FD_MEM_GHEAP, H5F_block_read() forces + * type to H5FD_MEM_DRAW via its call to H5F__accum_read(). + * Thus we do the same for purposes of computing the eoa + * for sanity checks. + */ + cooked_type = (type->mem_type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : type->mem_type; + + /* Get the file's end-of-allocation value */ + eoa = H5F_get_eoa(f, cooked_type); + + HDassert(H5F_addr_defined(eoa)); + + /* Check for bad address in general */ + if ( H5F_addr_gt(addr, eoa) ) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "address of object past end of allocation") + + /* Check if the amount of data to read will be past the eoa */ + if( H5F_addr_gt((addr + *len), eoa) ) { + + if(actual) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "actual len exceeds EOA.") + else + /* Trim down the length of the metadata */ + /* Note that for some cache clients, this will cause an + * assertion failure. JRM -- 8/29/14 + */ + *len = (size_t)(eoa - addr); + } + + if ( *len <= 0 ) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "len not positive after adjustment for EOA.") + +done: + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5C_verify_len_eoa() */ + + + +/*------------------------------------------------------------------------- + * * Function: H5C_load_entry * * Purpose: Attempt to load the entry at the specified disk address @@ -8995,8 +10088,19 @@ H5C_load_entry(H5F_t * f, haddr_t addr, void * udata) { + hbool_t dirty = FALSE; /* Flag indicating whether thing was dirtied during deserialize */ + hbool_t compressed = FALSE; /* flag indicating whether thing */ + /* will be run through filters on */ + /* on read and write. Usually FALSE */ + /* set to true if appropriate. */ + size_t compressed_size = 0; /* entry compressed size if */ + /* known -- otherwise uncompressed. */ + /* Zero indicates compression not */ + /* enabled. */ + void * image = NULL; /* Buffer for disk image */ void * thing = NULL; /* Pointer to thing loaded */ H5C_cache_entry_t * entry; /* Alias for thing loaded, as cache entry */ + size_t len; /* Size of image in file */ void * ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT @@ -9005,14 +10109,223 @@ H5C_load_entry(H5F_t * f, HDassert(f->shared); HDassert(f->shared->cache); HDassert(type); - HDassert(type->load); - HDassert(type->size); + + /* verify absence of prohibited or unsupported type flag combinations */ + HDassert(!(type->flags & H5C__CLASS_NO_IO_FLAG)); + + /* for now, we do not combine the speculative load and compressed flags */ + HDassert(!((type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG) && + (type->flags & H5C__CLASS_COMPRESSED_FLAG))); + + /* Can't see how skip reads could be usefully combined with + * either the speculative read or compressed flags. Hence disallow. + */ + HDassert(!((type->flags & H5C__CLASS_SKIP_READS) && + (type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG))); + HDassert(!((type->flags & H5C__CLASS_SKIP_READS) && + (type->flags & H5C__CLASS_COMPRESSED_FLAG))); + HDassert(H5F_addr_defined(addr)); + HDassert(type->get_load_size); + HDassert(type->deserialize); + + /* Call the get_load_size callback, to retrieve the initial + * size of image + */ + if(type->get_load_size(NULL, udata, &len, NULL, NULL, NULL) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "can't retrieve image size") + + HDassert(len > 0); + + /* Check for possible speculative read off the end of the file */ + if(type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG) { + +/* Quincey has added patches for eoa calculations -- leave the original + * code around until we see the effect of these patches. + * JRM -- 1/1/15 + */ +#if 0 /* original code */ /* JRM */ + /* the original version of this code has several problems: + * + * First, the sblock is not available until the sblock + * has been read in, which causes a seg fault. This is + * dealt with easily enough by testing to see if + * f->shared->sblock is NULL, and calling H5FD_get_base_addr() + * to obtain the base addr when it is. + * + * The second issue is more subtle. H5F_get_eoa() calls + * H5FD_get_eoa(). However, this function returns the EOA as + * a relative address -- i.e. relative to the base address. + * This means that the base addr + addr < eoa sanity check will + * fail whenever the super block is not at address 0 when + * reading in the first chunk of the super block. + * + * To address these issues, I have rewritten the code to + * simply verify that the address plus length is less than + * the eoa. I think this is sufficient, but further testing + * should tell me if it isn't. + * JRM -- 8/29/14 + */ + haddr_t eoa; /* End-of-allocation in the file */ + haddr_t base_addr; /* Base address of file data */ + + /* Get the file's end-of-allocation value */ + eoa = H5F_get_eoa(f, type->mem_type); + HDassert(H5F_addr_defined(eoa)); + + /* Get the file's base address */ + if ( f->shared->sblock ) + + base_addr = H5F_BASE_ADDR(f); + + else { /* sblock not loaded yet -- use file driver info */ + + HDassert(f->shared->lf); + base_addr = H5FD_get_base_addr(f->shared->lf); + + } + HDassert(H5F_addr_defined(base_addr)); + + /* Check for bad address in general */ + if((addr + base_addr) > eoa) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, \ + "address of object past end of allocation") + + /* Check if the amount of data to read will be past the eoa */ + if((addr + base_addr + len) > eoa) + /* Trim down the length of the metadata */ + len = (size_t)(eoa - (addr + base_addr)); + +#else /* modified code */ /* JRM */ + + if(H5C_verify_len_eoa(f, type, addr, &len, FALSE) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "invalid len with respect to EOA.") + +#endif /* modified code */ /* JRM */ + } + /* Allocate the buffer for reading the on-disk entry image */ + if(NULL == (image = H5MM_malloc(len + H5C_IMAGE_EXTRA_SPACE))) + + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, \ + "memory allocation failed for on disk image buffer.") + +#if H5C_DO_MEMORY_SANITY_CHECKS + HDmemcpy(((uint8_t *)image) + len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + + /* Get the on-disk entry image */ + if ( 0 == (type->flags & H5C__CLASS_SKIP_READS) ) { + unsigned tries, max_tries; /* The # of read attempts */ + unsigned retries; /* The # of retries */ + htri_t chk_ret; /* return from verify_chksum callback */ + size_t actual_len = len; + void *new_image; /* Pointer to image */ + + /* Get the # of read attempts */ + max_tries = tries = H5F_GET_READ_ATTEMPTS(f); + + /* + * This do/while loop performs the following till the metadata checksum is correct or the + * file's allowed read attempts are reached. + * --read the metadata + * --determine the actual size of the metadata + * --perform checksum verification + */ + do { + compressed = FALSE; + compressed_size = 0; + + if(actual_len != len) { + if(NULL == (new_image = H5MM_realloc(image, len + H5C_IMAGE_EXTRA_SPACE))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "image null after H5MM_realloc()") + image = new_image; + } + + if(H5F_block_read(f, type->mem_type, addr, len, dxpl_id, image) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_READERROR, NULL, "Can't read image*") + + actual_len = len; + + if(type->get_load_size(image, udata, &len, &actual_len, &compressed, &compressed_size) < 0) + continue; /* Transfer control to while() and count towards retries */ + + HDassert(((type->flags & H5C__CLASS_COMPRESSED_FLAG) != 0) || + ((compressed == FALSE) && (compressed_size == 0))); + HDassert((compressed == TRUE) || (compressed_size == 0)); + + if(actual_len != len) { + + if(type->flags & H5C__CLASS_COMPRESSED_FLAG) { + /* if actual_len != len, then compression must be enabled on the entry. + * In this case, the get_load_size callback should have set compressed to TRUE, + * compressed_size to the compressed size (which must equal to len), + * and actual_len to the uncompressed size of the entry, + * We can't verify the uncompressed size, but we can verify the rest + * with the following assertions. + */ + HDassert(compressed); + HDassert(compressed_size == len); + } else if(type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG) { + + size_t temp_len = actual_len; + + /* compressed must be FALSE, and compressed_size + * must be zero. + */ + HDassert(!compressed); + HDassert(compressed_size == 0); + + if(H5C_verify_len_eoa(f, type, addr, &temp_len, TRUE) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "actual_len exceeds EOA.") + HDassert(temp_len == actual_len); - if(NULL == (thing = (type->load)(f, dxpl_id, addr, udata))) + if(NULL == (new_image = H5MM_realloc(image, actual_len + H5C_IMAGE_EXTRA_SPACE))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "image null after H5MM_realloc()") + image = new_image; +#if H5C_DO_MEMORY_SANITY_CHECKS - HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "unable to load entry") + HDmemcpy(((uint8_t *)image) + actual_len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); + +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + /* If the thing's image needs to be bigger for a speculatively + * loaded thing, go get the on-disk image again (the extra portion). + */ + if(actual_len > len) { + + if(H5F_block_read(f, type->mem_type, addr+len, actual_len-len, dxpl_id, image+len) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "Can't read image") + } + } else { /* throw an error */ + HGOTO_ERROR(H5E_CACHE, H5E_UNSUPPORTED, NULL, + "size of non-speculative, non-compressed object changed") + } + } /* end if (actual_len != len) */ + + if(type->verify_chksum == NULL) + break; + + if((chk_ret = type->verify_chksum(image, actual_len, udata)) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_NOSPACE, NULL, "Failure from verify_chksum callback") + if(chk_ret == TRUE) + break; + } while(--tries); + + /* Check for too many tries */ + if(tries == 0) + HGOTO_ERROR(H5E_CACHE, H5E_READERROR, NULL, "incorrect metadatda checksum after all read attempts") + + /* Calculate and track the # of retries */ + retries = max_tries - tries; + if(retries) { /* Does not track 0 retry */ + if(H5F_track_metadata_read_retries(f, (unsigned)type->mem_type, retries) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "cannot track read tries = %u ", retries) + } + len = actual_len; + } /* end if !H5C__CLASS_SKIP_READS */ + /* Deserialize the on-disk image into the native memory form */ + if(NULL == (thing = type->deserialize(image, len, udata, &dirty))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "Can't deserialize image") entry = (H5C_cache_entry_t *)thing; @@ -9020,35 +10333,39 @@ H5C_load_entry(H5F_t * f, * * However, when this code is used in the metadata cache, it is * possible that object headers will be dirty at this point, as - * the load function will alter object headers if necessary to + * the deserialize function will alter object headers if necessary to * fix an old bug. * - * To support this bug fix, I have replace the old assert: - * - * HDassert( entry->is_dirty == FALSE ); - * - * with: + * In the following assert: * - * HDassert( ( entry->is_dirty == FALSE ) || ( type->id == 5 ) ); + * HDassert( ( dirty == FALSE ) || ( type->id == 5 || type->id == 6 ) ); * - * Note that type id 5 is associated with object headers in the metadata - * cache. + * note that type ids 5 & 6 are associated with object headers in the + * metadata cache. * * When we get to using H5C for other purposes, we may wish to * tighten up the assert so that the loophole only applies to the * metadata cache. */ - HDassert( ( entry->is_dirty == FALSE ) || ( type->id == 5 ) ); -#ifndef NDEBUG + HDassert( ( dirty == FALSE ) || ( type->id == 5 || type->id == 6) ); + entry->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC; -#endif /* NDEBUG */ entry->cache_ptr = f->shared->cache; entry->addr = addr; + entry->size = len; + HDassert(entry->size < H5C_MAX_ENTRY_SIZE); + entry->compressed = compressed; + entry->compressed_size = compressed_size; + entry->image_ptr = image; + entry->image_up_to_date = TRUE; entry->type = type; + entry->is_dirty = dirty; + entry->dirtied = FALSE; entry->is_protected = FALSE; entry->is_read_only = FALSE; entry->ro_ref_count = 0; + entry->is_pinned = FALSE; entry->in_slist = FALSE; entry->flush_marker = FALSE; #ifdef H5_HAVE_PARALLEL @@ -9057,13 +10374,6 @@ H5C_load_entry(H5F_t * f, #endif /* H5_HAVE_PARALLEL */ entry->flush_in_progress = FALSE; entry->destroy_in_progress = FALSE; - entry->free_file_space_on_destroy = FALSE; - - if((type->size)(f, thing, &(entry->size)) < 0) - - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGETSIZE, NULL, "Can't get size of thing") - - HDassert( entry->size < H5C_MAX_ENTRY_SIZE ); /* Initialize flush dependency height fields */ entry->flush_dep_parent = NULL; @@ -9085,6 +10395,18 @@ H5C_load_entry(H5F_t * f, ret_value = thing; done: + /* Cleanup on error */ + if(NULL == ret_value) { + + /* Release resources */ + if ( thing && type->free_icr(thing) < 0 ) + + HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, NULL, \ + "free_icr callback failed") + + if(image) + image = H5MM_xfree(image); + } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* H5C_load_entry() */ @@ -9123,36 +10445,45 @@ done: * * Programmer: John Mainzer, 5/14/04 * - * JRM -- 11/13/08 - * Modified function to always observe the min_clean_size - * whether we are maintaining the clean and dirt LRU lists - * or not. To do this, we had to add the new clean_index_size - * and dirty_index_size fields to H5C_t, and supporting code - * as needed throughout the cache. + * Changes: Modified function to skip over entries with the + * flush_in_progress flag set. If this is not done, + * an infinite recursion is possible if the cache is + * full, and the pre-serialize or serialize routine + * attempts to load another entry. * - * The purpose of this modification is to avoid "metadata - * blizzards" in the write only case. In such instances, - * the cache was allowed to fill with dirty metadata. When - * we finally needed to evict an entry to make space, we had - * to flush out a whole cache full of metadata -- which has - * interesting performance effects. We hope to avoid (or - * perhaps more accurately hide) this effect by maintaining - * the min_clean_size, which should force us to start flushing - * entries long before we actually have to evict something - * to make space. + * This error was exposed by a re-factor of the + * H5C_flush_single_entry() routine. However, it was + * a potential bug from the moment that entries were + * allowed to load other entries on flush. + * + * In passing, note that the primary and secondary dxpls + * mentioned in the comment above have been replaced by + * a single dxpl at some point, and thus the discussion + * above is somewhat obsolete. Date of this change is + * unkown. + * + * JRM -- 12/26/14 + * + * Modified function to detect deletions of entries + * during a scan of the LRU, and where appropriate, + * restart the scan to avoid proceeding with a next + * entry that is no longer in the cache. + * + * Note the absence of checks after flushes of clean + * entries. As a second entry can only be removed by + * by a call to the pre_serialize or serialize callback + * of the first, and as these callbacks will not be called + * on clean entries, no checks are needed. + * + * JRM -- 4/6/15 * - * MAM -- 01/06/09 - * Added code to maintain clean_entries_skipped and total_entries - * scanned statistics. *------------------------------------------------------------------------- */ static herr_t -H5C_make_space_in_cache(H5F_t * f, - hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, - size_t space_needed, - hbool_t write_permitted, - hbool_t * first_flush_ptr) +H5C_make_space_in_cache(H5F_t * f, + hid_t dxpl_id, + size_t space_needed, + hbool_t write_permitted) { H5C_t * cache_ptr = f->shared->cache; herr_t result; @@ -9165,6 +10496,7 @@ H5C_make_space_in_cache(H5F_t * f, size_t empty_space; hbool_t prev_is_dirty = FALSE; hbool_t didnt_flush_entry = FALSE; + hbool_t restart_scan; H5C_cache_entry_t * entry_ptr; H5C_cache_entry_t * prev_ptr; H5C_cache_entry_t * next_ptr; @@ -9176,13 +10508,12 @@ H5C_make_space_in_cache(H5F_t * f, HDassert( f ); HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); - HDassert( first_flush_ptr != NULL ); - HDassert( ( *first_flush_ptr == TRUE ) || ( *first_flush_ptr == FALSE ) ); HDassert( cache_ptr->index_size == (cache_ptr->clean_index_size + cache_ptr->dirty_index_size) ); if ( write_permitted ) { + restart_scan = FALSE; initial_list_len = cache_ptr->LRU_list_len; entry_ptr = cache_ptr->LRU_tail_ptr; @@ -9213,6 +10544,7 @@ H5C_make_space_in_cache(H5F_t * f, ( entry_ptr != NULL ) ) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert( !(entry_ptr->is_protected) ); HDassert( ! (entry_ptr->is_read_only) ); HDassert( (entry_ptr->ro_ref_count) == 0 ); @@ -9234,7 +10566,8 @@ H5C_make_space_in_cache(H5F_t * f, didnt_flush_entry = TRUE; result = SUCCEED; - } else if ( (entry_ptr->type)->id != H5C__EPOCH_MARKER_TYPE) { + } else if ( ( (entry_ptr->type)->id != H5C__EPOCH_MARKER_TYPE ) && + ( ! entry_ptr->flush_in_progress ) ) { didnt_flush_entry = FALSE; @@ -9249,14 +10582,29 @@ H5C_make_space_in_cache(H5F_t * f, } #endif /* H5C_COLLECT_CACHE_STATS */ + /* reset entries_removed_counter and + * last_entry_removed_ptr prior to the call to + * H5C_flush_single_entry() so that we can spot + * unexpected removals of entries from the cache, + * and set the restart_scan flag if proceeding + * would be likely to cause us to scan an entry + * that is no longer in the cache. + */ + cache_ptr->entries_removed_counter = 0; + cache_ptr->last_entry_removed_ptr = NULL; + result = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - entry_ptr->type, + dxpl_id, entry_ptr->addr, H5C__NO_FLAGS_SET, - first_flush_ptr, - FALSE); + FALSE, + NULL); + + if ( ( cache_ptr->entries_removed_counter > 1 ) || + ( cache_ptr->last_entry_removed_ptr == prev_ptr ) ) + + restart_scan = TRUE; + } else if ( (cache_ptr->index_size + space_needed) > cache_ptr->max_cache_size ) { @@ -9265,13 +10613,11 @@ H5C_make_space_in_cache(H5F_t * f, #endif /* H5C_COLLECT_CACHE_STATS */ result = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - entry_ptr->type, + dxpl_id, entry_ptr->addr, H5C__FLUSH_INVALIDATE_FLAG, - first_flush_ptr, - TRUE); + TRUE, + NULL); } else { /* We have enough space so don't flush clean entry. @@ -9292,7 +10638,8 @@ H5C_make_space_in_cache(H5F_t * f, } else { - /* Skip epoch markers. Set result to SUCCEED to avoid + /* Skip epoch markers and entries that are in the process + * of being flushed. Set result to SUCCEED to avoid * triggering the error code below. */ didnt_flush_entry = TRUE; @@ -9306,26 +10653,20 @@ H5C_make_space_in_cache(H5F_t * f, } if ( prev_ptr != NULL ) { -#ifndef NDEBUG - if ( prev_ptr->magic != H5C__H5C_CACHE_ENTRY_T_MAGIC ) { - - /* something horrible has happened to *prev_ptr -- - * scream and die. - */ - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "*prev_ptr corrupt 1") - } -#endif /* NDEBUG */ if ( didnt_flush_entry ) { - /* epoch markers don't get flushed, so the sanity checks - * on normal entries will fail -- thus just set entry_ptr - * to prev_ptr and go on. - */ + /* epoch markers don't get flushed, and we don't touch + * entries that are in the process of being flushed. + * Hence no need for sanity checks, as we haven't + * flushed anything. Thus just set entry_ptr to prev_ptr + * and go on. + */ entry_ptr = prev_ptr; - } else if ( ( prev_ptr->is_dirty != prev_is_dirty ) + } else if ( ( restart_scan ) + || + ( prev_ptr->is_dirty != prev_is_dirty ) || ( prev_ptr->next != next_ptr ) || @@ -9336,7 +10677,9 @@ H5C_make_space_in_cache(H5F_t * f, /* something has happened to the LRU -- start over * from the tail. */ + restart_scan = FALSE; entry_ptr = cache_ptr->LRU_tail_ptr; + H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr) } else { @@ -9426,13 +10769,11 @@ H5C_make_space_in_cache(H5F_t * f, prev_ptr = entry_ptr->aux_prev; result = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - entry_ptr->type, + dxpl_id, entry_ptr->addr, H5C__FLUSH_INVALIDATE_FLAG, - first_flush_ptr, - TRUE); + TRUE, + NULL); if ( result < 0 ) { @@ -9440,9 +10781,15 @@ H5C_make_space_in_cache(H5F_t * f, "unable to flush entry") } + /* we are scanning the clean LRU, so the serialize function + * will not be called on any entry -- thus there is no + * concern about the list being modified out from under + * this function. + */ + entry_ptr = prev_ptr; entries_examined++; - } + } } done: @@ -9489,90 +10836,90 @@ H5C_validate_lru_list(H5C_t * cache_ptr) HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); if ( ( ( cache_ptr->LRU_head_ptr == NULL ) - || - ( cache_ptr->LRU_tail_ptr == NULL ) - ) - && - ( cache_ptr->LRU_head_ptr != cache_ptr->LRU_tail_ptr ) + || + ( cache_ptr->LRU_tail_ptr == NULL ) + ) + && + ( cache_ptr->LRU_head_ptr != cache_ptr->LRU_tail_ptr ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed") } if ( ( cache_ptr->LRU_list_len < 0 ) || ( cache_ptr->LRU_list_size < 0 ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed") } if ( ( cache_ptr->LRU_list_len == 1 ) - && - ( ( cache_ptr->LRU_head_ptr != cache_ptr->LRU_tail_ptr ) - || - ( cache_ptr->LRU_head_ptr == NULL ) - || - ( cache_ptr->LRU_head_ptr->size != cache_ptr->LRU_list_size ) - ) + && + ( ( cache_ptr->LRU_head_ptr != cache_ptr->LRU_tail_ptr ) + || + ( cache_ptr->LRU_head_ptr == NULL ) + || + ( cache_ptr->LRU_head_ptr->size != cache_ptr->LRU_list_size ) + ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed") } if ( ( cache_ptr->LRU_list_len >= 1 ) - && - ( ( cache_ptr->LRU_head_ptr == NULL ) - || - ( cache_ptr->LRU_head_ptr->prev != NULL ) - || - ( cache_ptr->LRU_tail_ptr == NULL ) - || - ( cache_ptr->LRU_tail_ptr->next != NULL ) - ) + && + ( ( cache_ptr->LRU_head_ptr == NULL ) + || + ( cache_ptr->LRU_head_ptr->prev != NULL ) + || + ( cache_ptr->LRU_tail_ptr == NULL ) + || + ( cache_ptr->LRU_tail_ptr->next != NULL ) + ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed") } entry_ptr = cache_ptr->LRU_head_ptr; while ( entry_ptr != NULL ) { - if ( ( entry_ptr != cache_ptr->LRU_head_ptr ) && - ( ( entry_ptr->prev == NULL ) || - ( entry_ptr->prev->next != entry_ptr ) ) ) { + if ( ( entry_ptr != cache_ptr->LRU_head_ptr ) && + ( ( entry_ptr->prev == NULL ) || + ( entry_ptr->prev->next != entry_ptr ) ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed") + } - if ( ( entry_ptr != cache_ptr->LRU_tail_ptr ) && - ( ( entry_ptr->next == NULL ) || - ( entry_ptr->next->prev != entry_ptr ) ) ) { + if ( ( entry_ptr != cache_ptr->LRU_tail_ptr ) && + ( ( entry_ptr->next == NULL ) || + ( entry_ptr->next->prev != entry_ptr ) ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed") + } - if ( ( entry_ptr->is_pinned ) || - ( entry_ptr->pinned_from_client ) || - ( entry_ptr->pinned_from_cache ) ) { + if ( ( entry_ptr->is_pinned ) || + ( entry_ptr->pinned_from_client ) || + ( entry_ptr->pinned_from_cache ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed") + } - len++; - size += entry_ptr->size; - entry_ptr = entry_ptr->next; + len++; + size += entry_ptr->size; + entry_ptr = entry_ptr->next; } if ( ( cache_ptr->LRU_list_len != len ) || - ( cache_ptr->LRU_list_size != size ) ) { + ( cache_ptr->LRU_list_size != size ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed") } done: if ( ret_value != SUCCEED ) { - HDassert(0); + HDassert(0); } FUNC_LEAVE_NOAPI(ret_value) @@ -9619,94 +10966,94 @@ H5C_validate_pinned_entry_list(H5C_t * cache_ptr) HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); if ( ( ( cache_ptr->pel_head_ptr == NULL ) - || - ( cache_ptr->pel_tail_ptr == NULL ) - ) - && - ( cache_ptr->pel_head_ptr != cache_ptr->pel_tail_ptr ) + || + ( cache_ptr->pel_tail_ptr == NULL ) + ) + && + ( cache_ptr->pel_head_ptr != cache_ptr->pel_tail_ptr ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed") } if ( ( cache_ptr->pel_len < 0 ) || ( cache_ptr->pel_size < 0 ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed") } if ( ( cache_ptr->pel_len == 1 ) - && - ( ( cache_ptr->pel_head_ptr != cache_ptr->pel_tail_ptr ) - || - ( cache_ptr->pel_head_ptr == NULL ) - || - ( cache_ptr->pel_head_ptr->size != cache_ptr->pel_size ) - ) + && + ( ( cache_ptr->pel_head_ptr != cache_ptr->pel_tail_ptr ) + || + ( cache_ptr->pel_head_ptr == NULL ) + || + ( cache_ptr->pel_head_ptr->size != cache_ptr->pel_size ) + ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed") } if ( ( cache_ptr->pel_len >= 1 ) - && - ( ( cache_ptr->pel_head_ptr == NULL ) - || - ( cache_ptr->pel_head_ptr->prev != NULL ) - || - ( cache_ptr->pel_tail_ptr == NULL ) - || - ( cache_ptr->pel_tail_ptr->next != NULL ) - ) + && + ( ( cache_ptr->pel_head_ptr == NULL ) + || + ( cache_ptr->pel_head_ptr->prev != NULL ) + || + ( cache_ptr->pel_tail_ptr == NULL ) + || + ( cache_ptr->pel_tail_ptr->next != NULL ) + ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed") } entry_ptr = cache_ptr->pel_head_ptr; while ( entry_ptr != NULL ) { - if ( ( entry_ptr != cache_ptr->pel_head_ptr ) && - ( ( entry_ptr->prev == NULL ) || - ( entry_ptr->prev->next != entry_ptr ) ) ) { + if ( ( entry_ptr != cache_ptr->pel_head_ptr ) && + ( ( entry_ptr->prev == NULL ) || + ( entry_ptr->prev->next != entry_ptr ) ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed") + } - if ( ( entry_ptr != cache_ptr->pel_tail_ptr ) && - ( ( entry_ptr->next == NULL ) || - ( entry_ptr->next->prev != entry_ptr ) ) ) { + if ( ( entry_ptr != cache_ptr->pel_tail_ptr ) && + ( ( entry_ptr->next == NULL ) || + ( entry_ptr->next->prev != entry_ptr ) ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed") + } - if ( ! entry_ptr->is_pinned ) { + if ( ! entry_ptr->is_pinned ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed") + } - if ( ! ( ( entry_ptr->pinned_from_client ) || - ( entry_ptr->pinned_from_cache ) ) ) { + if ( ! ( ( entry_ptr->pinned_from_client ) || + ( entry_ptr->pinned_from_cache ) ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed") + } - len++; - size += entry_ptr->size; - entry_ptr = entry_ptr->next; + len++; + size += entry_ptr->size; + entry_ptr = entry_ptr->next; } if ( ( cache_ptr->pel_len != len ) || - ( cache_ptr->pel_size != size ) ) { + ( cache_ptr->pel_size != size ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 9 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 9 failed") } done: if ( ret_value != SUCCEED ) { - HDassert(0); + HDassert(0); } FUNC_LEAVE_NOAPI(ret_value) @@ -9753,94 +11100,94 @@ H5C_validate_protected_entry_list(H5C_t * cache_ptr) HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); if ( ( ( cache_ptr->pl_head_ptr == NULL ) - || - ( cache_ptr->pl_tail_ptr == NULL ) - ) - && - ( cache_ptr->pl_head_ptr != cache_ptr->pl_tail_ptr ) + || + ( cache_ptr->pl_tail_ptr == NULL ) + ) + && + ( cache_ptr->pl_head_ptr != cache_ptr->pl_tail_ptr ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 1 failed") } if ( ( cache_ptr->pl_len < 0 ) || ( cache_ptr->pl_size < 0 ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 2 failed") } if ( ( cache_ptr->pl_len == 1 ) - && - ( ( cache_ptr->pl_head_ptr != cache_ptr->pl_tail_ptr ) - || - ( cache_ptr->pl_head_ptr == NULL ) - || - ( cache_ptr->pl_head_ptr->size != cache_ptr->pl_size ) - ) + && + ( ( cache_ptr->pl_head_ptr != cache_ptr->pl_tail_ptr ) + || + ( cache_ptr->pl_head_ptr == NULL ) + || + ( cache_ptr->pl_head_ptr->size != cache_ptr->pl_size ) + ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 3 failed") } if ( ( cache_ptr->pl_len >= 1 ) - && - ( ( cache_ptr->pl_head_ptr == NULL ) - || - ( cache_ptr->pl_head_ptr->prev != NULL ) - || - ( cache_ptr->pl_tail_ptr == NULL ) - || - ( cache_ptr->pl_tail_ptr->next != NULL ) - ) + && + ( ( cache_ptr->pl_head_ptr == NULL ) + || + ( cache_ptr->pl_head_ptr->prev != NULL ) + || + ( cache_ptr->pl_tail_ptr == NULL ) + || + ( cache_ptr->pl_tail_ptr->next != NULL ) + ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 4 failed") } entry_ptr = cache_ptr->pl_head_ptr; while ( entry_ptr != NULL ) { - if ( ( entry_ptr != cache_ptr->pl_head_ptr ) && - ( ( entry_ptr->prev == NULL ) || - ( entry_ptr->prev->next != entry_ptr ) ) ) { + if ( ( entry_ptr != cache_ptr->pl_head_ptr ) && + ( ( entry_ptr->prev == NULL ) || + ( entry_ptr->prev->next != entry_ptr ) ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 5 failed") + } - if ( ( entry_ptr != cache_ptr->pl_tail_ptr ) && - ( ( entry_ptr->next == NULL ) || - ( entry_ptr->next->prev != entry_ptr ) ) ) { + if ( ( entry_ptr != cache_ptr->pl_tail_ptr ) && + ( ( entry_ptr->next == NULL ) || + ( entry_ptr->next->prev != entry_ptr ) ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 6 failed") + } - if ( ! entry_ptr->is_protected ) { + if ( ! entry_ptr->is_protected ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 7 failed") + } - if ( ( entry_ptr->is_read_only ) && - ( entry_ptr->ro_ref_count <= 0 ) ) { + if ( ( entry_ptr->is_read_only ) && + ( entry_ptr->ro_ref_count <= 0 ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed") - } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 8 failed") + } - len++; - size += entry_ptr->size; - entry_ptr = entry_ptr->next; + len++; + size += entry_ptr->size; + entry_ptr = entry_ptr->next; } if ( ( cache_ptr->pl_len != len ) || - ( cache_ptr->pl_size != size ) ) { + ( cache_ptr->pl_size != size ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 9 failed") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Check 9 failed") } done: if ( ret_value != SUCCEED ) { - HDassert(0); + HDassert(0); } FUNC_LEAVE_NOAPI(ret_value) @@ -9852,6 +11199,66 @@ done: /*------------------------------------------------------------------------- * + * Function: H5C_entry_in_skip_list + * + * Purpose: Debugging function that scans skip list to see if it + * is in present. We need this, as it is possible for + * an entry to be in the skip list twice. + * + * Return: FALSE if the entry is not in the skip list, and TRUE + * if it is. + * + * Programmer: John Mainzer, 11/1/14 + * + * Changes: + * + * None. + * + *------------------------------------------------------------------------- + */ +#if H5C_DO_SLIST_SANITY_CHECKS + +static hbool_t +H5C_entry_in_skip_list(H5C_t * cache_ptr, H5C_cache_entry_t *target_ptr) +{ + hbool_t in_slist = FALSE; + H5SL_node_t * node_ptr = NULL; + H5C_cache_entry_t * entry_ptr = NULL; + + HDassert( cache_ptr ); + HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC ); + HDassert( cache_ptr->slist_ptr ); + + node_ptr = H5SL_first(cache_ptr->slist_ptr); + + while ( ( node_ptr != NULL ) && ( ! in_slist ) ) + { + entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); + + HDassert( entry_ptr ); + HDassert( entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC ); + HDassert( entry_ptr->is_dirty ); + HDassert( entry_ptr->in_slist ); + + if ( entry_ptr == target_ptr ) { + + in_slist = TRUE; + + } else { + + node_ptr = H5SL_next(node_ptr); + } + } + + return(in_slist); + +} /* H5C_entry_in_skip_list() */ + +#endif /* H5C_DO_SLIST_SANITY_CHECKS */ + + +/*------------------------------------------------------------------------- + * * Function: H5C_get_entry_ptr_from_addr() * * Purpose: Debugging function that attempts to look up an entry in the @@ -9893,7 +11300,7 @@ done: #ifndef NDEBUG herr_t H5C_get_entry_ptr_from_addr(const H5F_t *f, - haddr_t addr, + haddr_t addr, void ** entry_ptr_ptr) { H5C_t * cache_ptr; @@ -9917,21 +11324,21 @@ H5C_get_entry_ptr_from_addr(const H5F_t *f, */ if ( ( cache_ptr == NULL ) || ( cache_ptr->magic != H5C__H5C_T_MAGIC ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.") } H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL) if ( entry_ptr == NULL ) { - /* the entry doesn't exist in the cache -- report this - * and quit. - */ - *entry_ptr_ptr = NULL; + /* the entry doesn't exist in the cache -- report this + * and quit. + */ + *entry_ptr_ptr = NULL; } else { - *entry_ptr_ptr = entry_ptr; + *entry_ptr_ptr = entry_ptr; /* increment call counter */ (cache_ptr->get_entry_ptr_from_addr_counter)++; @@ -9978,10 +11385,10 @@ done: #ifndef NDEBUG herr_t H5C_verify_entry_type(const H5F_t *f, - haddr_t addr, - const H5C_class_t * expected_type, - hbool_t * in_cache_ptr, - hbool_t * type_ok_ptr) + haddr_t addr, + const H5C_class_t * expected_type, + hbool_t * in_cache_ptr, + hbool_t * type_ok_ptr) { H5C_t * cache_ptr; H5C_cache_entry_t * entry_ptr = NULL; @@ -10005,21 +11412,21 @@ H5C_verify_entry_type(const H5F_t *f, */ if ( ( cache_ptr == NULL ) || ( cache_ptr->magic != H5C__H5C_T_MAGIC ) ) { - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.") + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry.") } H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL) if ( entry_ptr == NULL ) { - /* the entry doesn't exist in the cache -- report this - * and quit. - */ - *in_cache_ptr = FALSE; + /* the entry doesn't exist in the cache -- report this + * and quit. + */ + *in_cache_ptr = FALSE; } else { - *in_cache_ptr = TRUE; + *in_cache_ptr = TRUE; *type_ok_ptr = (expected_type == entry_ptr->type); } @@ -10104,11 +11511,11 @@ H5C_tag_entry(H5C_t * cache_ptr, H5C_cache_entry_t * entry_ptr, hid_t dxpl_id) /* Get the dataset transfer property list */ if(NULL == (dxpl = (H5P_genplist_t *)H5I_object_verify(dxpl_id, H5I_GENPROP_LST))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list") + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list") /* Get the tag from the DXPL */ if((H5P_get(dxpl, "H5C_tag", &tag)) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to query property value") + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to query property value") /* Apply the tag to the entry */ entry_ptr->tag = tag.value; @@ -10120,7 +11527,6 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_tag_entry */ - /*------------------------------------------------------------------------- * * Function: H5C_evict_tagged_entries @@ -10135,7 +11541,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5C_evict_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, haddr_t tag) +H5C_evict_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag) { /* Variable Declarations */ herr_t status; @@ -10144,9 +11550,7 @@ H5C_evict_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_ int i; hbool_t evicted_entries_last_pass; hbool_t pinned_entries_need_evicted; - hbool_t first_flush = TRUE; - - H5C_t *cache_ptr = NULL; + H5C_t *cache_ptr = NULL; herr_t ret_value = SUCCEED; /* Function Enter Macro */ @@ -10165,66 +11569,64 @@ H5C_evict_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_ /* Start evicting entries */ do { - /* Reset pinned/evicted trackers */ - pinned_entries_need_evicted = FALSE; - evicted_entries_last_pass = FALSE; + /* Reset pinned/evicted trackers */ + pinned_entries_need_evicted = FALSE; + evicted_entries_last_pass = FALSE; - /* Iterate through entries in the index. */ - for (i = 0; i < H5C__HASH_TABLE_LEN; i++) { + /* Iterate through entries in the index. */ + for (i = 0; i < H5C__HASH_TABLE_LEN; i++) { - next_entry_ptr = cache_ptr->index[i]; + next_entry_ptr = cache_ptr->index[i]; - while ( next_entry_ptr != NULL ) { + while ( next_entry_ptr != NULL ) { - entry_ptr = next_entry_ptr; - next_entry_ptr = entry_ptr->ht_next; + entry_ptr = next_entry_ptr; + next_entry_ptr = entry_ptr->ht_next; if(( entry_ptr->tag == tag ) || ( entry_ptr->globality == H5C_GLOBALITY_MAJOR)) { - /* This entry will need to be evicted */ - - if ( entry_ptr->is_protected ) { - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict protected entry"); - } else if (entry_ptr->is_dirty) { - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict dirty entry"); - } else if (entry_ptr->is_pinned) { - - /* Can't evict at this time, but let's note that we hit a pinned - entry and we'll loop back around again (as evicting other - entries will hopefully unpin this entry) */ + /* This entry will need to be evicted */ + + if ( entry_ptr->is_protected ) { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict protected entry"); + } else if (entry_ptr->is_dirty) { + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Cannot evict dirty entry"); + } else if (entry_ptr->is_pinned) { + + /* Can't evict at this time, but let's note that we hit a pinned + entry and we'll loop back around again (as evicting other + entries will hopefully unpin this entry) */ - pinned_entries_need_evicted = TRUE; + pinned_entries_need_evicted = TRUE; - } else { + } else { - /* Evict the Entry */ + /* Evict the Entry */ - status = H5C_flush_single_entry(f, - primary_dxpl_id, - secondary_dxpl_id, - entry_ptr->type, - entry_ptr->addr, - H5C__FLUSH_INVALIDATE_FLAG | H5C__FLUSH_CLEAR_ONLY_FLAG, - &first_flush, - TRUE); + status = H5C_flush_single_entry(f, + dxpl_id, + entry_ptr->addr, + H5C__FLUSH_INVALIDATE_FLAG | H5C__FLUSH_CLEAR_ONLY_FLAG, + TRUE, + NULL); - if ( status < 0 ) { + if ( status < 0 ) { - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ - "Entry eviction failed.") + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, \ + "Entry eviction failed.") - } + } - evicted_entries_last_pass = TRUE; + evicted_entries_last_pass = TRUE; - } /* end if */ + } /* end if */ - } /* end if */ + } /* end if */ - } /* end while */ + } /* end while */ - } /* end for */ + } /* end for */ /* Keep doing this until we have stopped evicted entries */ } while ((evicted_entries_last_pass == TRUE)); @@ -10232,7 +11634,7 @@ H5C_evict_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_ /* If we stop evicting entries and pinned entries still need evicted, then we have a problem. */ if (pinned_entries_need_evicted) { - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Pinned entries still need evicted?!"); + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Pinned entries still need evicted?!"); } /* end if */ done: @@ -10275,26 +11677,26 @@ H5C_mark_tagged_entries(H5C_t * cache_ptr, haddr_t tag, hbool_t mark_clean) * when flushing based on tag value */ for(u = 0; u < H5C__HASH_TABLE_LEN; u++) { - entry_ptr = cache_ptr->index[u]; + entry_ptr = cache_ptr->index[u]; - while ( entry_ptr != NULL ) { + while ( entry_ptr != NULL ) { - if (( entry_ptr->tag == tag ) || - ( entry_ptr->globality == H5C_GLOBALITY_MAJOR)) { + if (( entry_ptr->tag == tag ) || + ( entry_ptr->globality == H5C_GLOBALITY_MAJOR)) { - /* We only want to set the flush marker on entries that - * actually need flushed (i.e., dirty ones), unless - * we've specified otherwise with the mark_clean flag */ - if (entry_ptr->is_dirty || mark_clean) { + /* We only want to set the flush marker on entries that + * actually need flushed (i.e., dirty ones), unless + * we've specified otherwise with the mark_clean flag */ + if (entry_ptr->is_dirty || mark_clean) { - entry_ptr->flush_marker = TRUE; + entry_ptr->flush_marker = TRUE; - } /* end if */ + } /* end if */ - } /* end if */ + } /* end if */ - entry_ptr = entry_ptr->ht_next; - } /* end while */ + entry_ptr = entry_ptr->ht_next; + } /* end while */ } /* for */ FUNC_LEAVE_NOAPI(SUCCEED) @@ -10315,7 +11717,7 @@ H5C_mark_tagged_entries(H5C_t * cache_ptr, haddr_t tag, hbool_t mark_clean) *------------------------------------------------------------------------- */ static herr_t -H5C_flush_marked_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, H5C_t * cache_ptr) +H5C_flush_marked_entries(H5F_t * f, hid_t dxpl_id, H5C_t * cache_ptr) { herr_t ret_value = SUCCEED; @@ -10326,9 +11728,8 @@ H5C_flush_marked_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_ HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); /* Flush all marked entries */ - if(H5C_flush_cache(f, primary_dxpl_id, secondary_dxpl_id, - H5C__FLUSH_MARKED_ENTRIES_FLAG | H5C__FLUSH_IGNORE_PROTECTED_FLAG) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush cache") + if(H5C_flush_cache(f, dxpl_id, H5C__FLUSH_MARKED_ENTRIES_FLAG | H5C__FLUSH_IGNORE_PROTECTED_FLAG) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush cache") done: FUNC_LEAVE_NOAPI(ret_value) @@ -10349,7 +11750,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5C_flush_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, haddr_t tag) +H5C_flush_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag) { /* Variable Declarations */ H5C_t *cache_ptr = NULL; @@ -10367,11 +11768,11 @@ H5C_flush_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_ /* Mark all entries with specified tag */ if((result = H5C_mark_tagged_entries(cache_ptr, tag, FALSE)) < 0 ) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't mark tagged entries") + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't mark tagged entries") /* Flush all marked entries */ - if(H5C_flush_marked_entries(f, primary_dxpl_id, secondary_dxpl_id, cache_ptr) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush marked entries") + if(H5C_flush_marked_entries(f, dxpl_id, cache_ptr) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush marked entries") done: FUNC_LEAVE_NOAPI(ret_value) @@ -10403,15 +11804,14 @@ H5C_retag_entries(H5C_t * cache_ptr, haddr_t src_tag, haddr_t dest_tag) /* Iterate through entries, retagging those with the src_tag tag */ for(u = 0; u < H5C__HASH_TABLE_LEN; u++) { - entry_ptr = cache_ptr->index[u]; - while(entry_ptr != NULL) { - if(cache_ptr->index[u] != NULL) { - if((cache_ptr->index[u])->tag == src_tag) { - (cache_ptr->index[u])->tag = dest_tag; - } - } /* end if */ - entry_ptr = entry_ptr->ht_next; - } /* end while */ + entry_ptr = cache_ptr->index[u]; + while(entry_ptr != NULL) { + if(cache_ptr->index[u] != NULL) + if((cache_ptr->index[u])->tag == src_tag) { + (cache_ptr->index[u])->tag = dest_tag; + } + entry_ptr = entry_ptr->ht_next; + } /* end while */ } /* end for */ FUNC_LEAVE_NOAPI_VOID @@ -10500,7 +11900,7 @@ H5C_cork(H5C_t * cache_ptr, haddr_t obj_addr, unsigned action, hbool_t *corked) default: /* should be unreachable */ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown cork action") - break; + break; } /* end switch */ if(action != H5C__GET_CORKED) @@ -10545,15 +11945,15 @@ H5C_mark_tagged_entries_cork(H5C_t *cache_ptr, haddr_t obj_addr, hbool_t val) /* and set the entry's "corked" field to "val" */ for(u = 0; u < H5C__HASH_TABLE_LEN; u++) { - entry_ptr = cache_ptr->index[u]; + entry_ptr = cache_ptr->index[u]; - while(entry_ptr != NULL) { + while(entry_ptr != NULL) { - if(entry_ptr->tag == obj_addr) + if(entry_ptr->tag == obj_addr) entry_ptr->is_corked = val; - entry_ptr = entry_ptr->ht_next; - } /* end while */ + entry_ptr = entry_ptr->ht_next; + } /* end while */ } /* end for */ FUNC_LEAVE_NOAPI(SUCCEED) @@ -10586,22 +11986,22 @@ H5C__mark_flush_dep_dirty(H5C_cache_entry_t * entry) /* Sanity checks */ HDassert(entry); HDassert((entry->is_dirty && entry->flush_dep_ndirty_children == 0) - || (!entry->is_dirty && entry->flush_dep_ndirty_children == 1)); + || (!entry->is_dirty && entry->flush_dep_ndirty_children == 1)); /* Iterate over the parent entries, if any */ for(i=0; i<entry->flush_dep_nparents; i++) { - /* Sanity check */ - HDassert(entry->flush_dep_parent[i]->flush_dep_ndirty_children - < entry->flush_dep_parent[i]->flush_dep_nchildren); - - /* Adjust the parent's number of dirty children */ - entry->flush_dep_parent[i]->flush_dep_ndirty_children++; - - /* Propagate the flush dep dirty flag up the chain if necessary */ - if(!entry->flush_dep_parent[i]->is_dirty - && entry->flush_dep_parent[i]->flush_dep_ndirty_children == 1) - if(H5C__mark_flush_dep_dirty(entry->flush_dep_parent[i]) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't propagate flush dep dirty flag") + /* Sanity check */ + HDassert(entry->flush_dep_parent[i]->flush_dep_ndirty_children + < entry->flush_dep_parent[i]->flush_dep_nchildren); + + /* Adjust the parent's number of dirty children */ + entry->flush_dep_parent[i]->flush_dep_ndirty_children++; + + /* Propagate the flush dep dirty flag up the chain if necessary */ + if(!entry->flush_dep_parent[i]->is_dirty + && entry->flush_dep_parent[i]->flush_dep_ndirty_children == 1) + if(H5C__mark_flush_dep_dirty(entry->flush_dep_parent[i]) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't propagate flush dep dirty flag") } /* end for */ done: @@ -10638,17 +12038,17 @@ H5C__mark_flush_dep_clean(H5C_cache_entry_t * entry) /* Iterate over the parent entries, if any */ for(i=0; i<entry->flush_dep_nparents; i++) { - /* Sanity check */ - HDassert(entry->flush_dep_parent[i]->flush_dep_ndirty_children > 0); + /* Sanity check */ + HDassert(entry->flush_dep_parent[i]->flush_dep_ndirty_children > 0); - /* Adjust the parent's number of dirty children */ - entry->flush_dep_parent[i]->flush_dep_ndirty_children--; + /* Adjust the parent's number of dirty children */ + entry->flush_dep_parent[i]->flush_dep_ndirty_children--; - /* Propagate the flush dep clean flag up the chain if necessary */ - if(!entry->flush_dep_parent[i]->is_dirty - && entry->flush_dep_parent[i]->flush_dep_ndirty_children == 0) - if(H5C__mark_flush_dep_clean(entry->flush_dep_parent[i]) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't propagate flush dep clean flag") + /* Propagate the flush dep clean flag up the chain if necessary */ + if(!entry->flush_dep_parent[i]->is_dirty + && entry->flush_dep_parent[i]->flush_dep_ndirty_children == 0) + if(H5C__mark_flush_dep_clean(entry->flush_dep_parent[i]) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't propagate flush dep clean flag") } /* end for */ done: @@ -10689,9 +12089,8 @@ H5C__assert_flush_dep_nocycle(H5C_cache_entry_t * entry, /* Iterate over entry's parents (if any) */ for(i=0; i<entry->flush_dep_nparents; i++) - H5C__assert_flush_dep_nocycle(entry->flush_dep_parent[i], base_entry); + H5C__assert_flush_dep_nocycle(entry->flush_dep_parent[i], base_entry); FUNC_LEAVE_NOAPI_VOID } /* H5C__assert_flush_dep_nocycle() */ #endif /* NDEBUG */ - diff --git a/src/H5Cpkg.h b/src/H5Cpkg.h index 61c0539..c8a5a7c 100644 --- a/src/H5Cpkg.h +++ b/src/H5Cpkg.h @@ -564,6 +564,15 @@ if ( ( (entry_ptr) == NULL ) || \ #define H5C__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr) \ ((cache_ptr)->unpins)[(entry_ptr)->type->id]++; +#define H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr) \ + ((cache_ptr)->slist_scan_restarts)++; + +#define H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr) \ + ((cache_ptr)->LRU_scan_restarts)++; + +#define H5C__UPDATE_STATS_FOR_HASH_BUCKET_SCAN_RESTART(cache_ptr) \ + ((cache_ptr)->hash_bucket_scan_restarts)++; + #if H5C_COLLECT_CACHE_ENTRY_STATS #define H5C__RESET_CACHE_ENTRY_STATS(entry_ptr) \ @@ -590,9 +599,12 @@ if ( ( (entry_ptr) == NULL ) || \ ((entry_ptr)->flushes)++; \ } -#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) \ -{ \ - (((cache_ptr)->evictions)[(entry_ptr)->type->id])++; \ +#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr, take_ownership) \ +{ \ + if ( take_ownership ) \ + (((cache_ptr)->take_ownerships)[(entry_ptr)->type->id])++; \ + else \ + (((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] = \ @@ -700,8 +712,13 @@ if ( ( (entry_ptr) == NULL ) || \ (((cache_ptr)->pinned_flushes)[(entry_ptr)->type->id])++; \ } -#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) \ - (((cache_ptr)->evictions)[(entry_ptr)->type->id])++; +#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr, take_ownership) \ +{ \ + if ( take_ownership ) \ + (((cache_ptr)->take_ownerships)[(entry_ptr)->type->id])++; \ + else \ + (((cache_ptr)->evictions)[(entry_ptr)->type->id])++; \ +} #define H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) \ { \ @@ -771,10 +788,13 @@ if ( ( (entry_ptr) == NULL ) || \ #define H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) #define H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) #define H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr) -#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) +#define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr, take_ownership) #define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit) #define H5C__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr) #define H5C__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr) +#define H5C__UPDATE_STATS_FOR_SLIST_SCAN_RESTART(cache_ptr) +#define H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr) +#define H5C__UPDATE_STATS_FOR_HASH_BUCKET_SCAN_RESTART(cache_ptr) #endif /* H5C_COLLECT_CACHE_STATS */ @@ -819,11 +839,25 @@ if ( ( (cache_ptr) == NULL ) || \ ( H5C__HASH_FCN((entry_ptr)->addr) >= H5C__HASH_TABLE_LEN ) || \ ( (cache_ptr)->index_size != \ ((cache_ptr)->clean_index_size + \ - (cache_ptr)->dirty_index_size) ) ) { \ + (cache_ptr)->dirty_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) ) { \ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, \ "Pre HT insert SC failed") \ } +#define H5C__POST_HT_INSERT_SC(cache_ptr, fail_val) \ +if ( ( (cache_ptr) == NULL ) || \ + ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \ + ( (cache_ptr)->index_size != \ + ((cache_ptr)->clean_index_size + \ + (cache_ptr)->dirty_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, \ + "Post HT insert SC failed") \ +} + #define H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) \ if ( ( (cache_ptr) == NULL ) || \ ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \ @@ -844,10 +878,28 @@ if ( ( (cache_ptr) == NULL ) || \ ( (entry_ptr)->ht_prev != NULL ) ) || \ ( (cache_ptr)->index_size != \ ((cache_ptr)->clean_index_size + \ - (cache_ptr)->dirty_index_size) ) ) { \ + (cache_ptr)->dirty_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) ) { \ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Pre HT remove SC failed") \ } +#define H5C__POST_HT_REMOVE_SC(cache_ptr, entry_ptr) \ +if ( ( (cache_ptr) == NULL ) || \ + ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) || \ + ( (entry_ptr) == NULL ) || \ + ( ! H5F_addr_defined((entry_ptr)->addr) ) || \ + ( (entry_ptr)->size <= 0 ) || \ + ( (entry_ptr)->ht_prev != NULL ) || \ + ( (entry_ptr)->ht_prev != NULL ) || \ + ( (cache_ptr)->index_size != \ + ((cache_ptr)->clean_index_size + \ + (cache_ptr)->dirty_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) ) { \ + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Post HT remove SC failed") \ +} + /* (Keep in sync w/H5C_TEST__PRE_HT_SEARCH_SC macro in test/cache_common.h -QAK) */ #define H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) \ if ( ( (cache_ptr) == NULL ) || \ @@ -906,6 +958,8 @@ if ( ( (cache_ptr) == NULL ) || \ ( (cache_ptr)->index_size != \ ((cache_ptr)->clean_index_size + \ (cache_ptr)->dirty_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \ ( ( !( was_clean ) || \ ( (cache_ptr)->clean_index_size < (old_size) ) ) && \ ( ( (was_clean) ) || \ @@ -924,6 +978,8 @@ if ( ( (cache_ptr) == NULL ) || \ ( (cache_ptr)->index_size != \ ((cache_ptr)->clean_index_size + \ (cache_ptr)->dirty_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) || \ ( ( !((entry_ptr)->is_dirty ) || \ ( (cache_ptr)->dirty_index_size < (new_size) ) ) && \ ( ( ((entry_ptr)->is_dirty) ) || \ @@ -944,7 +1000,9 @@ if ( \ ( (cache_ptr)->index_size < (entry_ptr)->size ) || \ ( (cache_ptr)->dirty_index_size < (entry_ptr)->size ) || \ ( (cache_ptr)->index_size != \ - ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) ) { \ + ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) ) { \ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "Pre HT update for entry clean SC failed") \ } @@ -959,21 +1017,27 @@ if ( \ ( (cache_ptr)->index_size < (entry_ptr)->size ) || \ ( (cache_ptr)->clean_index_size < (entry_ptr)->size ) || \ ( (cache_ptr)->index_size != \ - ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) ) { \ + ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) ) { \ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "Pre HT update for entry dirty SC failed") \ } #define H5C__POST_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr) \ -if ( (cache_ptr)->index_size != \ - ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) { \ +if ( ( (cache_ptr)->index_size != \ + ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) ) { \ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "Post HT update for entry clean SC failed") \ } #define H5C__POST_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr) \ -if ( (cache_ptr)->index_size != \ - ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) { \ +if ( ( (cache_ptr)->index_size != \ + ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->clean_index_size) ) || \ + ( (cache_ptr)->index_size < ((cache_ptr)->dirty_index_size) ) ) { \ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ "Post HT update for entry dirty SC failed") \ } @@ -981,7 +1045,9 @@ if ( (cache_ptr)->index_size != \ #else /* H5C_DO_SANITY_CHECKS */ #define H5C__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) +#define H5C__POST_HT_INSERT_SC(cache_ptr, fail_val) #define H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr) +#define H5C__POST_HT_REMOVE_SC(cache_ptr, entry_ptr) #define H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val) #define H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val) #define H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) @@ -1017,9 +1083,10 @@ if ( (cache_ptr)->index_size != \ (cache_ptr)->clean_index_size += (entry_ptr)->size; \ if ((entry_ptr)->flush_me_last) { \ (cache_ptr)->num_last_entries++; \ - HDassert((cache_ptr)->num_last_entries == 1); \ + HDassert((cache_ptr)->num_last_entries <= 2); \ } \ H5C__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) \ + H5C__POST_HT_INSERT_SC(cache_ptr, fail_val) \ } #define H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr) \ @@ -1043,9 +1110,10 @@ if ( (cache_ptr)->index_size != \ (cache_ptr)->clean_index_size -= (entry_ptr)->size; \ if ((entry_ptr)->flush_me_last) { \ (cache_ptr)->num_last_entries--; \ - HDassert((cache_ptr)->num_last_entries == 0); \ + HDassert((cache_ptr)->num_last_entries <= 1); \ } \ H5C__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) \ + H5C__POST_HT_REMOVE_SC(cache_ptr, entry_ptr) \ } #define H5C__SEARCH_INDEX(cache_ptr, Addr, entry_ptr, fail_val) \ @@ -1196,9 +1264,20 @@ if ( (cache_ptr)->index_size != \ * able to dirty, resize and/or move entries during the * flush. * + * JRM -- 12/13/14 + * Added code to set cache_ptr->slist_changed to TRUE + * when an entry is inserted in the slist. + * *------------------------------------------------------------------------- */ +#if H5C_DO_SLIST_SANITY_CHECKS +#define ENTRY_IN_SLIST(cache_ptr, entry_ptr) \ + H5C_entry_in_skip_list((cache_ptr), (entry_ptr)) +#else /* H5C_DO_SLIST_SANITY_CHECKS */ +#define ENTRY_IN_SLIST(cache_ptr, entry_ptr) FALSE +#endif /* H5C_DO_SLIST_SANITY_CHECKS */ + #if H5C_DO_SANITY_CHECKS #define H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val) \ @@ -1209,12 +1288,14 @@ if ( (cache_ptr)->index_size != \ HDassert( (entry_ptr)->size > 0 ); \ HDassert( H5F_addr_defined((entry_ptr)->addr) ); \ HDassert( !((entry_ptr)->in_slist) ); \ + HDassert( !ENTRY_IN_SLIST((cache_ptr), (entry_ptr)) ); \ \ 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_changed = TRUE; \ (cache_ptr)->slist_len++; \ (cache_ptr)->slist_size += (entry_ptr)->size; \ (cache_ptr)->slist_len_increase++; \ @@ -1235,12 +1316,14 @@ if ( (cache_ptr)->index_size != \ HDassert( (entry_ptr)->size > 0 ); \ HDassert( H5F_addr_defined((entry_ptr)->addr) ); \ HDassert( !((entry_ptr)->in_slist) ); \ + HDassert( !ENTRY_IN_SLIST((cache_ptr), (entry_ptr)) ); \ \ 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_changed = TRUE; \ (cache_ptr)->slist_len++; \ (cache_ptr)->slist_size += (entry_ptr)->size; \ \ @@ -1281,6 +1364,10 @@ if ( (cache_ptr)->index_size != \ * Updated sanity checks for the new is_read_only and * ro_ref_count fields in H5C_cache_entry_t. * + * JRM -- 12/13/14 + * Added code to set cache_ptr->slist_changed to TRUE + * when an entry is removed from the slist. + * *------------------------------------------------------------------------- */ @@ -1302,6 +1389,7 @@ if ( (cache_ptr)->index_size != \ "Can't delete entry from skip list.") \ \ HDassert( (cache_ptr)->slist_len > 0 ); \ + (cache_ptr)->slist_changed = TRUE; \ (cache_ptr)->slist_len--; \ HDassert( (cache_ptr)->slist_size >= (entry_ptr)->size ); \ (cache_ptr)->slist_size -= (entry_ptr)->size; \ @@ -1332,6 +1420,11 @@ if ( (cache_ptr)->index_size != \ * able to dirty, resize and/or move entries during the * flush. * + * JRM -- 12/13/14 + * Note that we do not set cache_ptr->slist_changed to TRUE + * in this case, as the structure of the slist is not + * modified. + * *------------------------------------------------------------------------- */ @@ -2720,6 +2813,10 @@ if ( (cache_ptr)->index_size != \ * the max_cache_size limit until the next time the cache * attempts to load or insert an entry. * + * d) When the evictions_enabled field is false (see below), + * the cache size will increase without limit until the + * field is set to true. + * * min_clean_size: Nominal minimum number of clean bytes in the cache. * The cache attempts to maintain this number of bytes of * clean data so as to avoid case b) above. Again, this is @@ -2770,7 +2867,7 @@ if ( (cache_ptr)->index_size != \ * This value should not be mistaken for footprint of the * cache in memory. The average cache entry is small, and * the cache has a considerable overhead. Multiplying the - * index_size by two should yield a conservative estimate + * index_size by three should yield a conservative estimate * of the cache's memory footprint. * * clean_index_size: Number of bytes of clean entries currently stored in @@ -2781,12 +2878,7 @@ if ( (cache_ptr)->index_size != \ * * WARNING: * - * 1) The clean_index_size field is not maintained by the - * index macros, as the hash table doesn't care whether - * the entry is clean or dirty. Instead the field is - * maintained in the H5C__UPDATE_RP macros. - * - * 2) The value of the clean_index_size must not be mistaken + * The value of the clean_index_size must not be mistaken * for the current clean size of the cache. Rather, the * clean size of the cache is the current value of * clean_index_size plus the amount of empty space (if any) @@ -2798,13 +2890,6 @@ if ( (cache_ptr)->index_size != \ * Thus we should have the invariant that clean_index_size + * dirty_index_size == index_size. * - * WARNING: - * - * 1) The dirty_index_size field is not maintained by the - * index macros, as the hash table doesn't care whether - * the entry is clean or dirty. Instead the field is - * maintained in the H5C__UPDATE_RP macros. - * * index: Array of pointer to H5C_cache_entry_t of size * H5C__HASH_TABLE_LEN. At present, this value is a power * of two, not the usual prime number. @@ -2820,6 +2905,37 @@ if ( (cache_ptr)->index_size != \ * changing the H5C__HASH_FCN macro and the deletion of the * H5C__HASH_MASK #define. No other changes should be required. * + * With the addition of the take ownership flag, it is possible that + * an entry may be removed from the cache as the result of the flush of + * a second entry. In general, this causes little trouble, but it is + * possible that the entry removed may be the next entry in the scan of + * a list. In this case, we must be able to detect the fact that the + * entry has been removed, so that the scan doesn't attempt to proceed with + * an entry that is no longer in the cache. + * + * The following fields are maintained to facilitate this. + * + * entries_removed_counter: Counter that is incremented each time an + * entry is removed from the cache by any means (eviction, + * expungement, or take ownership at this point in time). + * Functions that perform scans on lists may set this field + * to zero prior to calling H5C_flush_single_entry(). + * Unexpected changes to the counter indicate that an entry + * was removed from the cache as a side effect of the flush. + * + * last_entry_removed_ptr: Pointer to the instance of H5C_cache_entry_t + * which contained the last entry to be removed from the cache, + * or NULL if there either is no such entry, or if a function + * performing a scan of a list has set this field to NULL prior + * to calling H5C_flush_single_entry(). + * + * WARNING!!! This field must NEVER be dereferenced. It is + * maintained to allow functions that perform scans of lists + * to compare this pointer with their pointers to next, thus + * allowing them to avoid unnecessary restarts of scans if the + * pointers don't match, and if entries_removed_counter is + * one. + * * * With the addition of cache entry tagging, it is possible that * an entry may be inserted into the cache without a tag during testing @@ -2839,6 +2955,21 @@ if ( (cache_ptr)->index_size != \ * are flushed. (this has been changed -- dirty entries are now removed from * the skip list as they are flushed. JRM - 10/25/05) * + * slist_changed: Boolean flag used to indicate whether the contents of + * the slist has changed since the last time this flag was + * reset. This is used in the cache flush code to detect + * conditions in which pre-serialize or serialize callbacks + * have modified the slist -- which obliges us to restart + * the scan of the slist from the beginning. + * + * slist_change_in_pre_serialize: Boolean flag used to indicate that + * a pre_serialize call has modified the slist since the + * last time this flag was reset. + * + * slist_change_in_serialize: Boolean flag used to indicate that + * a serialize call has modified the slist since the + * last time this flag was reset. + * * slist_len: Number of entries currently in the skip list * used to maintain a sorted list of dirty entries in the * cache. @@ -2869,6 +3000,11 @@ if ( (cache_ptr)->index_size != \ * explicit tests for that case should be added when said * HDasserts are removed. * + * Update: There are now two possible last entries + * (superblock and file driver info message). This + * number will probably increase as we add superblock + * messages. JRM -- 11/18/14 + * * With the addition of the fractal heap, the cache must now deal with * the case in which entries may be dirtied, moved, or have their sizes * changed during a flush. To allow sanity checks in this situation, the @@ -2877,10 +3013,11 @@ if ( (cache_ptr)->index_size != \ * * slist_len_increase: Number of entries that have been added to the * slist since the last time this field was set to zero. + * Note that this value can be negative. * * slist_size_increase: Total size of all entries that have been added * to the slist since the last time this field was set to - * zero. + * zero. Note that this value can be negative. * * cork_list_ptr: A skip list to track object addresses that are corked. * When an entry is inserted or protected in the cache, @@ -2924,9 +3061,9 @@ if ( (cache_ptr)->index_size != \ * replacement policy code). * * 2) A pinned entry can be accessed or modified at any time. - * Therefore, the cache must check with the entry owner - * before flushing it. If permission is denied, the - * cache just skips the entry in the flush. + * This places an additional burden on the associated pre-serialize + * and serialize callbacks, which must ensure the the entry is in + * a consistant state before creating an image of it. * * 3) A pinned entry can be marked as dirty (and possibly * change size) while it is unprotected. @@ -2984,7 +3121,8 @@ if ( (cache_ptr)->index_size != \ * be collective and the other processes will not know to participate. * * To deal with this issue, I have modified the usual LRU policy by adding - * clean and dirty LRU lists to the usual LRU list. + * clean and dirty LRU lists to the usual LRU list. In general, these + * lists are only exist in parallel builds. * * The clean LRU list is simply the regular LRU list with all dirty cache * entries removed. @@ -3001,7 +3139,7 @@ if ( (cache_ptr)->index_size != \ * * Even if we start with a completely clean cache, a sequence of protects * without unprotects can empty the clean LRU list. In this case, the - * cache must grow temporarily. At the next write, we will attempt to + * cache must grow temporarily. At the next sync point, we will attempt to * evict enough entries to reduce index_size to less than max_cache_size. * While this will usually be possible, all bets are off if enough entries * are protected. @@ -3011,14 +3149,14 @@ if ( (cache_ptr)->index_size != \ * * LRU_list_len: Number of cache entries currently on the LRU list. * - * Observe that LRU_list_len + pl_len must always equal - * index_len. + * Observe that LRU_list_len + pl_len + pel_len must always + * equal index_len. * * LRU_list_size: Number of bytes of cache entries currently residing on the * LRU list. * - * Observe that LRU_list_size + pl_size must always equal - * index_size. + * Observe that LRU_list_size + pl_size + pel_size must always + * equal index_size. * * LRU_head_ptr: Pointer to the head of the doubly linked LRU list. Cache * entries on this list are linked by their next and prev fields. @@ -3263,6 +3401,11 @@ if ( (cache_ptr)->index_size != \ * equal to the array index has been evicted from the cache in * the current epoch. * + * take_ownerships: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The + * cells are used to record the number of times an entry with + * type id equal to the array index has been removed from the + * cache via the H5C__TAKE_OWNERSHIP_FLAG in the current epoch. + * * moves: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells * are used to record the number of times an entry with type * id equal to the array index has been moved in the current @@ -3271,7 +3414,7 @@ if ( (cache_ptr)->index_size != \ * entry_flush_moves: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. * The cells are used to record the number of times an entry * with type id equal to the array index has been moved - * during its flush callback in the current epoch. + * during its pre-serialize callback in the current epoch. * * cache_flush_moves: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. * The cells are used to record the number of times an entry @@ -3316,7 +3459,8 @@ if ( (cache_ptr)->index_size != \ * entry_flush_size_changes: Array of int64 of length * H5C__MAX_NUM_TYPE_IDS + 1. The cells are used to record * the number of times an entry with type id equal to the - * array index has changed size while in its flush callback. + * array index has changed size while in its pre-serialize + * callback. * * cache_flush_size_changes: Array of int64 of length * H5C__MAX_NUM_TYPE_IDS + 1. The cells are used to record @@ -3389,7 +3533,33 @@ if ( (cache_ptr)->index_size != \ * * entries_scanned_to_make_space: Number of entries scanned only when looking * for entries to evict in order to make space in cache. - + * + * + * As entries are now capable of moving, loading, dirtying, and deleting + * other entries in their pre_serialize and serialize callbacks, it has + * been necessary to insert code to restart scans of lists so as to avoid + * improper behavior if the next entry in the list is the target of one on + * these operations. + * + * The following fields are use to count such occurances. They are used + * both in tests (to verify that the scan has been restarted), and to + * obtain estimates of how frequently these restarts occur. + * + * slist_scan_restarts: Number of times a scan of the slist (that contains + * calls to H5C_flush_single_entry()) has been restarted to + * avoid potential issues with change of status of the next + * entry in the scan. + * + * LRU_scan_restarts: Number of times a scan of the LRU list (that contains + * calls to H5C_flush_single_entry()) has been restarted to + * avoid potential issues with change of status of the next + * entry in the scan. + * + * hash_bucket_scan_restarts: Number of times a scan of a hash bucket list + * (that contains calls to H5C_flush_single_entry()) has been + * restarted to avoid potential issues with change of status + * of the next entry in the scan. + * * The remaining stats are collected only when both H5C_COLLECT_CACHE_STATS * and H5C_COLLECT_CACHE_ENTRY_STATS are true. * @@ -3460,9 +3630,17 @@ struct H5C_t { size_t dirty_index_size; H5C_cache_entry_t * (index[H5C__HASH_TABLE_LEN]); + /* Fields to detect entries removed during scans */ + int64_t entries_removed_counter; + H5C_cache_entry_t * last_entry_removed_ptr; + /* Field to disable tag validation */ hbool_t ignore_tags; + /* Fields for maintaining list of in-order entries, for flushing */ + hbool_t slist_changed; + hbool_t slist_change_in_pre_serialize; + hbool_t slist_change_in_serialize; int32_t slist_len; size_t slist_size; H5SL_t * slist_ptr; @@ -3539,6 +3717,7 @@ struct H5C_t { int64_t clears[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t flushes[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t evictions[H5C__MAX_NUM_TYPE_IDS + 1]; + int64_t take_ownerships[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t moves[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t entry_flush_moves[H5C__MAX_NUM_TYPE_IDS + 1]; int64_t cache_flush_moves[H5C__MAX_NUM_TYPE_IDS + 1]; @@ -3583,6 +3762,11 @@ struct H5C_t { int32_t max_entries_skipped_in_msic; int32_t max_entries_scanned_in_msic; int64_t entries_scanned_to_make_space; + + /* Fields for tracking skip list scan restarts */ + int64_t slist_scan_restarts; + int64_t LRU_scan_restarts; + int64_t hash_bucket_scan_restarts; #if H5C_COLLECT_CACHE_ENTRY_STATS int32_t max_accesses[H5C__MAX_NUM_TYPE_IDS + 1]; diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h index 902e635..4a3bf25 100644 --- a/src/H5Cprivate.h +++ b/src/H5Cprivate.h @@ -40,9 +40,30 @@ /* Library Private Macros */ /**************************/ -#define H5C_DO_SANITY_CHECKS 0 +#ifndef NDEBUG +#define H5C_DO_SANITY_CHECKS 1 +#define H5C_DO_SLIST_SANITY_CHECKS 0 #define H5C_DO_TAGGING_SANITY_CHECKS 1 #define H5C_DO_EXTREME_SANITY_CHECKS 0 +#else /* NDEBUG */ +/* With rare execptions, the following defines should be set + * to 0 if NDEBUG is defined + */ +#define H5C_DO_SANITY_CHECKS 0 +#define H5C_DO_SLIST_SANITY_CHECKS 0 +#define H5C_DO_TAGGING_SANITY_CHECKS 0 +#define H5C_DO_EXTREME_SANITY_CHECKS 0 +#endif /* NDEBUG */ + +/* Note: The memory sanity checks aren't going to work until I/O filters are + * changed to call a particular alloc/free routine for their buffers, + * because the H5AC__SERIALIZE_RESIZED_FLAG set by the fractal heap + * direct block serialize callback calls H5Z_pipeline(). When the I/O + * filters are changed, then we should implement "cache image alloc/free" + * routines that the fractal heap direct block (and global heap) serialize + * calls can use when resizing (and re-allocating) their image in the + * cache. -QAK */ +#define H5C_DO_MEMORY_SANITY_CHECKS 0 /* This sanity checking constant was picked out of the air. Increase * or decrease it if appropriate. Its purposes is to detect corrupt @@ -53,9 +74,15 @@ #define H5C_MAX_ENTRY_SIZE ((size_t)(32 * 1024 * 1024)) /* H5C_COLLECT_CACHE_STATS controls overall collection of statistics - * on cache activity. In general, this #define should be set to 0. + * on cache activity. In general, this #define should be set to 1 in + * debug mode, and 0 in production mode.. */ + +#ifndef NDEBUG +#define H5C_COLLECT_CACHE_STATS 1 +#else /* NDEBUG */ #define H5C_COLLECT_CACHE_STATS 0 +#endif /* NDEBUG */ /* H5C_COLLECT_CACHE_ENTRY_STATS controls collection of statistics * in individual cache entries. @@ -82,10 +109,21 @@ #define H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS 0 #endif /* H5_HAVE_PARALLEL */ -/* Flags returned from the 'flush' callback */ -#define H5C_CALLBACK__NO_FLAGS_SET 0x0 -#define H5C_CALLBACK__SIZE_CHANGED_FLAG 0x1 -#define H5C_CALLBACK__MOVED_FLAG 0x2 +/* Flags for cache client class behavior */ +#define H5C__CLASS_NO_FLAGS_SET ((unsigned)0x0) +#define H5C__CLASS_SPECULATIVE_LOAD_FLAG ((unsigned)0x1) +#define H5C__CLASS_COMPRESSED_FLAG ((unsigned)0x2) +/* The following flags may only appear in test code */ +/* The H5C__CLASS_SKIP_READS & H5C__CLASS_SKIP_WRITES flags are used in H5Oproxy.c */ +#define H5C__CLASS_NO_IO_FLAG ((unsigned)0x4) +#define H5C__CLASS_SKIP_READS ((unsigned)0x8) +#define H5C__CLASS_SKIP_WRITES ((unsigned)0x10) + +/* Flags for pre-serialize callback */ +#define H5C__SERIALIZE_NO_FLAGS_SET ((unsigned)0) +#define H5C__SERIALIZE_RESIZED_FLAG ((unsigned)0x1) +#define H5C__SERIALIZE_MOVED_FLAG ((unsigned)0x2) +#define H5C__SERIALIZE_COMPRESSED_FLAG ((unsigned)0x4) /* Upper and lower limits on cache size. These limits are picked * out of a hat -- you should be able to change them as necessary. @@ -104,11 +142,9 @@ #define H5C__DEFAULT_MAX_CACHE_SIZE ((size_t)(4 * 1024 * 1024)) #define H5C__DEFAULT_MIN_CLEAN_SIZE ((size_t)(2 * 1024 * 1024)) -#ifndef NDEBUG /* Values for cache entry magic field */ #define H5C__H5C_CACHE_ENTRY_T_MAGIC 0x005CAC0A #define H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC 0xDeadBeef -#endif /* NDEBUG */ /* Cache configuration validation definitions */ #define H5C_RESIZE_CFG__VALIDATE_GENERAL 0x1 @@ -161,9 +197,13 @@ * These flags apply to H5C_insert_entry(): * H5C__SET_FLUSH_MARKER_FLAG * H5C__PIN_ENTRY_FLAG + * H5C__FLUSH_LAST_FLAG ; super block only + * H5C__FLUSH_COLLECTIVELY_FLAG ; super block only * * These flags apply to H5C_protect() * H5C__READ_ONLY_FLAG + * H5C__FLUSH_LAST_FLAG ; super block only + * H5C__FLUSH_COLLECTIVELY_FLAG ; super block only * * These flags apply to H5C_unprotect(): * H5C__SET_FLUSH_MARKER_FLAG @@ -238,64 +278,928 @@ typedef enum { } H5C_tag_globality_t; /* - * Class methods pertaining to caching. Each type of cached object will - * have a constant variable with permanent life-span that describes how - * to cache the object. That variable will be of type H5C_class_t and - * have the following required fields... * - * LOAD: Loads an object from disk to memory. The function - * should allocate some data structure and return it. + * Struct H5C_class_t + * + * Instances of H5C_class_t are used to specify the callback functions + * used by the metadata cache for each class of metadata cache entry. + * The fields of the structure are discussed below: + * + * id: Integer field containing the unique ID of the class of metadata + * cache entries. + * + * name: Pointer to a string containing the name of the class of metadata + * cache entries. + * + * mem_type: Instance of H5FD_mem_t, that is used to supply the + * mem type passed into H5F_block_read(). + * + * flags: Flags indicating class-specific behavior. + * + * Whoever created the flags field neglected to document the meanings + * of the flags he created. Hence the following discussion of the + * H5C__CLASS_SPECULATIVE_LOAD_FLAG and (to a lesser extent) + * H5C__CLASS_COMPRESSED_FLAG should be viewed with suspicion, + * as the meanings are divined from the source code, and thus may be + * inaccurate. Please correct any errors you find. + * + * Possible flags are: + * + * H5C__CLASS_NO_FLAGS_SET: No special processing. + * + * H5C__CLASS_SPECULATIVE_LOAD_FLAG: This flag appears to be used + * only in H5C_load_entry(). When it is set, entries are + * permitted to change their sizes on the first attempt + * to load. + * + * If the new size is larger than the old, the read buffer + * is reallocated to the new size, loaded from file, and the + * deserialize routine is called a second time on the + * new buffer. The entry returned by the first call to + * the deserialize routine is discarded (via the free_icr + * call) after the new size is retrieved (via the image_len + * call). Note that the new size is used as the size of the + * entry in the cache. + * + * If the new size is smaller than the old, no new loads + * or desearializes are performed, but the new size becomes + * the size of the entry in the cache. + * + * When this flag is set, an attempt to read past the + * end of file is pemitted. In this case, if the size + * returned get_load_size callback would result in a + * read past the end of file, the size is trunkated to + * avoid this, and processing proceeds as normal. + * + * H5C__CLASS_COMPRESSED_FLAG: This flags indicates that the entry + * may be compressed -- i.e. its on disk image is run through + * filters on the way to and from disk. Thus the uncompressed + * (or unfiltered) size of the entry may be different from the + * size of the entry in file. + * + * This has the following implications: + * + * On load, uncompressed size and load size may be different. + * Presumably, load size will be smaller than uncompressed + * size, but there is no requirement for this in the code + * (but note that I have inserted an assertion to this effect, + * which has not been triggered to date). + * + * On insertion, compressed (AKA filtered, AKA on disk) size + * is unknown, as the entry has yet to be run through filters. + * Compressed size is computed whenever the entry is + * written (or the image is updated -- not relevant until + * journaling is brought back). + * + * On dirty (of a clean entry), compressed (AKA filtered, + * AKA on disk) size becomes unknown. Thus, compressed size + * must be computed by the pre-serialize callback before the + * entry may be written. + * + * Once the compressed size becomes unknown, it remains so + * until the on disk image is constructed. + * + * Observe that the cache needs to know the size of the entry + * for space allocation purposes. Since the compressed size + * can change or become unknown, it uses the uncompressed + * size which may change, but which should always be known. + * The compressed size is used only for journaling and disk I/O. + * + * While there is no logical reason why they could not be + * combined, due to absence of need and for simplicity of code, + * the cache does not permit both the the + * H5C__CLASS_COMPRESSED_FLAG and the + * H5C__CLASS_SPECULATIVE_LOAD_FLAG to be set in the same + * instance of H5C_class_t. + * + * The following flags may only appear in test code. + * + * H5C__CLASS_NO_IO_FLAG: This flag is intended only for use in test + * code. When it is set, any attempt to load an entry of + * the type with this flag set will trigger an assertion + * failure, and any flush of an entry with this flag set + * will not result in any write to file. + * + * H5C__CLASS_SKIP_READS: This flags is intended only for use in test + * code. When it is set, reads on load will be skipped, + * and an uninitialize buffer will be passed to the + * deserialize function. + * This flag is used in H5Oproxy.c because this client does not + * exist on disk. See description in that file. + * + * H5C__CLASS_SKIP_WRITES: This flags is intended only for use in test + * code. When it is set, writes of buffers prepared by the + * serialize callback will be skipped. + * This flag is used in H5Oproxy.c because this client does not + * exist on disk. See description in that file. + * + * GET_LOAD_SIZE: Pointer to the 'get load size' function. + * + * This function determines the size of a metadata cache entry based + * on the parameter "image": + * (a) When the piece of metadata has not been read, "image" is null. + * This function determines the size based on the information in the + * parameter "udata" or an initial speculative guess. The size is + * returned in the parameter "image_len_ptr". + * (b) When the piece of metadata has been read, "image" is non-null. + * This function might deserialize the needed metadata information + * to determine the actual size. The size is returned in the + * parameter "actual_len_ptr". The calculation of actual size is + * needed for checksum verification. + * + * For an entry with H5C__CLASS_NO_FLAGS_SET: + * This function computes either one of the following: + * (1) When "image" is null, it returns in "image_len_ptr" + * the on disk size of the entry. + * (2) When "image" is non-null, it does nothing. + * The values stored in "image_len_ptr" and "actual_len_ptr" + * should be the same. + * + * For an entry with H5C__CLASS_SPECULATIVE_LOAD_FLAG: + * This function computes either one of the following: + * (1) When "image" is null, it returns in "image_len_ptr" + * the initial guess of the entry's on disk size. + * (2) When "image" is non-null, it returns in "actual_len_ptr" + * the actual size of the entry on disk by + * deserializing the needed metadata information. + * + * For an entry with H5C__CLASS_COMPRESSED_FLAG: + * This function computes either one of the following: + * (1) When "image" is null, it returns in "image_len_ptr" + * the entry's on disk size: + * --for a filtered entry: the compressed size + * --for a non-filtered entry: the uncompressed size + * (2) When "image" is non-null, it returns in "actual_len_ptr: + * --for a filtered entry: the de-compressed size based on + * "udata" information + * --for a non-filtered entry: the uncompressed size + * + * The typedef for the get_load_size callback is as follows: + * + * typedef herr_t (*H5C_get_load_size_func_t)(const void *image_ptr, + * void *udata_ptr, + * size_t *image_len_ptr, + * size_t *actual_len_ptr, + * size_t *compressed_ptr, + * size_t *compressed_image_len_ptr); + * + * The parameters of the get_load_size callback are as follows: + * + * image_ptr: Pointer to a buffer containing the metadata read in. + * + * udata_ptr: Pointer to user data provided in the protect call, which + * will also be passed through to the deserialize callback. + * + * image_len_ptr: Pointer to the location in which the length in bytes + * of the in file image to be deserialized is to be returned. + * + * This value is used by the cache to determine the size of + * the disk image for the metadata, in order to read the disk + * image from the file. + * + * actual_len_ptr: Pointer to the location containing the actual length + * of the metadata entry on disk. + * + * compressed_ptr: See description in image_len callback. + * + * compressed_image_len_ptr: See description in image_len callback. + * + * Processing in the get_load_size function should proceed as follows: + * + * If successful, the function will place the length in either the + * *image_len_ptr or *actual_le_ptr associated with supplied user data + * and then return SUCCEED. + * + * On failure, the function must return FAIL and push error information + * onto the error stack with the error API routines, without modifying + * the value pointed to by image_len_ptr or actual_len_ptr. + * + * + * VERIFY_CHKSUM: Pointer to the verify_chksum function. + * + * This function verifies the checksum computed for the metadata is + * the same as the checksum stored in the metadata. + * + * It computes the checksum based on the metadata stored in the + * parameter "image_ptr" and the actual length of the metadata in the + * parameter "len" which is obtained from the "get_load_size" callback. + * + * For a filtered metadata entry with H5C__CLASS_COMPRESSED_FLAG, + * "len" is the decompressed size. This function will decompress + * the metadata and compute the checksum for the metadata with + * length "len". + * + * The typedef for the verify_chksum callback is as follows: + * + * typedef htri_t (*H5C_verify_chksum_func_t)(const void *image_ptr, + * size_t len, + * void *udata_ptr); + * + * The parameters of the verify_chksum callback are as follows: + * + * image_ptr: Pointer to a buffer containing the metadata read in. + * + * len: The actual length of the metadata. + * + * udata_ptr: Pointer to user data. + * + * + * DESERIALIZE: Pointer to the deserialize function. * - * FLUSH: Writes some data structure back to disk. It would be - * wise for the data structure to include dirty flags to - * indicate whether it really needs to be written. This - * function is also responsible for freeing memory allocated - * by the LOAD method if the DEST argument is non-zero (by - * calling the DEST method). + * This function must be able to read a buffer containing the on disk + * image of a metadata cache entry, allocate and load the equivalent + * in core representation, and return a pointer to that representation. * - * DEST: Just frees memory allocated by the LOAD method. + * The typedef for the deserialize callback is as follows: * - * CLEAR: Just marks object as non-dirty. + * typedef void *(*H5C_deserialize_func_t)(const void * image_ptr, + * size_t len, + * void * udata_ptr, + * boolean * dirty_ptr); * - * NOTIFY: Notify client that an action on an entry has taken/will take - * place + * The parameters of the deserialize callback are as follows: * - * SIZE: Report the size (on disk) of the specified cache object. - * Note that the space allocated on disk may not be contiguous. - */ + * image_ptr: Pointer to a buffer of length len containing the + * contents of the file starting at addr and continuing + * for len bytes. + * + * len: Length in bytes of the in file image to be deserialized. + * + * This parameter is supplied mainly for sanity checking. + * Sanity checks should be performed when compiled in debug + * mode, but the parameter may be unused when compiled in + * production mode. + * + * udata_ptr: Pointer to user data provided in the protect call, which + * must be passed through to the deserialize callback. + * + * dirty_ptr: Pointer to boolean which the deserialize function + * must use to mark the entry dirty if it has to modify + * the entry to clean up file corruption left over from + * an old bug in the HDF5 library. + * + * Processing in the deserialize function should proceed as follows: + * + * NOTE: With the modification to get_load_size callback (see above + * description) to compute the actual length of a metadata entry for + * checksum verification, the value in the parameter "len" will be the + * actual length of the metadata and a subsequent call to image_len + * callback is not needed. + * + * If the image contains valid data, and is of the correct length, + * the deserialize function must allocate space for an in core + * representation of that data, load the contents of the image into + * the space allocated for the in core representation, and return + * a pointer to the in core representation. Observe that an + * instance of H5C_cache_entry_t must be the first item in this + * representation. The cache will initialize it after the callback + * returns. + * + * Note that the structure of the in core representation is otherwise + * up to the cache client. All that is required is that the pointer + * returned be sufficient for the clients purposes when it is returned + * on a protect call. + * + * If the deserialize function has to clean up file corruption + * left over from an old bug in the HDF5 library, it must set + * *dirty_ptr to TRUE. If it doesn't, no action is needed as + * *dirty_ptr will be set to FALSE before the deserialize call. + * + * If the operation fails for any reason (i.e. bad data in buffer, bad + * buffer length, malloc failure, etc.) the function must return NULL and + * push error information on the error stack with the error API routines. + * + * Exceptions to the above: + * + * If the H5C__CLASS_SPECULATIVE_LOAD_FLAG is set, the buffer supplied + * to the function need not be currect on the first invocation of the + * callback in any single attempt to load the entry. + * + * In this case, if the buffer is larger than necessary, the function + * should load the entry as described above and not flag an error due + * to the oversized buffer. The cache will correct its mis-apprehension + * of the entry size with a subsequent call to the image_len callback. + * + * If the buffer is too small, and this is the first deserialize call + * in the entry load operation, the function should not flag an error. + * Instead, it must compute the correct size of the entry, allocate an + * in core representation and initialize it to the extent that an + * immediate call to the image len callback will return the correct + * image size. + * + * In this case, when the deserialize callback returns, the cache will + * call the image length callback, realize that the supplied buffer was + * too small, discard the returned in core representation, allocate + * and load a new buffer of the correct size from file, and then call + * the deserialize callback again. + * + * If the H5C__CLASS_COMPRESSED_FLAG is set, exceptions are as per the + * H5C__CLASS_SPECULATIVE_LOAD_FLAG, save that only oversized buffers + * are permitted. + * + * + * IMAGE_LEN: Pointer to the image length callback. + + * NOTE: With the modification to the get_load_size callback (see above + * description) due to checksum verification, the image_len callback + * is mainly used for newly inserted entries and assert verification. + * + * This callback exists primarily to support + * H5C__CLASS_SPECULATIVE_LOAD_FLAG and H5C__CLASS_COMPRESSED_FLAG + * discussed above, although it is also used to obtain the size of + * newly inserted entries. + * + * In the case of the H5C__CLASS_SPECULATIVE_LOAD_FLAG, it is used to + * allow the client to change the size of an entry in the deserialize + * callback. + * + * For the H5C__CLASS_COMPRESSED_FLAG, it is used to allow the client + * to indicate whether the entry is compressed (i.e. whether entries + * are run through filters) and if so, to report both the uncompressed + * and the compressed entry size (i.e. the actual on disk size after + * the entry has been run through filters) if that value is known. + * + * The callback is also used in H5C_insert_entry() to obtain the + * size of the newly inserted entry. + * + * The typedef for the image_len callback is as follows: + * + * typedef herr_t (*H5C_image_len_func_t)(void *thing, + * size_t *image_len_ptr, + * hbool_t *compressed_ptr, + * size_t *compressed_image_len_ptr); + * + * The parameters of the image_len callback are as follows: + * + * thing: Pointer to the in core representation of the entry. + * + * image_len_ptr: Pointer to size_t in which the callback will return + * the length (in bytes) of the cache entry. + * + * If the H5C__CLASS_COMPRESSED_FLAG is not set in the + * associated instance of H5C_class_t, or if the flag is + * set, and the callback sets *compressed_ptr to FALSE, + * this size is the actual size of the entry on disk. + * + * Otherwise, this size is the uncompressed size of the + * entry -- which the cache will use for all purposes OTHER + * than journal writes and disk I/O. + * + * compressed_ptr: Pointer to a boolean flag indicating whether + * the cache entry will be compressed / uncompressed on + * disk writes / reads. + * + * If the H5C__CLASS_COMPRESSED_FLAG is not set in the + * associated instance of H5C_class_t, *compressed_ptr + * must be set to FALSE. + * + * If the H5C__CLASS_COMPRESSED_FLAG is set in the + * associated instance of H5C_class_t, and filters are + * not enabled, *compressed_ptr must be set to FALSE. + * + * If the H5C__CLASS_COMPRESSED_FLAG is set in the + * associated instance of H5C_class_t, and filters are + * enabled, the callback must set *compressed_ptr to TRUE. + * + * Note that *compressed_ptr will always be set to FALSE + * by the caller prior to invocation of the callback. Thus + * callbacks for clients that don't set the + * H5C__CLASS_COMPRESSED_FLAG can ignore this parameter. + * + * compressed_image_len_ptr: Pointer to size_t in which the callback + * may return the length (in bytes) of the compressed on + * disk image of the entry, or the uncompressed size if the + * compressed size has not yet been calculated. + * + * Since computing the compressed image len is expensive, + * the callback should only report the most recently computed + * value -- which will typically be incorrect if the entry + * is dirty. + * + * If *compressed_ptr is set to FALSE, *compressed_image_len_ptr + * should be set to zero. However, as *compressed_image_len_ptr + * will be initialize to zero prior to the call, the callback + * need not modify it if the H5C__CLASS_COMPRESSED_FLAG is + * not set. + * + * If the H5C__CLASS_COMPRESSED_FLAG is not set in the associated + * instance of H5C_class_t, processing in the image_len function + * should proceed as follows: + * + * If successful, the function will place the length of the on disk + * image associated with the in core representation provided in the + * thing parameter in *image_len_ptr, and then return SUCCEED. Since + * *compressed_ptr and *compressed_image_len_ptr will be initialized to + * FALSE and zero respectively before the call, the callback need not + * modify these values, and may declare the associated parameters as + * UNUSED. + * + * If the H5C__CLASS_COMPRESSED_FLAG is set in the associated + * instance of H5C_class_t, processing in the image_len function + * should proceed as follows: + * + * If successful, the function will place the uncompressed length of + * the on disk image associated with the in core representation + * provided in the thing parameter in *image_len_ptr. If filters + * are not enabled for the entry, it will set *compressed_ptr to FALSE, + * and *compressed_image_len_ptr to zero. If filters are enabled, + * it will set *compressed_ptr to TRUE. In this case, it must set + * *compressed_image_len_ptr equal to the last computed compressed + * if the compressed size, or to the uncompressed size if that value + * is yet to be computed. In all cases, it will return SUCCEED if + * successful. + * + * In either case, if the function fails, it must return FAIL and + * push error information onto the error stack with the error API + * routines, and return without modifying the values pointed to by + * the image_len_ptr, compressed_ptr, and compressed_image_len_ptr + * parameters. + * + * PRE_SERIALIZE: Pointer to the pre-serialize callback. + * + * The pre-serialize callback is invoked by the metadata cache before + * it needs a current on-disk image of the metadata entry for purposes + * either constructing a journal or flushing the entry to disk. + * + * If the client needs to change the address or compressed or + * uncompressed length of the entry prior to flush, the pre-serialize + * callback is responsible for these actions, so that the actual + * serialize callback (described below) is only responsible for + * serializing the data structure, not moving it on disk or resizing it. + * + * In addition, the client may use the pre-serialize callback to + * ensure that the entry is ready to be flushed -- in particular, + * if the entry contains references to other entries that are in + * temporary file space, the pre-serialize callback must move those + * entries into real file space so that the serialzed entry will + * contain no invalid data. + * + * One would think that the base address and length of + * the length of the entry's image on disk would be well known. + * However, that need not be the case as free space section info + * entries will change size (and possibly location) depending on the + * number of blocks of free space being manages, and fractal heap + * direct blocks can change compressed size (and possibly location) + * on serialization if compression is enabled. Similarly, it may + * be necessary to move entries from temporary to real file space. + * + * The pre-serialize callback must report any such changes to the + * cache, which must then update its internal structures as needed. + * + * The typedef for the pre-serialize callback is as follows: + * + * typedef herr_t (*H5C_pre_serialize_func_t)(const H5F_t *f, + * hid_t dxpl_id, + * void * thing, + * haddr_t addr, + * size_t len, + * size_t compressed_len, + * haddr_t * new_addr_ptr, + * size_t * new_len_ptr, + * size_t * new_compressed_len_ptr, + * unsigned * flags_ptr); + * + * The parameters of the pre-serialize callback are as follows: + * + * f: File pointer -- needed if other metadata cache entries + * must be modified in the process of serializing the + * target entry. + * + * dxpl_id: dxpl_id passed with the file pointer to the cache, and + * passed on to the callback. Necessary as some callbacks + * revise the size and location of the target entry, or + * possibly other entries on pre-serialize. + * + * thing: Pointer to void containing the address of the in core + * representation of the target metadata cache entry. + * This is the same pointer returned by a protect of the + * addr and len given above. + * + * addr: Base address in file of the entry to be serialized. + * + * This parameter is supplied mainly for sanity checking. + * Sanity checks should be performed when compiled in debug + * mode, but the parameter may be unused when compiled in + * production mode. + * + * len: Length in bytes of the in file image of the entry to be + * serialized. Also the size the image passed to the + * serialize callback (discussed below) unless either that + * value is altered by this function, or the entry will be + * compressed. In the latter case, the compressed size + * of the entry will be reported in *new_compressed_len_ptr. + * + * This parameter is supplied mainly for sanity checking. + * Sanity checks should be performed when compiled in debug + * mode, but the parameter may be unused when compiled in + * production mode. + * + * compressed_len: If the entry is to be compressed (i.e. run through + * filters) prior to flush, Length in bytes of the last know + * compressed size of the entry -- or the uncompressed size + * if no such value exists (i.e. the entry has been inserted, + * but never flushed). This parameter should be set to zero + * in all other cases. + * + * This parameter is supplied mainly for sanity checking. + * Sanity checks should be performed when compiled in debug + * mode, but the parameter may be unused when compiled in + * production mode. + * + * new_addr_ptr: Pointer to haddr_t. If the entry is moved by + * the serialize function, the new on disk base address must + * be stored in *new_addr_ptr, and the appropriate flag set + * in *flags_ptr. + * + * If the entry is not moved by the serialize function, + * *new_addr_ptr is undefined on pre-serialize callback + * return. + * + * new_len_ptr: Pointer to size_t. If the entry is resized by the + * serialize function, the new length of the on disk image + * must be stored in *new_len_ptr, and the appropriate flag set + * in *flags_ptr. + * + * If the entry is not resized by the pre-serialize function, + * *new_len_ptr is undefined on pre-serialize callback + * return. + * + * new_compressed_len_ptr: Pointer to size_t. If the image will be + * compressed (i.e. run through filters) prior to being + * written to disk, the compressed size (in bytes) of the + * on disk image must be stored in *new_compressed_len_ptr, + * and the appropriate flag set in *flags_ptr. + * + * flags_ptr: Pointer to an unsigned integer used to return flags + * indicating whether the preserialize function resized or moved + * the entry, or computed its compressed size. If the entry was + * neither resized or moved, nor will be compressed, + * the serialize function must set *flags_ptr to zero. + * H5C__SERIALIZE_RESIZED_FLAG, H5C__SERIALIZE_MOVED_FLAG + * and H5C__SERIALIZE_COMPRESSED_FLAG must be set to indicate + * a resize, a move, or compression respectively. + * + * If the H5C__SERIALIZE_RESIZED_FLAG is set, the new length + * must be stored in *new_len_ptr. + * + * If the H5C__SERIALIZE_MOVED_FLAG flag is set, the + * new image base address must be stored in *new_addr_ptr. + * + * If the H5C__SERIALIZE_COMPRESSED_FLAG is set, the + * compressed size of the new image must be stored in + * *new_compressed_len_ptr. + * + * Processing in the pre-serialize function should proceed as follows: + * + * The pre-serialize function must examine the in core representation + * indicated by the thing parameter, if the pre-serialize function does + * not need to change the size or location of the on-disk image, or + * compute its compress size, it must set *flags_ptr to zero. + * + * If the (uncompressed) size of the on-disk image must be changed, + * the pre-serialize function must load the length of the new image + * into *new_len_ptr, and set the H5C__SERIALIZE_RESIZED_FLAG in + * *flags_ptr. + * + * If the base address of the on disk image must be changed, the + * pre-serialize function must set *new_addr_ptr to the new base address, + * and set the H5C__SERIALIZE_MOVED_FLAG in *flags_ptr. + * + * If the H5C__CLASS_COMPRESSED_FLAG is set in the assocated instance + * of H5C_class_t, and filters (i.e. compression) are enabled, the + * pre-serialize function must compute the compressed size of the + * on disk image, and if it has changed, load this value into + * *new_compressed_len_ptr, and set H5C__SERIALIZE_COMPRESSED_FLAG in + * *flags_ptr. + * + * Note that to do this, the preserialize function will typically have + * to serialize the entry, and run it through the filters to obtain + * the compressed size. For efficiency, the compressed image may + * be stored to be copied into the supplied buffer by the + * serialize callback. Needless to say this is awkward. We may + * want to re-work the API for cache clients to simplify this. + * + * In addition, the pre-serialize callback may perform any other + * processing required before the entry is written to disk + * + * If it is successful, the function must return SUCCEED. + * + * If it fails for any reason, the function must return FAIL and + * push error information on the error stack with the error API + * routines. + * + * + * SERIALIZE: Pointer to the serialize callback. + * + * The serialize callback is invoked by the metadata cache whenever + * it needs a current on disk image of the metadata entry for purposes + * either constructing a journal entry or flushing the entry to disk. + * + * At this point, the base address and length of the entry's image on + * disk must be well known and not change during the serialization + * process. + * + * While any size and/or location changes must have been handled + * by a pre-serialize call, the client may elect to handle any other + * changes to the entry required to place it in correct form for + * writing to disk in this call. + * + * The typedef for the serialize callback is as follows: + * + * typedef herr_t (*H5C_serialize_func_t)(const H5F_t *f, + * void * image_ptr, + * size_t len, + * void * thing); + * + * The parameters of the serialize callback are as follows: + * + * f: File pointer -- needed if other metadata cache entries + * must be modified in the process of serializing the + * target entry. + * + * image_ptr: Pointer to a buffer of length len bytes into which a + * serialized image of the target metadata cache entry is + * to be written. + * + * Note that this buffer will not in general be initialized + * to any particular value. Thus the serialize function may + * not assume any initial value and must set each byte in + * the buffer. + * + * len: Length in bytes of the in file image of the entry to be + * serialized. Also the size of *image_ptr (below). If + * compression is not enabled, this value is simply the + * uncompressed size of the entry's image on disk. If + * compression is enabled, this value is the size of the + * compressed image. + * + * This parameter is supplied mainly for sanity checking. + * Sanity checks should be performed when compiled in debug + * mode, but the parameter may be unused when compiled in + * production mode. + * + * thing: Pointer to void containing the address of the in core + * representation of the target metadata cache entry. + * This is the same pointer returned by a protect of the + * addr and len given above. + * + * Processing in the serialize function should proceed as follows: + * + * If there are any remaining changes to the entry required before + * write to disk, they must be dealt with first. + * + * The serialize function must then examine the in core + * representation indicated by the thing parameter, and write a + * serialized (and possibly compressed) image of its contents into + * the provided buffer. + * + * If it is successful, the function must return SUCCEED. + * + * If it fails for any reason, the function must return FAIL and + * push error information on the error stack with the error API + * routines. + * + * + * NOTIFY: Pointer to the notify callback. + * + * The notify callback is invoked by the metadata cache when a cache + * action on an entry has taken/will take place and the client indicates + * it wishes to be notified about the action. + * + * The typedef for the notify callback is as follows: + * + * typedef herr_t (*H5C_notify_func_t)(H5C_notify_action_t action, + * void *thing); + * + * The parameters of the notify callback are as follows: + * + * action: An enum indicating the metadata cache action that has taken/ + * will take place. + * + * thing: Pointer to void containing the address of the in core + * representation of the target metadata cache entry. This + * is the same pointer that would be returned by a protect + * of the addr and len of the entry. + * + * Processing in the notify function should proceed as follows: + * + * The notify function may perform any action it would like, including + * metadata cache calls. + * + * If the function is successful, it must return SUCCEED. + * + * If it fails for any reason, the function must return FAIL and + * push error information on the error stack with the error API + * routines. + * + * + * FREE_ICR: Pointer to the free ICR callback. + * + * The free ICR callback is invoked by the metadata cache when it + * wishes to evict an entry, and needs the client to free the memory + * allocated for the in core representation. + * + * The typedef for the free ICR callback is as follows: + * + * typedef herr_t (*H5C_free_icr_func_t)(void * thing)); + * + * The parameters of the free ICR callback are as follows: + * + * thing: Pointer to void containing the address of the in core + * representation of the target metadata cache entry. This + * is the same pointer that would be returned by a protect + * of the addr and len of the entry. + * + * Processing in the free ICR function should proceed as follows: + * + * The free ICR function must free all memory allocated to the + * in core representation. + * + * If the function is successful, it must return SUCCEED. + * + * If it fails for any reason, the function must return FAIL and + * push error information on the error stack with the error API + * routines. + * + * At least when compiled with debug, it would be useful if the + * free ICR call would fail if the in core representation has been + * modified since the last serialize of clear callback. + * + * CLEAR: Pointer to the clear callback. + * + * In principle, there should be no need for the clear callback, + * as the dirty flag should be maintained by the metadata cache. + *. + * However, some clients maintain dirty bits on internal data, + * and we need some way of keeping these dirty bits in sync with + * those maintained by the metadata cache. This callback exists + * to serve this purpose. If defined, it is called whenever the + * cache marks dirty entry clean, or when the cache is about to + * discard a dirty entry without writing it to disk (This + * happens as the result of an unprotect call with the + * H5AC__DELETED_FLAG set, and the H5C__TAKE_OWNERSHIP_FLAG not + * set.) + * + * Arguably, this functionality should be in the NOTIFY callback. + * However, this callback is specific to only a few clients, and + * it will be called relatively frequently. Hence it is made its + * own callback to minimize overhead. + * + * The typedef for the clear callback is as follows: + * + * typedef herr_t (*H5C_clear_func_t)(const H5F_t *f, + * void * thing, + * hbool_t about_to_destroy); + * + * The parameters of the clear callback are as follows: + * + * f: File pointer. + * + * thing: Pointer to void containing the address of the in core + * representation of the target metadata cache entry. This + * is the same pointer that would be returned by a protect() + * call of the associated addr and len. + * + * about_to_destroy: Boolean flag used to indicate whether the + * metadata cache is about to destroy the target metadata + * cache entry. The callback may use this flag to omit + * operations that are irrelevant it the entry is about + * to be destroyed. + * + * Processing in the clear function should proceed as follows: + * + * Reset all internal dirty bits in the target metadata cache entry. + * + * If the about_to_destroy flag is TRUE, the clear function may + * ommit any dirty bit that will not trigger a sanity check failure + * or otherwise cause problems in the subsequent free icr call. + * In particular, the call must ensure that the free icr call will + * not fail due to changes prior to this call, and after the + * last serialize or clear call. + * + * If the function is successful, it must return SUCCEED. + * + * If it fails for any reason, the function must return FAIL and + * push error information on the error stack with the error API + * routines. + * + * GET_FSF_SIZE: Pointer to the get file space free size callback. + * + * In principle, there is no need for the get file space free size + * callback. However, as an optimization, it is sometimes convenient + * to allocate and free file space for a number of cache entries + * simultaneously in a single contiguous block of file space. + * + * File space allocation is done by the client, so the metadata cache + * need not be involved. However, since the metadata cache typically + * handles file space release when an entry is destroyed, some + * adjustment on the part of the metadata cache is required for this + * operation. + * + * The get file space free size callback exists to support this + * operation. + * + * If a group of cache entries that were allocated as a group are to + * be discarded and their file space released, the type of the first + * (i.e. lowest address) entry in the group must implement the + * get free file space size callback. + * + * To free the file space of all entries in the group in a single + * operation, first expunge all entries other than the first without + * the free file space flag. + * + * Then, to complete the operation, unprotect or expunge the first + * entry in the block with the free file space flag set. Since + * the get free file space callback is implemented, the metadata + * cache will use this callback to get the size of the block to be + * freed, instead of using the size of the entry as is done otherwise. + * + * At present this callback is used only by the H5FA and H5EA dblock + * and dblock page client classes. + * + * The typedef for the clear callback is as follows: + * + * typedef herr_t (*H5C_get_fsf_size_t)(const void * thing, + * size_t *fsf_size_ptr); + * + * The parameters of the clear callback are as follows: + * + * thing: Pointer to void containing the address of the in core + * representation of the target metadata cache entry. This + * is the same pointer that would be returned by a protect() + * call of the associated addr and len. + * + * fs_size_ptr: Pointer to size_t in which the callback will return + * the size of the piece of file space to be freed. Note + * that the space to be freed is presumed to have the same + * base address as the cache entry. + * + * The function simply returns the size of the block of file space + * to be freed in *fsf_size_ptr. + * + * If the function is successful, it must return SUCCEED. + * + * If it fails for any reason, the function must return FAIL and + * push error information on the error stack with the error API + * routines. + * + ***************************************************************************/ /* Actions that can be reported to 'notify' client callback */ typedef enum H5C_notify_action_t { - H5C_NOTIFY_ACTION_AFTER_INSERT, /* Entry has been added to the cache */ - /* (could be loaded from file with - * 'protect' call, or inserted - * with 'set' call) + H5C_NOTIFY_ACTION_AFTER_INSERT, /* Entry has been added to the cache + * via the insert call + */ + H5C_NOTIFY_ACTION_AFTER_LOAD, /* Entry has been loaded into the + * from file via the protect call + */ + H5C_NOTIFY_ACTION_AFTER_FLUSH, /* Entry has just been flushed to + * file. + */ + H5C_NOTIFY_ACTION_BEFORE_EVICT /* Entry is about to be evicted + * from cache. */ - H5C_NOTIFY_ACTION_BEFORE_EVICT /* Entry is about to be evicted from cache */ } H5C_notify_action_t; /* Cache client callback function pointers */ -typedef void *(*H5C_load_func_t)(H5F_t *f, hid_t dxpl_id, haddr_t addr, - void *udata); -typedef herr_t (*H5C_flush_func_t)(H5F_t *f, hid_t dxpl_id, hbool_t dest, - haddr_t addr, void *thing, unsigned *flags_ptr); -typedef herr_t (*H5C_dest_func_t)(H5F_t *f, void *thing); -typedef herr_t (*H5C_clear_func_t)(H5F_t *f, void *thing, hbool_t dest); +typedef herr_t (*H5C_get_load_size_func_t)(const void *image_ptr, void *udata_ptr, + size_t *image_len_ptr, size_t *actual_len_ptr, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +typedef htri_t (*H5C_verify_chksum_func_t)(const void *image_ptr, size_t len, void *udata_ptr); +typedef void *(*H5C_deserialize_func_t)(const void *image_ptr, + size_t len, void *udata_ptr, hbool_t *dirty_ptr); +typedef herr_t (*H5C_image_len_func_t)(const void *thing, + size_t *image_len_ptr, hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +typedef herr_t (*H5C_pre_serialize_func_t)(const H5F_t *f, hid_t dxpl_id, + void *thing, haddr_t addr, size_t len, size_t compressed_len, + haddr_t *new_addr_ptr, size_t *new_len_ptr, size_t *new_compressed_len_ptr, + unsigned *flags_ptr); +typedef herr_t (*H5C_serialize_func_t)(const H5F_t *f, void *image_ptr, + size_t len, void *thing); typedef herr_t (*H5C_notify_func_t)(H5C_notify_action_t action, void *thing); -typedef herr_t (*H5C_size_func_t)(const H5F_t *f, const void *thing, - size_t *size_ptr); +typedef herr_t (*H5C_free_icr_func_t)(void *thing); +typedef herr_t (*H5C_clear_func_t)(const H5F_t *f, void * thing, + hbool_t about_to_destroy); +typedef herr_t (*H5C_get_fsf_size_t)(const void * thing, size_t *fsf_size_ptr); /* Metadata cache client class definition */ typedef struct H5C_class_t { - int id; - H5C_load_func_t load; - H5C_flush_func_t flush; - H5C_dest_func_t dest; - H5C_clear_func_t clear; - H5C_notify_func_t notify; - H5C_size_func_t size; + int id; + const char * name; + H5FD_mem_t mem_type; + unsigned flags; + H5C_get_load_size_func_t get_load_size; + H5C_verify_chksum_func_t verify_chksum; + H5C_deserialize_func_t deserialize; + H5C_image_len_func_t image_len; + H5C_pre_serialize_func_t pre_serialize; + H5C_serialize_func_t serialize; + H5C_notify_func_t notify; + H5C_free_icr_func_t free_icr; + H5C_clear_func_t clear; + H5C_get_fsf_size_t fsf_size; } H5C_class_t; /* Type defintions of callback functions used by the cache as a whole */ @@ -328,7 +1232,7 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t *cache_ptr, haddr_t addr, * just before the entry is freed. * * This is necessary, as the LRU list can be changed out - * from under H5C_make_space_in_cache() by the flush + * from under H5C_make_space_in_cache() by the serialize * callback which may change the size of an existing entry, * and/or load a new entry while serializing the target entry. * @@ -341,18 +1245,66 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t *cache_ptr, haddr_t addr, * detect this case, and re-start its scan from the bottom * of the LRU when this situation occurs. * - * This field is only compiled in debug mode. + * cache_ptr: Pointer to the cache that this entry is contained within. * * addr: Base address of the cache entry on disk. * - * size: Length of the cache entry on disk. Note that unlike normal - * caches, the entries in this cache are of variable length. - * The entries should never overlap, and when we do writebacks, - * we will want to writeback adjacent entries where possible. + * size: Length of the cache entry on disk in bytes(exception: if + * the entry is compressed on disk, this field contains the + * uncompressed size of the entry -- see discussion of + * compressed entries below). Note that unlike normal + * caches, the entries in this cache are of arbitrary size. + * + * With the exception of compressed entries, the file space + * allocations for cache entries implied by the addr and size + * fields must be disjoint. For compressed entries, + * the size field contains the uncompressed size -- thus in + * in this case, substitution of compressed size for size + * must result in disjoint file space allocations. However, + * as discussed below, the compressed size may not be know. + * + * Any entry whose associated instance of H5C_class_t has the + * H5C__CLASS_COMPRESSED_FLAG set may be compressed. When + * an entry is compressed (that is, when filters are enabled + * on it), the compressed flag (see below) must be set, and + * the compressed size (if known), must be stored in + * the compressed_size field. + * + * Since the compressed size will be unknown unless the + * entry is clean, or has an up to date image (see the + * image_ptr and image_up_to_date fields below), we use the + * uncompressed size for all purposes other than disk I/O. + * + * compressed: Boolean flag that is set iff the instance of H5C_class_t + * associated with the entry has the H5C__CLASS_COMPRESSED_FLAG + * set, and filters are enabled on the entry. + * + * compressed_size: If compressed is TRUE, this field contains the actual + * compressed size of the entry in bytes, which is also its + * true size on disk -- or the uncompressed size if the + * compressed size is unknown (i.e. the entry has been + * inserted in the cache, but it has not been compressed yet). + * Note that this value will usually be incorrect if the + * entry is dirty. + * + * Since this value is frequently out of date and expensive to + * compute, it is used only for disk I/O. The uncompressed + * size of the entry (stored in the size field above) is used + * for all other purposes (i.e. computing the sum of the sizes + * of all entries in the cache, etc.). + * + * If compressed is FALSE, this field should contain 0. * - * NB: At present, entries need not be contiguous on disk. Until - * we fix this, we can't do much with writing back adjacent - * entries. + * image_ptr: Pointer to void. When not NULL, this field points to a + * dynamically allocated block of size bytes in which the + * on disk image of the metadata cache entry is stored. + * + * If the entry is dirty, the pre-serialize and serialize + * callbacks must be used to update this image before it is + * written to disk + * + * image_up_to_date: Boolean flag that is set to TRUE when *image_ptr + * is up to date, and set to false when the entry is dirtied. * * type: Pointer to the instance of H5C_class_t containing pointers * to the methods for cache entries of the current type. This @@ -385,6 +1337,9 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t *cache_ptr, haddr_t addr, * modules using the cache. These still clear the * is_dirty field as before. -- JRM 7/5/05 * + * Update: Management of the is_dirty field is now entirely + * in the cache. -- JRM 7/5/07 + * * dirtied: Boolean flag used to indicate that the entry has been * dirtied while protected. * @@ -441,9 +1396,10 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t *cache_ptr, haddr_t addr, * policy code (LRU at present). * * 2) A pinned entry can be accessed or modified at any time. - * Therefore, the cache must check with the entry owner - * before flushing it. If permission is denied, the - * cache does not flush the entry. + * This places an extra burden on the pre-serialize and + * serialize callbacks, which must ensure that a pinned + * entry is consistant and ready to write to disk before + * generating an image. * * 3) A pinned entry can be marked as dirty (and possibly * change size) while it is unprotected. @@ -485,6 +1441,11 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t *cache_ptr, haddr_t addr, * will need to be expanded and tested appropriately if that * functionality is desired. * + * Update: There are now two possible last entries + * (superblock and file driver info message). This + * number will probably increase as we add superblock + * messages. JRM -- 11/18/14 + * * clear_on_unprotect: Boolean flag used only in PHDF5. When H5C is used * to implement the metadata cache In the parallel case, only * the cache with mpi rank 0 is allowed to actually write to @@ -512,11 +1473,6 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t *cache_ptr, haddr_t addr, * destroy_in_progress: Boolean flag that is set to true iff the entry * is in the process of being flushed and destroyed. * - * free_file_space_on_destroy: Boolean flag that is set to true iff the entry - * is in the process of being flushed and destroyed and the file - * space used by the object should be freed by the cache client's - * 'dest' callback routine. - * * * Fields supporting the 'flush dependency' feature: * @@ -596,63 +1552,43 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t *cache_ptr, haddr_t addr, * The use of the replacement policy fields under the Modified LRU policy * is discussed below: * - * next: Next pointer in either the LRU or the protected list, - * depending on the current value of protected. If there - * is no next entry on the list, this field should be set - * to NULL. + * next: Next pointer in either the LRU, the protected list, or + * the pinned list depending on the current values of + * is_protected and is_pinned. If there is no next entry + * on the list, this field should be set to NULL. * - * prev: Prev pointer in either the LRU or the protected list, - * depending on the current value of protected. If there - * is no previous entry on the list, this field should be - * set to NULL. + * prev: Prev pointer in either the LRU, the protected list, + * or the pinned list depending on the current values of + * is_protected and is_pinned. If there is no previous + * entry on the list, this field should be set to NULL. * * aux_next: Next pointer on either the clean or dirty LRU lists. - * This entry should be NULL when protected is true. When - * protected is false, and dirty is true, it should point - * to the next item on the dirty LRU list. When protected - * is false, and dirty is false, it should point to the - * next item on the clean LRU list. In either case, when - * there is no next item, it should be NULL. + * This entry should be NULL when either is_protected or + * is_pinned is true. + * + * When is_protected and is_pinned are false, and is_dirty is + * true, it should point to the next item on the dirty LRU + * list. + * + * When is_protected and is_pinned are false, and is_dirty is + * false, it should point to the next item on the clean LRU + * list. In either case, when there is no next item, it + * should be NULL. * * aux_prev: Previous pointer on either the clean or dirty LRU lists. - * This entry should be NULL when protected is true. When - * protected is false, and dirty is true, it should point - * to the previous item on the dirty LRU list. When protected - * is false, and dirty is false, it should point to the - * previous item on the clean LRU list. In either case, when - * 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. + * This entry should be NULL when either is_protected or + * is_pinned is true. + * + * When is_protected and is_pinned are false, and is_dirty is + * true, it should point to the previous item on the dirty + * LRU list. + * + * When is_protected and is_pinned are false, and is_dirty + * is false, it should point to the previous item on the + * clean LRU list. * + * In either case, when there is no previous item, it should + * be NULL. * * Cache entry stats collection fields: * @@ -674,12 +1610,14 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t *cache_ptr, haddr_t addr, * ****************************************************************************/ typedef struct H5C_cache_entry_t { -#ifndef NDEBUG uint32_t magic; -#endif /* NDEBUG */ H5C_t * cache_ptr; haddr_t addr; size_t size; + hbool_t compressed; + size_t compressed_size; + void * image_ptr; + hbool_t image_up_to_date; const H5C_class_t * type; haddr_t tag; int globality; @@ -700,7 +1638,6 @@ typedef struct H5C_cache_entry_t { #endif /* H5_HAVE_PARALLEL */ hbool_t flush_in_progress; hbool_t destroy_in_progress; - hbool_t free_file_space_on_destroy; /* fields supporting the 'flush dependency' feature: */ struct H5C_cache_entry_t ** flush_dep_parent; @@ -1039,15 +1976,15 @@ H5_DLL void H5C_def_auto_resize_rpt_fcn(H5C_t *cache_ptr, int32_t version, double hit_rate, enum H5C_resize_status status, size_t old_max_cache_size, size_t new_max_cache_size, size_t old_min_clean_size, size_t new_min_clean_size); -H5_DLL herr_t H5C_dest(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id); -H5_DLL herr_t H5C_evict(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id); -H5_DLL herr_t H5C_expunge_entry(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, - const H5C_class_t *type, haddr_t addr, unsigned flags); -H5_DLL herr_t H5C_flush_cache(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, - unsigned flags); -H5_DLL herr_t H5C_flush_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, haddr_t tag); -H5_DLL herr_t H5C_evict_tagged_entries(H5F_t * f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, haddr_t tag); -H5_DLL herr_t H5C_flush_to_min_clean(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id); +H5_DLL herr_t H5C_dest(H5F_t *f, hid_t dxpl_id); +H5_DLL herr_t H5C_evict(H5F_t *f, hid_t dxpl_id); +H5_DLL herr_t H5C_expunge_entry(H5F_t *f, hid_t dxpl_id, const H5C_class_t *type, haddr_t addr, unsigned flags); + + +H5_DLL herr_t H5C_flush_cache(H5F_t *f, hid_t dxpl_id, unsigned flags); +H5_DLL herr_t H5C_flush_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag); +H5_DLL herr_t H5C_evict_tagged_entries(H5F_t * f, hid_t dxpl_id, haddr_t tag); +H5_DLL herr_t H5C_flush_to_min_clean(H5F_t *f, hid_t dxpl_id); H5_DLL herr_t H5C_get_cache_auto_resize_config(const H5C_t *cache_ptr, H5C_auto_size_ctl_t *config_ptr); H5_DLL herr_t H5C_get_cache_size(H5C_t *cache_ptr, size_t *max_size_ptr, @@ -1061,17 +1998,17 @@ H5_DLL herr_t H5C_get_entry_status(const H5F_t *f, haddr_t addr, H5_DLL herr_t H5C_get_evictions_enabled(const H5C_t *cache_ptr, hbool_t *evictions_enabled_ptr); H5_DLL FILE *H5C_get_trace_file_ptr(const H5C_t *cache_ptr); H5_DLL FILE *H5C_get_trace_file_ptr_from_entry(const H5C_cache_entry_t *entry_ptr); -H5_DLL herr_t H5C_insert_entry(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, - const H5C_class_t *type, haddr_t addr, void *thing, unsigned int flags); -H5_DLL herr_t H5C_mark_entries_as_clean(H5F_t *f, hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, int32_t ce_array_len, haddr_t *ce_array_ptr); +H5_DLL herr_t H5C_insert_entry(H5F_t *f, hid_t dxpl_id, const H5C_class_t *type, + haddr_t addr, void *thing, unsigned int flags); +H5_DLL herr_t H5C_mark_entries_as_clean(H5F_t *f, hid_t dxpl_id, int32_t ce_array_len, + haddr_t *ce_array_ptr); H5_DLL herr_t H5C_mark_entry_dirty(void *thing); H5_DLL herr_t H5C_move_entry(H5C_t *cache_ptr, const H5C_class_t *type, haddr_t old_addr, haddr_t new_addr); H5_DLL herr_t H5C_pin_protected_entry(void *thing); H5_DLL herr_t H5C_create_flush_dependency(void *parent_thing, void *child_thing); -H5_DLL void * H5C_protect(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, - const H5C_class_t *type, haddr_t addr, void *udata, unsigned flags); +H5_DLL void * H5C_protect(H5F_t *f, hid_t dxpl_id, const H5C_class_t *type, + haddr_t addr, void *udata, unsigned flags); H5_DLL herr_t H5C_reset_cache_hit_rate_stats(H5C_t *cache_ptr); H5_DLL herr_t H5C_resize_entry(void *thing, size_t new_size); H5_DLL herr_t H5C_set_cache_auto_resize_config(H5C_t *cache_ptr, H5C_auto_size_ctl_t *config_ptr); @@ -1085,8 +2022,8 @@ H5_DLL void H5C_stats__reset(H5C_t *cache_ptr); H5_DLL herr_t H5C_dump_cache(H5C_t *cache_ptr, const char *cache_name); H5_DLL herr_t H5C_unpin_entry(void *thing); H5_DLL herr_t H5C_destroy_flush_dependency(void *parent_thing, void *child_thing); -H5_DLL herr_t H5C_unprotect(H5F_t *f, hid_t primary_dxpl_id, hid_t secondary_dxpl_id, - const H5C_class_t *type, haddr_t addr, void *thing, unsigned int flags); +H5_DLL herr_t H5C_unprotect(H5F_t *f, hid_t dxpl_id, const H5C_class_t *type, + haddr_t addr, void *thing, unsigned int flags); H5_DLL herr_t H5C_validate_resize_config(H5C_auto_size_ctl_t *config_ptr, unsigned int tests); H5_DLL herr_t H5C_ignore_tags(H5C_t *cache_ptr); @@ -1094,9 +2031,9 @@ H5_DLL void H5C_retag_entries(H5C_t * cache_ptr, haddr_t src_tag, haddr_t dest_t H5_DLL herr_t H5C_cork(H5C_t *cache_ptr, haddr_t obj_addr, unsigned action, hbool_t *corked); #ifdef H5_HAVE_PARALLEL -H5_DLL herr_t H5C_apply_candidate_list(H5F_t *f, hid_t primary_dxpl_id, - hid_t secondary_dxpl_id, H5C_t *cache_ptr, int num_candidates, - haddr_t *candidates_list_ptr, int mpi_rank, int mpi_size); +H5_DLL herr_t H5C_apply_candidate_list(H5F_t *f, hid_t dxpl_id, + H5C_t *cache_ptr, int num_candidates, haddr_t *candidates_list_ptr, + int mpi_rank, int mpi_size); H5_DLL herr_t H5C_construct_candidate_list__clean_cache(H5C_t *cache_ptr); H5_DLL herr_t H5C_construct_candidate_list__min_clean(H5C_t *cache_ptr); #endif /* H5_HAVE_PARALLEL */ diff --git a/src/H5Dlayout.c b/src/H5Dlayout.c index c0cde78..d9a8845 100644 --- a/src/H5Dlayout.c +++ b/src/H5Dlayout.c @@ -479,7 +479,7 @@ H5D__layout_oh_create(H5F_t *file, hid_t dxpl_id, H5O_t *oh, H5D_t *dset, HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create EFL file name heap") /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(file, dxpl_id, efl->heap_addr, H5AC_WRITE))) + if(NULL == (heap = H5HL_protect(file, dxpl_id, efl->heap_addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_DATASET, H5E_CANTPROTECT, FAIL, "unable to protect EFL file name heap") /* Insert "empty" name first */ @@ -152,7 +152,7 @@ HDfprintf(stderr, "%s: Called\n", FUNC); H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array info") /* Lock the array header into memory */ - if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, ea_addr, ctx_udata, H5AC_WRITE))) + if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, ea_addr, ctx_udata, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header") /* Point extensible array wrapper at header and bump it's ref count */ @@ -213,7 +213,7 @@ H5EA_open(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr, void *ctx_udata)) #ifdef QAK HDfprintf(stderr, "%s: ea_addr = %a\n", FUNC, ea_addr); #endif /* QAK */ - if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, ea_addr, ctx_udata, H5AC_READ))) + if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, ea_addr, ctx_udata, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header, address = %llu", (unsigned long long)ea_addr) /* Check for pending array deletion */ @@ -337,7 +337,7 @@ END_FUNC(PRIV) /* end H5EA_get_addr() */ */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__lookup_elmt(const H5EA_t *ea, hid_t dxpl_id, hsize_t idx, H5AC_protect_t thing_acc, +H5EA__lookup_elmt(const H5EA_t *ea, hid_t dxpl_id, hsize_t idx, unsigned thing_acc, void **thing, uint8_t **thing_elmt_buf, hsize_t *thing_elmt_idx, H5EA__unprotect_func_t *thing_unprot_func)) @@ -366,6 +366,9 @@ HDfprintf(stderr, "%s: Index %Hu\n", FUNC, idx); HDassert(thing_elmt_buf); HDassert(thing_unprot_func); + /* only the H5AC__READ_ONLY_FLAG may be set in thing_acc */ + HDassert((thing_acc & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Set the shared array header's file context for this operation */ hdr->f = ea->f; @@ -381,7 +384,7 @@ HDfprintf(stderr, "%s: Index %Hu\n", FUNC, idx); HDfprintf(stderr, "%s: Index block address not defined!\n", FUNC, idx); #endif /* QAK */ /* Check if we are allowed to create the thing */ - if(H5AC_WRITE == thing_acc) { + if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */ /* Create the index block */ hdr->idx_blk_addr = H5EA__iblock_create(hdr, dxpl_id, &stats_changed); if(!H5F_addr_defined(hdr->idx_blk_addr)) @@ -439,7 +442,7 @@ HDfprintf(stderr, "%s: dblk_idx = %u, iblock->ndblk_addrs = %Zu\n", FUNC, dblk_i /* Check if the data block has been allocated on disk yet */ if(!H5F_addr_defined(iblock->dblk_addrs[dblk_idx])) { /* Check if we are allowed to create the thing */ - if(H5AC_WRITE == thing_acc) { + if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */ haddr_t dblk_addr; /* Address of data block created */ hsize_t dblk_off; /* Offset of data block in array */ @@ -479,7 +482,7 @@ HDfprintf(stderr, "%s: dblk_idx = %u, iblock->ndblk_addrs = %Zu\n", FUNC, dblk_i /* Check if the super block has been allocated on disk yet */ if(!H5F_addr_defined(iblock->sblk_addrs[sblk_off])) { /* Check if we are allowed to create the thing */ - if(H5AC_WRITE == thing_acc) { + if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */ haddr_t sblk_addr; /* Address of data block created */ /* Create super block */ @@ -512,7 +515,7 @@ HDfprintf(stderr, "%s: dblk_idx = %u, sblock->ndblks = %Zu\n", FUNC, dblk_idx, s /* Check if the data block has been allocated on disk yet */ if(!H5F_addr_defined(sblock->dblk_addrs[dblk_idx])) { /* Check if we are allowed to create the thing */ - if(H5AC_WRITE == thing_acc) { + if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */ haddr_t dblk_addr; /* Address of data block created */ hsize_t dblk_off; /* Offset of data block in array */ @@ -572,7 +575,7 @@ HDfprintf(stderr, "%s: sblock->dblk_page_size = %Zu\n", FUNC, sblock->dblk_page_ /* Check if page has been initialized yet */ if(!H5VM_bit_get(sblock->page_init, page_init_idx)) { /* Check if we are allowed to create the thing */ - if(H5AC_WRITE == thing_acc) { + if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */ /* Create the data block page */ if(H5EA__dblk_page_create(hdr, dxpl_id, sblock, dblk_page_addr) < 0) H5E_THROW(H5E_CANTCREATE, "unable to create data block page") @@ -681,7 +684,7 @@ HDfprintf(stderr, "%s: Index %Hu\n", FUNC, idx); hdr->f = ea->f; /* Look up the array metadata containing the element we want to set */ - if(H5EA__lookup_elmt(ea, dxpl_id, idx, H5AC_WRITE, &thing, &thing_elmt_buf, &thing_elmt_idx, &thing_unprot_func) < 0) + if(H5EA__lookup_elmt(ea, dxpl_id, idx, H5AC__NO_FLAGS_SET, &thing, &thing_elmt_buf, &thing_elmt_idx, &thing_unprot_func) < 0) H5E_THROW(H5E_CANTPROTECT, "unable to protect array metadata") /* Sanity check */ @@ -766,7 +769,7 @@ HDfprintf(stderr, "%s: Index block address is: %a\n", FUNC, hdr->idx_blk_addr); hdr->f = ea->f; /* Look up the array metadata containing the element we want to set */ - if(H5EA__lookup_elmt(ea, dxpl_id, idx, H5AC_READ, &thing, &thing_elmt_buf, &thing_elmt_idx, &thing_unprot_func) < 0) + if(H5EA__lookup_elmt(ea, dxpl_id, idx, H5AC__READ_ONLY_FLAG, &thing, &thing_elmt_buf, &thing_elmt_idx, &thing_unprot_func) < 0) H5E_THROW(H5E_CANTPROTECT, "unable to protect array metadata") /* Check if the thing holding the element has been created yet */ @@ -873,7 +876,6 @@ CATCH END_FUNC(PRIV) /* end H5EA_undepend() */ - /*------------------------------------------------------------------------- * Function: H5EA_close @@ -943,7 +945,7 @@ HDfprintf(stderr, "%s: Called\n", FUNC); /* Lock the array header into memory */ /* (OK to pass in NULL for callback context, since we know the header must be in the cache) */ - if(NULL == (hdr = H5EA__hdr_protect(ea->f, dxpl_id, ea_addr, NULL, H5AC_WRITE))) + if(NULL == (hdr = H5EA__hdr_protect(ea->f, dxpl_id, ea_addr, NULL, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTLOAD, "unable to load extensible array header") /* Set the shared array header's file context for this operation */ @@ -1007,7 +1009,7 @@ H5EA_delete(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr, void *ctx_udata)) #ifdef QAK HDfprintf(stderr, "%s: ea_addr = %a\n", FUNC, ea_addr); #endif /* QAK */ - if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, ea_addr, ctx_udata, H5AC_WRITE))) + if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, ea_addr, ctx_udata, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array header, address = %llu", (unsigned long long)ea_addr) /* Check for files using shared array header */ diff --git a/src/H5EAcache.c b/src/H5EAcache.c index 3363701..ba7ee5d 100644 --- a/src/H5EAcache.c +++ b/src/H5EAcache.c @@ -57,13 +57,6 @@ #define H5EA_SBLOCK_VERSION 0 /* Super block */ #define H5EA_DBLOCK_VERSION 0 /* Data block */ -/* Size of stack buffer for serialization buffers */ -#define H5EA_HDR_BUF_SIZE 512 -#define H5EA_IBLOCK_BUF_SIZE 512 -#define H5EA_SBLOCK_BUF_SIZE 512 -#define H5EA_DBLOCK_BUF_SIZE 512 -#define H5EA_DBLK_PAGE_BUF_SIZE 512 - /******************/ /* Local Typedefs */ @@ -80,35 +73,74 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static H5EA_hdr_t *H5EA__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5EA__cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5EA_hdr_t *hdr, unsigned * flags_ptr); -static herr_t H5EA__cache_hdr_clear(H5F_t *f, H5EA_hdr_t *hdr, hbool_t destroy); -static herr_t H5EA__cache_hdr_size(const H5F_t *f, const H5EA_hdr_t *hdr, size_t *size_ptr); -static herr_t H5EA__cache_hdr_dest(H5F_t *f, H5EA_hdr_t *hdr); -static H5EA_iblock_t *H5EA__cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5EA__cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5EA_iblock_t *iblock, unsigned * flags_ptr); -static herr_t H5EA__cache_iblock_clear(H5F_t *f, H5EA_iblock_t *iblock, hbool_t destroy); -static herr_t H5EA__cache_iblock_notify(H5AC_notify_action_t action, H5EA_iblock_t *iblock); -static herr_t H5EA__cache_iblock_size(const H5F_t *f, const H5EA_iblock_t *iblock, size_t *size_ptr); -static herr_t H5EA__cache_iblock_dest(H5F_t *f, H5EA_iblock_t *iblock); -static H5EA_sblock_t *H5EA__cache_sblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5EA__cache_sblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5EA_sblock_t *sblock, unsigned * flags_ptr); -static herr_t H5EA__cache_sblock_clear(H5F_t *f, H5EA_sblock_t *sblock, hbool_t destroy); -static herr_t H5EA__cache_sblock_size(const H5F_t *f, const H5EA_sblock_t *sblock, size_t *size_ptr); -static herr_t H5EA__cache_sblock_notify(H5AC_notify_action_t action, H5EA_sblock_t *sblock); -static herr_t H5EA__cache_sblock_dest(H5F_t *f, H5EA_sblock_t *sblock); -static H5EA_dblock_t *H5EA__cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5EA__cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5EA_dblock_t *dblock, unsigned * flags_ptr); -static herr_t H5EA__cache_dblock_clear(H5F_t *f, H5EA_dblock_t *dblock, hbool_t destroy); -static herr_t H5EA__cache_dblock_size(const H5F_t *f, const H5EA_dblock_t *dblock, size_t *size_ptr); -static herr_t H5EA__cache_dblock_notify(H5AC_notify_action_t action, H5EA_dblock_t *dblock); -static herr_t H5EA__cache_dblock_dest(H5F_t *f, H5EA_dblock_t *dblock); -static H5EA_dblk_page_t *H5EA__cache_dblk_page_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5EA__cache_dblk_page_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5EA_dblk_page_t *dblk_page, unsigned * flags_ptr); -static herr_t H5EA__cache_dblk_page_clear(H5F_t *f, H5EA_dblk_page_t *dblk_page, hbool_t destroy); -static herr_t H5EA__cache_dblk_page_size(const H5F_t *f, const H5EA_dblk_page_t *dblk_page, size_t *size_ptr); -static herr_t H5EA__cache_dblk_page_notify(H5AC_notify_action_t action, H5EA_dblk_page_t *dblk_page); -static herr_t H5EA__cache_dblk_page_dest(H5F_t *f, H5EA_dblk_page_t *dblk_page); +static herr_t H5EA__cache_hdr_get_load_size(const void *image, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5EA__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5EA__cache_hdr_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5EA__cache_hdr_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5EA__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5EA__cache_hdr_free_icr(void *thing); + +static herr_t H5EA__cache_iblock_get_load_size(const void *image, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5EA__cache_iblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5EA__cache_iblock_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5EA__cache_iblock_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5EA__cache_iblock_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5EA__cache_iblock_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5EA__cache_iblock_free_icr(void *thing); + +static herr_t H5EA__cache_sblock_get_load_size(const void *image, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5EA__cache_sblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5EA__cache_sblock_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5EA__cache_sblock_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5EA__cache_sblock_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5EA__cache_sblock_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5EA__cache_sblock_free_icr(void *thing); + +static herr_t H5EA__cache_dblock_get_load_size(const void *image, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5EA__cache_dblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5EA__cache_dblock_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5EA__cache_dblock_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5EA__cache_dblock_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5EA__cache_dblock_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5EA__cache_dblock_free_icr(void *thing); +static herr_t H5EA__cache_dblock_fsf_size(const void *thing, size_t *fsf_size); + +static herr_t H5EA__cache_dblk_page_get_load_size(const void *image, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5EA__cache_dblk_page_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5EA__cache_dblk_page_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5EA__cache_dblk_page_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5EA__cache_dblk_page_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5EA__cache_dblk_page_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5EA__cache_dblk_page_free_icr(void *thing); /*********************/ @@ -117,57 +149,92 @@ static herr_t H5EA__cache_dblk_page_dest(H5F_t *f, H5EA_dblk_page_t *dblk_page); /* H5EA header inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_EARRAY_HDR[1] = {{ - H5AC_EARRAY_HDR_ID, - (H5AC_load_func_t)H5EA__cache_hdr_load, - (H5AC_flush_func_t)H5EA__cache_hdr_flush, - (H5AC_dest_func_t)H5EA__cache_hdr_dest, - (H5AC_clear_func_t)H5EA__cache_hdr_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5EA__cache_hdr_size, + H5AC_EARRAY_HDR_ID, /* Metadata client ID */ + "Extensible Array Header", /* Metadata client name (for debugging) */ + H5FD_MEM_EARRAY_HDR, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5EA__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5EA__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ + H5EA__cache_hdr_deserialize, /* 'deserialize' callback */ + H5EA__cache_hdr_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5EA__cache_hdr_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5EA__cache_hdr_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* H5EA index block inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_EARRAY_IBLOCK[1] = {{ - H5AC_EARRAY_IBLOCK_ID, - (H5AC_load_func_t)H5EA__cache_iblock_load, - (H5AC_flush_func_t)H5EA__cache_iblock_flush, - (H5AC_dest_func_t)H5EA__cache_iblock_dest, - (H5AC_clear_func_t)H5EA__cache_iblock_clear, - (H5AC_notify_func_t)H5EA__cache_iblock_notify, - (H5AC_size_func_t)H5EA__cache_iblock_size, + H5AC_EARRAY_IBLOCK_ID, /* Metadata client ID */ + "Extensible Array Index Block", /* Metadata client name (for debugging) */ + H5FD_MEM_EARRAY_IBLOCK, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5EA__cache_iblock_get_load_size, /* 'get_load_size' callback */ + H5EA__cache_iblock_verify_chksum, /* 'verify_chksum' callback */ + H5EA__cache_iblock_deserialize, /* 'deserialize' callback */ + H5EA__cache_iblock_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5EA__cache_iblock_serialize, /* 'serialize' callback */ + H5EA__cache_iblock_notify, /* 'notify' callback */ + H5EA__cache_iblock_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* H5EA super block inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_EARRAY_SBLOCK[1] = {{ - H5AC_EARRAY_SBLOCK_ID, - (H5AC_load_func_t)H5EA__cache_sblock_load, - (H5AC_flush_func_t)H5EA__cache_sblock_flush, - (H5AC_dest_func_t)H5EA__cache_sblock_dest, - (H5AC_clear_func_t)H5EA__cache_sblock_clear, - (H5AC_notify_func_t)H5EA__cache_sblock_notify, - (H5AC_size_func_t)H5EA__cache_sblock_size, + H5AC_EARRAY_SBLOCK_ID, /* Metadata client ID */ + "Extensible Array Super Block", /* Metadata client name (for debugging) */ + H5FD_MEM_EARRAY_SBLOCK, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5EA__cache_sblock_get_load_size, /* 'get_load_size' callback */ + H5EA__cache_sblock_verify_chksum, /* 'verify_chksum' callback */ + H5EA__cache_sblock_deserialize, /* 'deserialize' callback */ + H5EA__cache_sblock_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5EA__cache_sblock_serialize, /* 'serialize' callback */ + H5EA__cache_sblock_notify, /* 'notify' callback */ + H5EA__cache_sblock_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* H5EA data block inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_EARRAY_DBLOCK[1] = {{ - H5AC_EARRAY_DBLOCK_ID, - (H5AC_load_func_t)H5EA__cache_dblock_load, - (H5AC_flush_func_t)H5EA__cache_dblock_flush, - (H5AC_dest_func_t)H5EA__cache_dblock_dest, - (H5AC_clear_func_t)H5EA__cache_dblock_clear, - (H5AC_notify_func_t)H5EA__cache_dblock_notify, - (H5AC_size_func_t)H5EA__cache_dblock_size, + H5AC_EARRAY_DBLOCK_ID, /* Metadata client ID */ + "Extensible Array Data Block", /* Metadata client name (for debugging) */ + H5FD_MEM_EARRAY_DBLOCK, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5EA__cache_dblock_get_load_size, /* 'get_load_size' callback */ + H5EA__cache_dblock_verify_chksum, /* 'verify_chksum' callback */ + H5EA__cache_dblock_deserialize, /* 'deserialize' callback */ + H5EA__cache_dblock_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5EA__cache_dblock_serialize, /* 'serialize' callback */ + H5EA__cache_dblock_notify, /* 'notify' callback */ + H5EA__cache_dblock_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + H5EA__cache_dblock_fsf_size, /* 'fsf_size' callback */ }}; /* H5EA data block page inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_EARRAY_DBLK_PAGE[1] = {{ - H5AC_EARRAY_DBLK_PAGE_ID, - (H5AC_load_func_t)H5EA__cache_dblk_page_load, - (H5AC_flush_func_t)H5EA__cache_dblk_page_flush, - (H5AC_dest_func_t)H5EA__cache_dblk_page_dest, - (H5AC_clear_func_t)H5EA__cache_dblk_page_clear, - (H5AC_notify_func_t)H5EA__cache_dblk_page_notify, - (H5AC_size_func_t)H5EA__cache_dblk_page_size, + H5AC_EARRAY_DBLK_PAGE_ID, /* Metadata client ID */ + "Extensible Array Data Block Page", /* Metadata client name (for debugging) */ + H5FD_MEM_EARRAY_DBLK_PAGE, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5EA__cache_dblk_page_get_load_size, /* 'get_load_size' callback */ + H5EA__cache_dblk_page_verify_chksum, /* 'verify_chksum' callback */ + H5EA__cache_dblk_page_deserialize, /* 'deserialize' callback */ + H5EA__cache_dblk_page_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5EA__cache_dblk_page_serialize, /* 'serialize' callback */ + H5EA__cache_dblk_page_notify, /* 'notify' callback */ + H5EA__cache_dblk_page_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -183,95 +250,150 @@ const H5AC_class_t H5AC_EARRAY_DBLK_PAGE[1] = {{ /*------------------------------------------------------------------------- - * Function: H5EA__cache_hdr_load + * Function: H5EA__cache_hdr_get_load_size + * + * Purpose: Compute the size of the data structure on disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 16, 2013 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_hdr_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5EA_hdr_cache_ud_t *udata = (H5EA_hdr_cache_ud_t *)_udata; /* User data for callback */ + + /* Check arguments */ + HDassert(udata); + HDassert(udata->f); + HDassert(image_len); + + if(image == NULL) { + /* Set the image length size */ + *image_len = (size_t)H5EA_HEADER_SIZE_FILE(udata->f); + } else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } + +END_FUNC(STATIC) /* end H5EA__cache_hdr_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_hdr_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. * - * Purpose: Loads an extensible array header from the disk. + * Return: Success: TRUE/FALSE + * Failure: Negative * - * Return: Success: Pointer to a new extensible array + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5EA__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5EA__cache_hdr_verify_chksum() */ + + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_hdr_deserialize + * + * Purpose: Loads a data structure from the disk. + * + * Return: Success: Pointer to a new B-tree. * Failure: NULL * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Aug 26 2008 + * koziol@hdfgroup.org + * July 16, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, -H5EA_hdr_t *, NULL, NULL, -H5EA__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata)) +void *, NULL, NULL, +H5EA__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty)) /* Local variables */ H5EA_cls_id_t id; /* ID of extensible array class, as found in file */ H5EA_hdr_t *hdr = NULL; /* Extensible array info */ - size_t size; /* Header size */ - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5EA_HDR_BUF_SIZE]; /* Buffer for header */ - uint8_t *buf; /* Pointer to header buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5EA_hdr_cache_ud_t *udata = (H5EA_hdr_cache_ud_t *)_udata; + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(image); + HDassert(udata); + HDassert(udata->f); + HDassert(H5F_addr_defined(udata->addr)); /* Allocate space for the extensible array data structure */ - if(NULL == (hdr = H5EA__hdr_alloc(f))) + if(NULL == (hdr = H5EA__hdr_alloc(udata->f))) H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array shared header") /* Set the extensible array header's address */ - hdr->addr = addr; - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the 'base' size of the extensible array header on disk */ - size = H5EA_HEADER_SIZE_HDR(hdr); - - /* Get a pointer to a buffer that's large enough for serialized header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Read and validate header from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_EARRAY_HDR, H5AC_EARRAY_HDR_ID, addr, size, size, buf) < 0) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for extensible array header") - - /* Get temporary pointer to serialized header */ - p = buf; + hdr->addr = udata->addr; /* Magic number */ - if(HDmemcmp(p, H5EA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5EA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) H5E_THROW(H5E_BADVALUE, "wrong extensible array header signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5EA_HDR_VERSION) + if(*image++ != H5EA_HDR_VERSION) H5E_THROW(H5E_VERSION, "wrong extensible array header version") /* Extensible array class */ - id = (H5EA_cls_id_t)*p++; + id = (H5EA_cls_id_t)*image++; if(id >= H5EA_NUM_CLS_ID) H5E_THROW(H5E_BADTYPE, "incorrect extensible array class") hdr->cparam.cls = H5EA_client_class_g[id]; /* General array creation/configuration information */ - hdr->cparam.raw_elmt_size = *p++; /* Element size in file (in bytes) */ - hdr->cparam.max_nelmts_bits = *p++; /* Log2(Max. # of elements in array) - i.e. # of bits needed to store max. # of elements */ - hdr->cparam.idx_blk_elmts = *p++; /* # of elements to store in index block */ - hdr->cparam.data_blk_min_elmts = *p++; /* Min. # of elements per data block */ - hdr->cparam.sup_blk_min_data_ptrs = *p++; /* Min. # of data block pointers for a super block */ - hdr->cparam.max_dblk_page_nelmts_bits = *p++; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */ + hdr->cparam.raw_elmt_size = *image++; /* Element size in file (in bytes) */ + hdr->cparam.max_nelmts_bits = *image++; /* Log2(Max. # of elements in array) - i.e. # of bits needed to store max. # of elements */ + hdr->cparam.idx_blk_elmts = *image++; /* # of elements to store in index block */ + hdr->cparam.data_blk_min_elmts = *image++; /* Min. # of elements per data block */ + hdr->cparam.sup_blk_min_data_ptrs = *image++; /* Min. # of data block pointers for a super block */ + hdr->cparam.max_dblk_page_nelmts_bits = *image++; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */ /* Array statistics */ - hdr->stats.computed.hdr_size = size; /* Size of header in file */ - H5F_DECODE_LENGTH(f, p, hdr->stats.stored.nsuper_blks); /* Number of super blocks created */ - H5F_DECODE_LENGTH(f, p, hdr->stats.stored.super_blk_size); /* Size of super blocks created */ - H5F_DECODE_LENGTH(f, p, hdr->stats.stored.ndata_blks); /* Number of data blocks created */ - H5F_DECODE_LENGTH(f, p, hdr->stats.stored.data_blk_size); /* Size of data blocks created */ - H5F_DECODE_LENGTH(f, p, hdr->stats.stored.max_idx_set); /* Max. index set (+1) */ - H5F_DECODE_LENGTH(f, p, hdr->stats.stored.nelmts); /* Number of elements 'realized' */ + hdr->stats.computed.hdr_size = len; /* Size of header in file */ + H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.nsuper_blks); /* Number of super blocks created */ + H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.super_blk_size); /* Size of super blocks created */ + H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.ndata_blks); /* Number of data blocks created */ + H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.data_blk_size); /* Size of data blocks created */ + H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.max_idx_set); /* Max. index set (+1) */ + H5F_DECODE_LENGTH(udata->f, image, hdr->stats.stored.nelmts); /* Number of elements 'realized' */ /* Internal information */ - H5F_addr_decode(f, &p, &hdr->idx_blk_addr); /* Address of index block */ + H5F_addr_decode(udata->f, &image, &hdr->idx_blk_addr); /* Address of index block */ /* Index block statistics */ if(H5F_addr_defined(hdr->idx_blk_addr)) { @@ -296,17 +418,20 @@ H5EA__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata)) /* Sanity check */ /* (allow for checksum not decoded yet) */ - HDassert((size_t)(p - buf) == (size - H5EA_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM)); - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - buf) == (size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == len); /* Finish initializing extensible array header */ - if(H5EA__hdr_init(hdr, udata) < 0) + if(H5EA__hdr_init(hdr, udata->ctx_udata) < 0) H5E_THROW(H5E_CANTINIT, "initialization failed for extensible array header") - HDassert(hdr->size == size); + HDassert(hdr->size == len); /* Set return value */ ret_value = hdr; @@ -314,261 +439,251 @@ H5EA__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata)) CATCH /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") if(!ret_value) if(hdr && H5EA__hdr_dest(hdr) < 0) H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array header") -END_FUNC(STATIC) /* end H5EA__cache_hdr_load() */ +END_FUNC(STATIC) /* end H5EA__cache_hdr_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_hdr_flush + * Function: H5EA__cache_hdr_image_len * - * Purpose: Flushes a dirty extensible array header to disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Aug 26 2008 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 16, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5EA__cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5EA_hdr_t *hdr, unsigned H5_ATTR_UNUSED * flags_ptr)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_hdr_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5EA_HDR_BUF_SIZE]; /* Buffer for header */ + /* Local variables */ + const H5EA_hdr_t *hdr = (const H5EA_hdr_t *)_thing; /* Pointer to the object */ - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(hdr); + HDassert(image_len); - if(hdr->cache_info.is_dirty) { - uint8_t *buf; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t size; /* Header size on disk */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the array header on disk */ - size = hdr->size; + /* Set the image length size */ + *image_len = hdr->size; - /* Get a pointer to a buffer that's large enough for serialized header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") +END_FUNC(STATIC) /* end H5EA__cache_hdr_image_len() */ - /* Get temporary pointer to serialized header */ - p = buf; - - /* Magic number */ - HDmemcpy(p, H5EA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5EA_HDR_VERSION; + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_hdr_serialize + * + * Purpose: Flushes a dirty object to disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 16, 2013 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_hdr_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing)) - /* Extensible array type */ - *p++ = hdr->cparam.cls->id; + /* Local variables */ + H5EA_hdr_t *hdr = (H5EA_hdr_t *)_thing; /* Pointer to the extensible array header */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ - /* General array creation/configuration information */ - *p++ = hdr->cparam.raw_elmt_size; /* Element size in file (in bytes) */ - *p++ = hdr->cparam.max_nelmts_bits; /* Log2(Max. # of elements in array) - i.e. # of bits needed to store max. # of elements */ - *p++ = hdr->cparam.idx_blk_elmts; /* # of elements to store in index block */ - *p++ = hdr->cparam.data_blk_min_elmts; /* Min. # of elements per data block */ - *p++ = hdr->cparam.sup_blk_min_data_ptrs; /* Min. # of data block pointers for a super block */ - *p++ = hdr->cparam.max_dblk_page_nelmts_bits; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */ + /* check arguments */ + HDassert(f); + HDassert(image); + HDassert(hdr); - /* Array statistics */ - H5F_ENCODE_LENGTH(f, p, hdr->stats.stored.nsuper_blks); /* Number of super blocks created */ - H5F_ENCODE_LENGTH(f, p, hdr->stats.stored.super_blk_size); /* Size of super blocks created */ - H5F_ENCODE_LENGTH(f, p, hdr->stats.stored.ndata_blks); /* Number of data blocks created */ - H5F_ENCODE_LENGTH(f, p, hdr->stats.stored.data_blk_size); /* Size of data blocks created */ - H5F_ENCODE_LENGTH(f, p, hdr->stats.stored.max_idx_set); /* Max. index set (+1) */ - H5F_ENCODE_LENGTH(f, p, hdr->stats.stored.nelmts); /* Number of elements 'realized' */ + /* Magic number */ + HDmemcpy(image, H5EA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Internal information */ - H5F_addr_encode(f, &p, hdr->idx_blk_addr); /* Address of index block */ + /* Version # */ + *image++ = H5EA_HDR_VERSION; - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); + /* Extensible array type */ + *image++ = hdr->cparam.cls->id; - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); + /* General array creation/configuration information */ + *image++ = hdr->cparam.raw_elmt_size; /* Element size in file (in bytes) */ + *image++ = hdr->cparam.max_nelmts_bits; /* Log2(Max. # of elements in array) - i.e. # of bits needed to store max. # of elements */ + *image++ = hdr->cparam.idx_blk_elmts; /* # of elements to store in index block */ + *image++ = hdr->cparam.data_blk_min_elmts; /* Min. # of elements per data block */ + *image++ = hdr->cparam.sup_blk_min_data_ptrs; /* Min. # of data block pointers for a super block */ + *image++ = hdr->cparam.max_dblk_page_nelmts_bits; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */ - /* Write the array header. */ - HDassert((size_t)(p - buf) == size); - if(H5F_block_write(f, H5FD_MEM_EARRAY_HDR, addr, size, dxpl_id, buf) < 0) - H5E_THROW(H5E_WRITEERROR, "unable to save extensible array header to disk") + /* Array statistics */ + H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.nsuper_blks); /* Number of super blocks created */ + H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.super_blk_size); /* Size of super blocks created */ + H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.ndata_blks); /* Number of data blocks created */ + H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.data_blk_size); /* Size of data blocks created */ + H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.max_idx_set); /* Max. index set (+1) */ + H5F_ENCODE_LENGTH(f, image, hdr->stats.stored.nelmts); /* Number of elements 'realized' */ - hdr->cache_info.is_dirty = FALSE; - } /* end if */ + /* Internal information */ + H5F_addr_encode(f, &image, hdr->idx_blk_addr); /* Address of index block */ - if(destroy) - if(H5EA__cache_hdr_dest(f, hdr) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array header") + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); -CATCH + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= len); -END_FUNC(STATIC) /* end H5EA__cache_hdr_flush() */ +END_FUNC(STATIC) /* end H5EA__cache_hdr_serialize() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_hdr_clear + * Function: H5EA__cache_hdr_free_icr * - * Purpose: Mark a extensible array header in memory as non-dirty. + * Purpose: Destroy/release an "in core representation" of a data + * structure * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Aug 26 2008 + * koziol@hdfgroup.org + * July 16, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__cache_hdr_clear(H5F_t *f, H5EA_hdr_t *hdr, hbool_t destroy)) +H5EA__cache_hdr_free_icr(void *thing)) - /* Sanity check */ - HDassert(hdr); - - /* Reset the dirty flag. */ - hdr->cache_info.is_dirty = FALSE; + /* Check arguments */ + HDassert(thing); - if(destroy) - if(H5EA__cache_hdr_dest(f, hdr) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array header") + /* Release the extensible array header */ + if(H5EA__hdr_dest((H5EA_hdr_t *)thing) < 0) + H5E_THROW(H5E_CANTFREE, "can't free extensible array header") CATCH -END_FUNC(STATIC) /* end H5EA__cache_hdr_clear() */ +END_FUNC(STATIC) /* end H5EA__cache_hdr_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_hdr_size + * Function: H5EA__cache_iblock_get_load_size * - * Purpose: Compute the size in bytes of a extensible array header - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Compute the size of the data structure on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Aug 26 2008 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ -/* ARGSUSED */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5EA__cache_hdr_size(const H5F_t H5_ATTR_UNUSED *f, const H5EA_hdr_t *hdr, - size_t *size_ptr)) +H5EA__cache_iblock_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) - /* Sanity check */ - HDassert(f); + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5EA_hdr_t *hdr = (H5EA_hdr_t *)_udata; /* User data for callback */ + H5EA_iblock_t iblock; /* Fake index block for computing size */ + + /* Check arguments */ HDassert(hdr); - HDassert(size_ptr); + HDassert(image_len); - /* Set size value */ - *size_ptr = hdr->size; + if(image == NULL) { + /* Set up fake index block for computing size on disk */ + HDmemset(&iblock, 0, sizeof(iblock)); + iblock.hdr = (H5EA_hdr_t *)hdr; /* Casting away 'const' OK - QAK */ + iblock.nsblks = H5EA_SBLK_FIRST_IDX(hdr->cparam.sup_blk_min_data_ptrs); + iblock.ndblk_addrs = 2 * ((size_t)hdr->cparam.sup_blk_min_data_ptrs - 1); + iblock.nsblk_addrs = hdr->nsblks - iblock.nsblks; -END_FUNC(STATIC) /* end H5EA__cache_hdr_size() */ + /* Set the image length size */ + *image_len = (size_t)H5EA_IBLOCK_SIZE(&iblock); + } else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } + +END_FUNC(STATIC) /* end H5EA__cache_iblock_get_load_size() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_hdr_dest + * Function: H5EA__cache_iblock_verify_chksum * - * Purpose: Destroys an extensible array header in memory. + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. * - * Return: Non-negative on success/Negative on failure + * Return: Success: TRUE/FALSE + * Failure: Negative * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Aug 26 2008 + * Programmer: Vailin Choi; Aug 2015 * *------------------------------------------------------------------------- */ -/* ARGSUSED */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5EA__cache_hdr_dest(H5F_t *f, H5EA_hdr_t *hdr)) - - /* Check arguments */ - HDassert(f); - HDassert(hdr); - - /* Verify that header is clean */ - HDassert(hdr->cache_info.is_dirty == FALSE); +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5EA__cache_iblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!hdr->cache_info.free_file_space_on_destroy || H5F_addr_defined(hdr->cache_info.addr)); + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ - /* Check for freeing file space for extensible array header */ - if(hdr->cache_info.free_file_space_on_destroy) { - /* Sanity check address */ - HDassert(H5F_addr_eq(hdr->addr, hdr->cache_info.addr)); + /* Check arguments */ + HDassert(image); - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_EARRAY_HDR, H5AC_dxpl_id, hdr->cache_info.addr, (hsize_t)hdr->size) < 0) - H5E_THROW(H5E_CANTFREE, "unable to free extensible array header") - } /* end if */ + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); - /* Release the extensible array header */ - if(H5EA__hdr_dest(hdr) < 0) - H5E_THROW(H5E_CANTFREE, "can't free extensible array header") - -CATCH + if(stored_chksum != computed_chksum) + ret_value = FALSE; -END_FUNC(STATIC) /* end H5EA__cache_hdr_dest() */ +END_FUNC(STATIC) /* end H5EA__cache_iblock_verify_chksum() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_iblock_load + * Function: H5EA__cache_iblock_deserialize * - * Purpose: Loads an extensible array index block from the disk. + * Purpose: Loads a data structure from the disk. * - * Return: Success: Pointer to a new extensible array index block + * Return: Success: Pointer to a new B-tree. * Failure: NULL * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sep 9 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, -H5EA_iblock_t *, NULL, NULL, -H5EA__cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) +void *, NULL, NULL, +H5EA__cache_iblock_deserialize(const void *_image, size_t len, + void *_udata, hbool_t H5_ATTR_UNUSED *dirty)) /* Local variables */ - H5EA_hdr_t *hdr = (H5EA_hdr_t *)_udata; /* Shared extensible array information */ H5EA_iblock_t *iblock = NULL; /* Index block info */ - size_t size; /* Index block size */ - H5WB_t *wb = NULL; /* Wrapped buffer for index block data */ - uint8_t iblock_buf[H5EA_IBLOCK_BUF_SIZE]; /* Buffer for index block */ - uint8_t *buf; /* Pointer to index block buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5EA_hdr_t *hdr = (H5EA_hdr_t *)_udata; /* User data for callback */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ haddr_t arr_addr; /* Address of array header in the file */ size_t u; /* Local index variable */ - /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ + HDassert(image); HDassert(hdr); /* Allocate the extensible array index block */ @@ -576,41 +691,23 @@ H5EA__cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array index block") /* Set the extensible array index block's address */ - iblock->addr = addr; - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(iblock_buf, sizeof(iblock_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the extensible array index block on disk */ - size = H5EA_IBLOCK_SIZE(iblock); - - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Read and validate index block from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_EARRAY_IBLOCK, H5AC_EARRAY_IBLOCK_ID, addr, size, size, buf) < 0) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for extensible array index block") - - /* Get temporary pointer to serialized header */ - p = buf; + iblock->addr = hdr->idx_blk_addr; /* Magic number */ - if(HDmemcmp(p, H5EA_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5EA_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) H5E_THROW(H5E_BADVALUE, "wrong extensible array index block signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5EA_IBLOCK_VERSION) + if(*image++ != H5EA_IBLOCK_VERSION) H5E_THROW(H5E_VERSION, "wrong extensible array index block version") /* Extensible array type */ - if(*p++ != (uint8_t)hdr->cparam.cls->id) + if(*image++ != (uint8_t)hdr->cparam.cls->id) H5E_THROW(H5E_BADTYPE, "incorrect extensible array class") /* Address of header for array that owns this block (just for file integrity checks) */ - H5F_addr_decode(f, &p, &arr_addr); + H5F_addr_decode(hdr->f, &image, &arr_addr); if(H5F_addr_ne(arr_addr, hdr->addr)) H5E_THROW(H5E_BADVALUE, "wrong extensible array header address") @@ -619,36 +716,39 @@ H5EA__cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) /* Decode elements in index block */ if(hdr->cparam.idx_blk_elmts > 0) { /* Convert from raw elements on disk into native elements in memory */ - if((hdr->cparam.cls->decode)(p, iblock->elmts, (size_t)hdr->cparam.idx_blk_elmts, hdr->cb_ctx) < 0) + if((hdr->cparam.cls->decode)(image, iblock->elmts, (size_t)hdr->cparam.idx_blk_elmts, hdr->cb_ctx) < 0) H5E_THROW(H5E_CANTDECODE, "can't decode extensible array index elements") - p += (hdr->cparam.idx_blk_elmts * hdr->cparam.raw_elmt_size); + image += (hdr->cparam.idx_blk_elmts * hdr->cparam.raw_elmt_size); } /* end if */ /* Decode data block addresses in index block */ if(iblock->ndblk_addrs > 0) { /* Decode addresses of data blocks in index block */ for(u = 0; u < iblock->ndblk_addrs; u++) - H5F_addr_decode(f, &p, &iblock->dblk_addrs[u]); + H5F_addr_decode(hdr->f, &image, &iblock->dblk_addrs[u]); } /* end if */ /* Decode super block addresses in index block */ if(iblock->nsblk_addrs > 0) { /* Decode addresses of super blocks in index block */ for(u = 0; u < iblock->nsblk_addrs; u++) - H5F_addr_decode(f, &p, &iblock->sblk_addrs[u]); + H5F_addr_decode(hdr->f, &image, &iblock->sblk_addrs[u]); } /* end if */ /* Sanity check */ /* (allow for checksum not decoded yet) */ - HDassert((size_t)(p - buf) == (size - H5EA_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM)); /* Save the index block's size */ - iblock->size = size; + iblock->size = len; + + /* checksum verification already done in verify_chksum cb */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - buf) == (iblock->size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == iblock->size); /* Set return value */ ret_value = iblock; @@ -656,161 +756,128 @@ H5EA__cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) CATCH /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") if(!ret_value) if(iblock && H5EA__iblock_dest(iblock) < 0) H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array index block") -END_FUNC(STATIC) /* end H5EA__cache_iblock_load() */ +END_FUNC(STATIC) /* end H5EA__cache_iblock_deserialize() */ + + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_iblock_image_len + * + * Purpose: Compute the size of the data structure on disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 17, 2013 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_iblock_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) + + /* Local variables */ + const H5EA_iblock_t *iblock = (const H5EA_iblock_t *)_thing; /* Pointer to the object */ + + /* Check arguments */ + HDassert(iblock); + HDassert(image_len); + + /* Set the image length size */ + *image_len = iblock->size; + +END_FUNC(STATIC) /* end H5EA__cache_iblock_image_len() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_iblock_flush + * Function: H5EA__cache_iblock_serialize * - * Purpose: Flushes a dirty extensible array index block to disk. + * Purpose: Flushes a dirty object to disk. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sep 9 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5EA_iblock_t *iblock, unsigned H5_ATTR_UNUSED * flags_ptr)) +H5EA__cache_iblock_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing)) /* Local variables */ - H5WB_t *wb = NULL; /* Wrapped buffer for serializing data */ - uint8_t ser_buf[H5EA_IBLOCK_BUF_SIZE]; /* Serialization buffer */ + H5EA_iblock_t *iblock = (H5EA_iblock_t *)_thing; /* Pointer to the object to serialize */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ - /* Sanity check */ + /* check arguments */ HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(image); HDassert(iblock); HDassert(iblock->hdr); - if(iblock->cache_info.is_dirty) { - uint8_t *buf; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t size; /* Index block size on disk */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(ser_buf, sizeof(ser_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the index block on disk */ - size = iblock->size; - - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Get temporary pointer to serialized info */ - p = buf; - - /* Magic number */ - HDmemcpy(p, H5EA_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5EA_IBLOCK_VERSION; - - /* Extensible array type */ - *p++ = iblock->hdr->cparam.cls->id; + /* Get temporary pointer to serialized info */ - /* Address of array header for array which owns this block */ - H5F_addr_encode(f, &p, iblock->hdr->addr); - - /* Internal information */ - - /* Encode elements in index block */ - if(iblock->hdr->cparam.idx_blk_elmts > 0) { - /* Convert from native elements in memory into raw elements on disk */ - if((iblock->hdr->cparam.cls->encode)(p, iblock->elmts, (size_t)iblock->hdr->cparam.idx_blk_elmts, iblock->hdr->cb_ctx) < 0) - H5E_THROW(H5E_CANTENCODE, "can't encode extensible array index elements") - p += (iblock->hdr->cparam.idx_blk_elmts * iblock->hdr->cparam.raw_elmt_size); - } /* end if */ - - /* Encode data block addresses in index block */ - if(iblock->ndblk_addrs > 0) { - size_t u; /* Local index variable */ + /* Magic number */ + HDmemcpy(image, H5EA_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Encode addresses of data blocks in index block */ - for(u = 0; u < iblock->ndblk_addrs; u++) - H5F_addr_encode(f, &p, iblock->dblk_addrs[u]); - } /* end if */ + /* Version # */ + *image++ = H5EA_IBLOCK_VERSION; - /* Encode data block addresses in index block */ - if(iblock->nsblk_addrs > 0) { - size_t u; /* Local index variable */ + /* Extensible array type */ + *image++ = iblock->hdr->cparam.cls->id; - /* Encode addresses of super blocks in index block */ - for(u = 0; u < iblock->nsblk_addrs; u++) - H5F_addr_encode(f, &p, iblock->sblk_addrs[u]); - } /* end if */ + /* Address of array header for array which owns this block */ + H5F_addr_encode(f, &image, iblock->hdr->addr); - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); + /* Internal information */ - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); + /* Encode elements in index block */ + if(iblock->hdr->cparam.idx_blk_elmts > 0) { + /* Convert from native elements in memory into raw elements on disk */ + if((iblock->hdr->cparam.cls->encode)(image, iblock->elmts, (size_t)iblock->hdr->cparam.idx_blk_elmts, iblock->hdr->cb_ctx) < 0) + H5E_THROW(H5E_CANTENCODE, "can't encode extensible array index elements") + image += (iblock->hdr->cparam.idx_blk_elmts * iblock->hdr->cparam.raw_elmt_size); + } /* end if */ - /* Write the index block */ - HDassert((size_t)(p - buf) == size); - if(H5F_block_write(f, H5FD_MEM_EARRAY_IBLOCK, addr, size, dxpl_id, buf) < 0) - H5E_THROW(H5E_WRITEERROR, "unable to save extensible array index block to disk") + /* Encode data block addresses in index block */ + if(iblock->ndblk_addrs > 0) { + size_t u; /* Local index variable */ - iblock->cache_info.is_dirty = FALSE; + /* Encode addresses of data blocks in index block */ + for(u = 0; u < iblock->ndblk_addrs; u++) + H5F_addr_encode(f, &image, iblock->dblk_addrs[u]); } /* end if */ - if(destroy) - if(H5EA__cache_iblock_dest(f, iblock) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array index block") - -CATCH + /* Encode data block addresses in index block */ + if(iblock->nsblk_addrs > 0) { + size_t u; /* Local index variable */ - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") + /* Encode addresses of super blocks in index block */ + for(u = 0; u < iblock->nsblk_addrs; u++) + H5F_addr_encode(f, &image, iblock->sblk_addrs[u]); + } /* end if */ -END_FUNC(STATIC) /* end H5EA__cache_iblock_flush() */ + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); - -/*------------------------------------------------------------------------- - * Function: H5EA__cache_iblock_clear - * - * Purpose: Mark a extensible array index block in memory as non-dirty. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sept 9 2008 - * - *------------------------------------------------------------------------- - */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5EA__cache_iblock_clear(H5F_t *f, H5EA_iblock_t *iblock, hbool_t destroy)) + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); /* Sanity check */ - HDassert(iblock); - - /* Reset the dirty flag */ - iblock->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5EA__cache_iblock_dest(f, iblock) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array index block") + HDassert((size_t)(image - (uint8_t *)_image) <= len); CATCH -END_FUNC(STATIC) /* end H5EA__cache_iblock_clear() */ +END_FUNC(STATIC) /* end H5EA__cache_iblock_serialize() */ /*------------------------------------------------------------------------- @@ -822,13 +889,16 @@ END_FUNC(STATIC) /* end H5EA__cache_iblock_clear() */ * * Programmer: Quincey Koziol * koziol@hdfgroup.org - * Mar 31 2009 + * July 17, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__cache_iblock_notify(H5AC_notify_action_t action, H5EA_iblock_t *iblock)) +H5EA__cache_iblock_notify(H5AC_notify_action_t action, void *_thing)) + + /* Local variables */ + H5EA_iblock_t *iblock = (H5EA_iblock_t *)_thing; /* Pointer to the object */ /* Sanity check */ HDassert(iblock); @@ -838,14 +908,21 @@ H5EA__cache_iblock_notify(H5AC_notify_action_t action, H5EA_iblock_t *iblock)) /* Determine which action to take */ switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: /* Create flush dependency on extensible array header */ if(H5EA__create_flush_depend((H5AC_info_t *)iblock->hdr, (H5AC_info_t *)iblock) < 0) H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between index block and header, address = %llu", (unsigned long long)iblock->addr) break; - case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ - break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: + /* Destroy flush dependency on extensible array header */ + if(H5EA__destroy_flush_depend((H5AC_info_t *)iblock->hdr, (H5AC_info_t *)iblock) < 0) + H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between index block and header, address = %llu", (unsigned long long)iblock->addr) + break; default: #ifdef NDEBUG @@ -862,163 +939,196 @@ END_FUNC(STATIC) /* end H5EA__cache_iblock_notify() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_iblock_size + * Function: H5EA__cache_iblock_free_icr * - * Purpose: Compute the size in bytes of a extensible array index block - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Destroy/release an "in core representation" of a data + * structure * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sept 9 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ -/* ARGSUSED */ -BEGIN_FUNC(STATIC, NOERR, -herr_t, SUCCEED, -, -H5EA__cache_iblock_size(const H5F_t H5_ATTR_UNUSED *f, const H5EA_iblock_t *iblock, - size_t *size_ptr)) +BEGIN_FUNC(STATIC, ERR, +herr_t, SUCCEED, FAIL, +H5EA__cache_iblock_free_icr(void *thing)) - /* Sanity check */ - HDassert(f); - HDassert(iblock); - HDassert(size_ptr); + /* Check arguments */ + HDassert(thing); - /* Set size value */ - *size_ptr = iblock->size; + /* Release the extensible array index block */ + if(H5EA__iblock_dest((H5EA_iblock_t *)thing) < 0) + H5E_THROW(H5E_CANTFREE, "can't free extensible array index block") -END_FUNC(STATIC) /* end H5EA__cache_iblock_size() */ +CATCH + +END_FUNC(STATIC) /* end H5EA__cache_iblock_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_iblock_dest + * Function: H5EA__cache_sblock_get_load_size * - * Purpose: Destroys an extensible array index block in memory. + * Purpose: Compute the size of the data structure on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sep 9 2008 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5EA__cache_iblock_dest(H5F_t *f, H5EA_iblock_t *iblock)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_sblock_get_load_size(const void *_image, void *_udata, + size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) - /* Sanity check */ - HDassert(f); - HDassert(iblock); + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5EA_sblock_cache_ud_t *udata = (H5EA_sblock_cache_ud_t *)_udata; /* User data */ + H5EA_sblock_t sblock; /* Fake super block for computing size */ - /* Verify that index block is clean */ - HDassert(iblock->cache_info.is_dirty == FALSE); + /* Check arguments */ + HDassert(udata); + HDassert(udata->hdr); + HDassert(udata->sblk_idx > 0); + HDassert(H5F_addr_defined(udata->sblk_addr)); + HDassert(image_len); + + if(image == NULL) { + /* Set up fake super block for computing size on disk */ + /* (Note: extracted from H5EA__sblock_alloc) */ + HDmemset(&sblock, 0, sizeof(sblock)); + sblock.hdr = udata->hdr; + sblock.ndblks = udata->hdr->sblk_info[udata->sblk_idx].ndblks; + sblock.dblk_nelmts = udata->hdr->sblk_info[udata->sblk_idx].dblk_nelmts; + + /* Check if # of elements in data blocks requires paging */ + if(sblock.dblk_nelmts > udata->hdr->dblk_page_nelmts) { + /* Compute # of pages in each data block from this super block */ + sblock.dblk_npages = sblock.dblk_nelmts / udata->hdr->dblk_page_nelmts; + + /* Sanity check that we have at least 2 pages in data block */ + HDassert(sblock.dblk_npages > 1); + + /* Sanity check for integer truncation */ + HDassert((sblock.dblk_npages * udata->hdr->dblk_page_nelmts) == sblock.dblk_nelmts); + + /* Compute size of buffer for each data block's 'page init' bitmask */ + sblock.dblk_page_init_size = ((sblock.dblk_npages) + 7) / 8; + HDassert(sblock.dblk_page_init_size > 0); + } /* end if */ + + /* Set the image length size */ + *image_len = (size_t)H5EA_SBLOCK_SIZE(&sblock); + + } else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } + +END_FUNC(STATIC) /* end H5EA__cache_sblock_get_load_size() */ - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!iblock->cache_info.free_file_space_on_destroy || H5F_addr_defined(iblock->cache_info.addr)); + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_sblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5EA__cache_sblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) - /* Check for freeing file space for extensible array index block */ - if(iblock->cache_info.free_file_space_on_destroy) { - /* Sanity check address */ - HDassert(H5F_addr_eq(iblock->addr, iblock->cache_info.addr)); + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_EARRAY_IBLOCK, H5AC_dxpl_id, iblock->cache_info.addr, (hsize_t)iblock->size) < 0) - H5E_THROW(H5E_CANTFREE, "unable to free extensible array index block") - } /* end if */ + /* Check arguments */ + HDassert(image); - /* Release the index block */ - if(H5EA__iblock_dest(iblock) < 0) - H5E_THROW(H5E_CANTFREE, "can't free extensible array index block") + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); -CATCH + if(stored_chksum != computed_chksum) + ret_value = FALSE; -END_FUNC(STATIC) /* end H5EA__cache_iblock_dest() */ +END_FUNC(STATIC) /* end H5EA__cache_sblock_verify_chksum() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_sblock_load + * Function: H5EA__cache_sblock_deserialize * - * Purpose: Loads an extensible array super block from the disk. + * Purpose: Loads a data structure from the disk. * - * Return: Success: Pointer to a new extensible array super block + * Return: Success: Pointer to a new B-tree. * Failure: NULL * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sep 30 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, -H5EA_sblock_t *, NULL, NULL, -H5EA__cache_sblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) +void *, NULL, NULL, +H5EA__cache_sblock_deserialize(const void *_image, size_t len, + void *_udata, hbool_t H5_ATTR_UNUSED *dirty)) /* Local variables */ H5EA_sblock_t *sblock = NULL; /* Super block info */ - H5EA_sblock_cache_ud_t *udata = (H5EA_sblock_cache_ud_t *)_udata; /* User data for loading super block */ - size_t size; /* Super block size */ - H5WB_t *wb = NULL; /* Wrapped buffer for super block data */ - uint8_t sblock_buf[H5EA_IBLOCK_BUF_SIZE]; /* Buffer for super block */ - uint8_t *buf; /* Pointer to super block buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5EA_sblock_cache_ud_t *udata = (H5EA_sblock_cache_ud_t *)_udata; /* User data */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ haddr_t arr_addr; /* Address of array header in the file */ size_t u; /* Local index variable */ /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata && udata->hdr && udata->parent && udata->sblk_idx > 0); + HDassert(udata); + HDassert(udata->hdr); + HDassert(udata->parent); + HDassert(udata->sblk_idx > 0); + HDassert(H5F_addr_defined(udata->sblk_addr)); /* Allocate the extensible array super block */ if(NULL == (sblock = H5EA__sblock_alloc(udata->hdr, udata->parent, udata->sblk_idx))) H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array super block") /* Set the extensible array super block's address */ - sblock->addr = addr; - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(sblock_buf, sizeof(sblock_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the extensible array super block on disk */ - size = H5EA_SBLOCK_SIZE(sblock); - - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Read and validate super block from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_EARRAY_SBLOCK, H5AC_EARRAY_SBLOCK_ID, addr, size, size, buf) < 0) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for extensible array super block") - - /* Get temporary pointer to serialized header */ - p = buf; + sblock->addr = udata->sblk_addr; /* Magic number */ - if(HDmemcmp(p, H5EA_SBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5EA_SBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) H5E_THROW(H5E_BADVALUE, "wrong extensible array super block signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5EA_SBLOCK_VERSION) + if(*image++ != H5EA_SBLOCK_VERSION) H5E_THROW(H5E_VERSION, "wrong extensible array super block version") /* Extensible array type */ - if(*p++ != (uint8_t)udata->hdr->cparam.cls->id) + if(*image++ != (uint8_t)udata->hdr->cparam.cls->id) H5E_THROW(H5E_BADTYPE, "incorrect extensible array class") /* Address of header for array that owns this block (just for file integrity checks) */ - H5F_addr_decode(f, &p, &arr_addr); + H5F_addr_decode(udata->hdr->f, &image, &arr_addr); if(H5F_addr_ne(arr_addr, udata->hdr->addr)) H5E_THROW(H5E_BADVALUE, "wrong extensible array header address") /* Offset of block within the array's address space */ - UINT64DECODE_VAR(p, sblock->block_off, udata->hdr->arr_off_size); + UINT64DECODE_VAR(image, sblock->block_off, udata->hdr->arr_off_size); /* Internal information */ @@ -1027,25 +1137,28 @@ H5EA__cache_sblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) size_t tot_page_init_size = sblock->ndblks * sblock->dblk_page_init_size; /* Compute total size of 'page init' buffer */ /* Retrieve the 'page init' bitmasks */ - HDmemcpy(sblock->page_init, p, tot_page_init_size); - p += tot_page_init_size; + HDmemcpy(sblock->page_init, image, tot_page_init_size); + image += tot_page_init_size; } /* end if */ /* Decode data block addresses */ for(u = 0; u < sblock->ndblks; u++) - H5F_addr_decode(f, &p, &sblock->dblk_addrs[u]); + H5F_addr_decode(udata->hdr->f, &image, &sblock->dblk_addrs[u]); /* Sanity check */ /* (allow for checksum not decoded yet) */ - HDassert((size_t)(p - buf) == (size - H5EA_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM)); /* Save the super block's size */ - sblock->size = size; + sblock->size = len; - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - buf) == (sblock->size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == sblock->size); /* Set return value */ ret_value = sblock; @@ -1053,183 +1166,115 @@ H5EA__cache_sblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) CATCH /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") if(!ret_value) if(sblock && H5EA__sblock_dest(sblock) < 0) H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array super block") -END_FUNC(STATIC) /* end H5EA__cache_sblock_load() */ +END_FUNC(STATIC) /* end H5EA__cache_sblock_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_sblock_flush + * Function: H5EA__cache_sblock_image_len * - * Purpose: Flushes a dirty extensible array super block to disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sep 30 2008 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5EA__cache_sblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5EA_sblock_t *sblock, unsigned H5_ATTR_UNUSED * flags_ptr)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_sblock_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) /* Local variables */ - H5WB_t *wb = NULL; /* Wrapped buffer for serializing data */ - uint8_t ser_buf[H5EA_SBLOCK_BUF_SIZE]; /* Serialization buffer */ + const H5EA_sblock_t *sblock = (const H5EA_sblock_t *)_thing; /* Pointer to the object */ - /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(sblock); - HDassert(sblock->hdr); - - if(sblock->cache_info.is_dirty) { - uint8_t *buf; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t size; /* Index block size on disk */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - size_t u; /* Local index variable */ - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(ser_buf, sizeof(ser_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") + HDassert(image_len); - /* Compute the size of the super block on disk */ - size = sblock->size; + /* Set the image length size */ + *image_len = sblock->size; - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Get temporary pointer to serialized info */ - p = buf; - - /* Magic number */ - HDmemcpy(p, H5EA_SBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5EA_SBLOCK_VERSION; - - /* Extensible array type */ - *p++ = sblock->hdr->cparam.cls->id; - - /* Address of array header for array which owns this block */ - H5F_addr_encode(f, &p, sblock->hdr->addr); - - /* Offset of block in array */ - UINT64ENCODE_VAR(p, sblock->block_off, sblock->hdr->arr_off_size); - - /* Internal information */ - - /* Check for 'page init' bitmasks for this super block */ - if(sblock->dblk_npages > 0) { - size_t tot_page_init_size = sblock->ndblks * sblock->dblk_page_init_size; /* Compute total size of 'page init' buffer */ - - /* Store the 'page init' bitmasks */ - HDmemcpy(p, sblock->page_init, tot_page_init_size); - p += tot_page_init_size; - } /* end if */ - - /* Encode addresses of data blocks in super block */ - for(u = 0; u < sblock->ndblks; u++) - H5F_addr_encode(f, &p, sblock->dblk_addrs[u]); - - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); - - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); - - /* Write the super block */ - HDassert((size_t)(p - buf) == size); - if(H5F_block_write(f, H5FD_MEM_EARRAY_SBLOCK, addr, size, dxpl_id, buf) < 0) - H5E_THROW(H5E_WRITEERROR, "unable to save extensible array super block to disk") - - sblock->cache_info.is_dirty = FALSE; - } /* end if */ - - if(destroy) - if(H5EA__cache_sblock_dest(f, sblock) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array super block") - -CATCH - - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") - -END_FUNC(STATIC) /* end H5EA__cache_sblock_flush() */ +END_FUNC(STATIC) /* end H5EA__cache_sblock_image_len() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_sblock_clear + * Function: H5EA__cache_sblock_serialize * - * Purpose: Mark a extensible array super block in memory as non-dirty. + * Purpose: Flushes a dirty object to disk. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sept 30 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5EA__cache_sblock_clear(H5F_t *f, H5EA_sblock_t *sblock, hbool_t destroy)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_sblock_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing)) - /* Sanity check */ + /* Local variables */ + H5EA_sblock_t *sblock = (H5EA_sblock_t *)_thing; /* Pointer to the object to serialize */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + size_t u; /* Local index variable */ + + /* check arguments */ + HDassert(f); + HDassert(image); HDassert(sblock); + HDassert(sblock->hdr); - /* Reset the dirty flag */ - sblock->cache_info.is_dirty = FALSE; + /* Magic number */ + HDmemcpy(image, H5EA_SBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - if(destroy) - if(H5EA__cache_sblock_dest(f, sblock) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array super block") + /* Version # */ + *image++ = H5EA_SBLOCK_VERSION; -CATCH + /* Extensible array type */ + *image++ = sblock->hdr->cparam.cls->id; -END_FUNC(STATIC) /* end H5EA__cache_sblock_clear() */ + /* Address of array header for array which owns this block */ + H5F_addr_encode(f, &image, sblock->hdr->addr); - -/*------------------------------------------------------------------------- - * Function: H5EA__cache_sblock_size - * - * Purpose: Compute the size in bytes of a extensible array super block - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sept 30 2008 - * - *------------------------------------------------------------------------- - */ -/* ARGSUSED */ -BEGIN_FUNC(STATIC, NOERR, -herr_t, SUCCEED, -, -H5EA__cache_sblock_size(const H5F_t H5_ATTR_UNUSED *f, const H5EA_sblock_t *sblock, - size_t *size_ptr)) + /* Offset of block in array */ + UINT64ENCODE_VAR(image, sblock->block_off, sblock->hdr->arr_off_size); - /* Sanity check */ - HDassert(sblock); - HDassert(size_ptr); + /* Internal information */ - /* Set size value */ - *size_ptr = sblock->size; + /* Check for 'page init' bitmasks for this super block */ + if(sblock->dblk_npages > 0) { + size_t tot_page_init_size = sblock->ndblks * sblock->dblk_page_init_size; /* Compute total size of 'page init' buffer */ + + /* Store the 'page init' bitmasks */ + HDmemcpy(image, sblock->page_init, tot_page_init_size); + image += tot_page_init_size; + } /* end if */ + + /* Encode addresses of data blocks in super block */ + for(u = 0; u < sblock->ndblks; u++) + H5F_addr_encode(f, &image, sblock->dblk_addrs[u]); + + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); + + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= len); -END_FUNC(STATIC) /* end H5EA__cache_sblock_size() */ +END_FUNC(STATIC) /* end H5EA__cache_sblock_serialize() */ /*------------------------------------------------------------------------- @@ -1247,7 +1292,10 @@ END_FUNC(STATIC) /* end H5EA__cache_sblock_size() */ */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__cache_sblock_notify(H5AC_notify_action_t action, H5EA_sblock_t *sblock)) +H5EA__cache_sblock_notify(H5AC_notify_action_t action, void *_thing)) + + /* Local variables */ + H5EA_sblock_t *sblock = (H5EA_sblock_t *)_thing; /* Pointer to the object */ /* Sanity check */ HDassert(sblock); @@ -1257,14 +1305,21 @@ H5EA__cache_sblock_notify(H5AC_notify_action_t action, H5EA_sblock_t *sblock)) /* Determine which action to take */ switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: /* Create flush dependency on index block */ if(H5EA__create_flush_depend((H5AC_info_t *)sblock->parent, (H5AC_info_t *)sblock) < 0) H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between super block and index block, address = %llu", (unsigned long long)sblock->addr) break; - case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ - break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: + /* Destroy flush dependency on index block */ + if(H5EA__destroy_flush_depend((H5AC_info_t *)sblock->parent, (H5AC_info_t *)sblock) < 0) + H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between super block and index block, address = %llu", (unsigned long long)sblock->addr) + break; default: #ifdef NDEBUG @@ -1281,133 +1336,198 @@ END_FUNC(STATIC) /* end H5EA__cache_sblock_notify() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_sblock_dest + * Function: H5EA__cache_sblock_free_icr * - * Purpose: Destroys an extensible array super block in memory. + * Purpose: Destroy/release an "in core representation" of a data + * structure * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sep 30 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__cache_sblock_dest(H5F_t *f, H5EA_sblock_t *sblock)) +H5EA__cache_sblock_free_icr(void *thing)) - /* Sanity check */ - HDassert(f); - HDassert(sblock); + /* Check arguments */ + HDassert(thing); - /* Verify that super block is clean */ - HDassert(sblock->cache_info.is_dirty == FALSE); + /* Release the extensible array super block */ + if(H5EA__sblock_dest((H5EA_sblock_t *)thing) < 0) + H5E_THROW(H5E_CANTFREE, "can't free extensible array super block") - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!sblock->cache_info.free_file_space_on_destroy || H5F_addr_defined(sblock->cache_info.addr)); +CATCH - /* Check for freeing file space for extensible array super block */ - if(sblock->cache_info.free_file_space_on_destroy) { - /* Sanity check address */ - HDassert(H5F_addr_eq(sblock->addr, sblock->cache_info.addr)); +END_FUNC(STATIC) /* end H5EA__cache_sblock_free_icr() */ - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_EARRAY_SBLOCK, H5AC_dxpl_id, sblock->cache_info.addr, (hsize_t)sblock->size) < 0) - H5E_THROW(H5E_CANTFREE, "unable to free extensible array super block") - } /* end if */ + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_dblock_get_load_size + * + * Purpose: Compute the size of the data structure on disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 17, 2013 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_dblock_get_load_size(const void *_image, void *_udata, + size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) - /* Release the super block */ - if(H5EA__sblock_dest(sblock) < 0) - H5E_THROW(H5E_CANTFREE, "can't free extensible array super block") + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5EA_dblock_cache_ud_t *udata = (H5EA_dblock_cache_ud_t *)_udata; /* User data */ + H5EA_dblock_t dblock; /* Fake data block for computing size */ -CATCH + /* Check arguments */ + HDassert(udata); + HDassert(udata->hdr); + HDassert(udata->nelmts > 0); + HDassert(image_len); + + if(image == NULL) { + /* Set up fake data block for computing size on disk */ + /* (Note: extracted from H5EA__dblock_alloc) */ + HDmemset(&dblock, 0, sizeof(dblock)); + + /* need to set: + * + * dblock.hdr + * dblock.npages + * dblock.nelmts + * + * before we invoke either H5EA_DBLOCK_PREFIX_SIZE() or + * H5EA_DBLOCK_SIZE(). + */ + dblock.hdr = udata->hdr; + dblock.nelmts = udata->nelmts; + + if(udata->nelmts > udata->hdr->dblk_page_nelmts) { + /* Set the # of pages in the direct block */ + dblock.npages = udata->nelmts / udata->hdr->dblk_page_nelmts; + HDassert(udata->nelmts==(dblock.npages * udata->hdr->dblk_page_nelmts)); + } /* end if */ + + /* Set the image length size */ + if(!dblock.npages) + *image_len = H5EA_DBLOCK_SIZE(&dblock); + else + *image_len = H5EA_DBLOCK_PREFIX_SIZE(&dblock); + } else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } + +END_FUNC(STATIC) /* end H5EA__cache_dblock_get_load_size() */ -END_FUNC(STATIC) /* end H5EA__cache_sblock_dest() */ + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_dblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5EA__cache_dblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5EA__cache_sblock_verify_chksum() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblock_load + * Function: H5EA__cache_dblock_deserialize * - * Purpose: Loads an extensible array data block from the disk. + * Purpose: Loads a data structure from the disk. * - * Return: Success: Pointer to a new extensible array data block + * Return: Success: Pointer to a new B-tree. * Failure: NULL * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sep 16 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, -H5EA_dblock_t *, NULL, NULL, -H5EA__cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) +void *, NULL, NULL, +H5EA__cache_dblock_deserialize(const void *_image, size_t len, + void *_udata, hbool_t H5_ATTR_UNUSED *dirty)) /* Local variables */ H5EA_dblock_t *dblock = NULL; /* Data block info */ - H5EA_dblock_cache_ud_t *udata = (H5EA_dblock_cache_ud_t *)_udata; /* User data for loading data block */ - size_t size; /* Data block size */ - H5WB_t *wb = NULL; /* Wrapped buffer for data block data */ - uint8_t dblock_buf[H5EA_DBLOCK_BUF_SIZE]; /* Buffer for data block */ - uint8_t *buf; /* Pointer to data block buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5EA_dblock_cache_ud_t *udata = (H5EA_dblock_cache_ud_t *)_udata; /* User data */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ haddr_t arr_addr; /* Address of array header in the file */ - /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata && udata->hdr && udata->parent && udata->nelmts > 0); + /* Check arguments */ + HDassert(udata); + HDassert(udata->hdr); + HDassert(udata->parent); + HDassert(udata->nelmts > 0); + HDassert(H5F_addr_defined(udata->dblk_addr)); /* Allocate the extensible array data block */ if(NULL == (dblock = H5EA__dblock_alloc(udata->hdr, udata->parent, udata->nelmts))) H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array data block") - /* Set the extensible array data block's information */ - dblock->addr = addr; - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(dblock_buf, sizeof(dblock_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the extensible array data block on disk */ - if(!dblock->npages) - size = H5EA_DBLOCK_SIZE(dblock); - else - size = H5EA_DBLOCK_PREFIX_SIZE(dblock); + HDassert(((!dblock->npages) && (len == H5EA_DBLOCK_SIZE(dblock))) || + (len == H5EA_DBLOCK_PREFIX_SIZE(dblock))); - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Read and validate data block from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_EARRAY_DBLOCK, H5AC_EARRAY_DBLOCK_ID, addr, size, size, buf) < 0) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for extensible data block") - - /* Get temporary pointer to serialized header */ - p = buf; + /* Set the extensible array data block's information */ + dblock->addr = udata->dblk_addr; /* Magic number */ - if(HDmemcmp(p, H5EA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5EA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) H5E_THROW(H5E_BADVALUE, "wrong extensible array data block signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5EA_DBLOCK_VERSION) + if(*image++ != H5EA_DBLOCK_VERSION) H5E_THROW(H5E_VERSION, "wrong extensible array data block version") /* Extensible array type */ - if(*p++ != (uint8_t)udata->hdr->cparam.cls->id) + if(*image++ != (uint8_t)udata->hdr->cparam.cls->id) H5E_THROW(H5E_BADTYPE, "incorrect extensible array class") /* Address of header for array that owns this block (just for file integrity checks) */ - H5F_addr_decode(f, &p, &arr_addr); + H5F_addr_decode(udata->hdr->f, &image, &arr_addr); if(H5F_addr_ne(arr_addr, udata->hdr->addr)) H5E_THROW(H5E_BADVALUE, "wrong extensible array header address") /* Offset of block within the array's address space */ - UINT64DECODE_VAR(p, dblock->block_off, udata->hdr->arr_off_size); + UINT64DECODE_VAR(image, dblock->block_off, udata->hdr->arr_off_size); /* Internal information */ @@ -1415,22 +1535,26 @@ H5EA__cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) if(!dblock->npages) { /* Decode elements in data block */ /* Convert from raw elements on disk into native elements in memory */ - if((udata->hdr->cparam.cls->decode)(p, dblock->elmts, udata->nelmts, udata->hdr->cb_ctx) < 0) + if((udata->hdr->cparam.cls->decode)(image, dblock->elmts, udata->nelmts, udata->hdr->cb_ctx) < 0) H5E_THROW(H5E_CANTDECODE, "can't decode extensible array data elements") - p += (udata->nelmts * udata->hdr->cparam.raw_elmt_size); + image += (udata->nelmts * udata->hdr->cparam.raw_elmt_size); } /* end if */ /* Sanity check */ /* (allow for checksum not decoded yet) */ - HDassert((size_t)(p - buf) == (size - H5EA_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM)); /* Set the data block's size */ + /* (Note: This is not the same as the image length, for paged data blocks) */ dblock->size = H5EA_DBLOCK_SIZE(dblock); - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - buf) == (size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == len); /* Set return value */ ret_value = dblock; @@ -1438,151 +1562,116 @@ H5EA__cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) CATCH /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") if(!ret_value) if(dblock && H5EA__dblock_dest(dblock) < 0) H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block") -END_FUNC(STATIC) /* end H5EA__cache_dblock_load() */ +END_FUNC(STATIC) /* end H5EA__cache_dblock_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblock_flush + * Function: H5EA__cache_dblock_image_len * - * Purpose: Flushes a dirty extensible array data block to disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sep 18 2008 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5EA__cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5EA_dblock_t *dblock, unsigned H5_ATTR_UNUSED * flags_ptr)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_dblock_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) /* Local variables */ - H5WB_t *wb = NULL; /* Wrapped buffer for serializing data */ - uint8_t ser_buf[H5EA_DBLOCK_BUF_SIZE]; /* Serialization buffer */ + const H5EA_dblock_t *dblock = (const H5EA_dblock_t *)_thing; /* Pointer to the object */ - /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(dblock); - HDassert(dblock->hdr); - - if(dblock->cache_info.is_dirty) { - uint8_t *buf; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t size; /* Index block size on disk */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(ser_buf, sizeof(ser_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the data block on disk */ - if(!dblock->npages) - size = dblock->size; - else - size = H5EA_DBLOCK_PREFIX_SIZE(dblock); - - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Get temporary pointer to serialized info */ - p = buf; - - /* Magic number */ - HDmemcpy(p, H5EA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5EA_DBLOCK_VERSION; - - /* Extensible array type */ - *p++ = dblock->hdr->cparam.cls->id; + HDassert(image_len); - /* Address of array header for array which owns this block */ - H5F_addr_encode(f, &p, dblock->hdr->addr); - - /* Offset of block in array */ - UINT64ENCODE_VAR(p, dblock->block_off, dblock->hdr->arr_off_size); - - /* Internal information */ - - /* Only encode elements if the data block is not paged */ - if(!dblock->npages) { - /* Encode elements in data block */ - - /* Convert from native elements in memory into raw elements on disk */ - if((dblock->hdr->cparam.cls->encode)(p, dblock->elmts, dblock->nelmts, dblock->hdr->cb_ctx) < 0) - H5E_THROW(H5E_CANTENCODE, "can't encode extensible array data elements") - p += (dblock->nelmts * dblock->hdr->cparam.raw_elmt_size); - } /* end if */ - - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); - - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); - - /* Write the data block */ - HDassert((size_t)(p - buf) == size); - if(H5F_block_write(f, H5FD_MEM_EARRAY_DBLOCK, addr, size, dxpl_id, buf) < 0) - H5E_THROW(H5E_WRITEERROR, "unable to save extensible array data block to disk") - - dblock->cache_info.is_dirty = FALSE; - } /* end if */ - - if(destroy) - if(H5EA__cache_dblock_dest(f, dblock) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block") - -CATCH - - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") + /* Set the image length size */ + if(!dblock->npages) + *image_len = dblock->size; + else + *image_len = (size_t)H5EA_DBLOCK_PREFIX_SIZE(dblock); -END_FUNC(STATIC) /* end H5EA__cache_dblock_flush() */ +END_FUNC(STATIC) /* end H5EA__cache_dblock_image_len() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblock_clear + * Function: H5EA__cache_dblock_serialize * - * Purpose: Mark a extensible array data block in memory as non-dirty. + * Purpose: Flushes a dirty object to disk. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sept 18 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__cache_dblock_clear(H5F_t *f, H5EA_dblock_t *dblock, hbool_t destroy)) +H5EA__cache_dblock_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing)) - /* Sanity check */ + /* Local variables */ + H5EA_dblock_t *dblock = (H5EA_dblock_t *)_thing; /* Pointer to the object to serialize */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + + /* check arguments */ + HDassert(f); + HDassert(image); HDassert(dblock); + HDassert(dblock->hdr); + + /* Magic number */ + HDmemcpy(image, H5EA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Reset the dirty flag */ - dblock->cache_info.is_dirty = FALSE; + /* Version # */ + *image++ = H5EA_DBLOCK_VERSION; - if(destroy) - if(H5EA__cache_dblock_dest(f, dblock) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block") + /* Extensible array type */ + *image++ = dblock->hdr->cparam.cls->id; + + /* Address of array header for array which owns this block */ + H5F_addr_encode(f, &image, dblock->hdr->addr); + + /* Offset of block in array */ + UINT64ENCODE_VAR(image, dblock->block_off, dblock->hdr->arr_off_size); + + /* Internal information */ + + /* Only encode elements if the data block is not paged */ + if(!dblock->npages) { + /* Encode elements in data block */ + + /* Convert from native elements in memory into raw elements on disk */ + if((dblock->hdr->cparam.cls->encode)(image, dblock->elmts, dblock->nelmts, dblock->hdr->cb_ctx) < 0) + H5E_THROW(H5E_CANTENCODE, "can't encode extensible array data elements") + image += (dblock->nelmts * dblock->hdr->cparam.raw_elmt_size); + } /* end if */ + + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); + + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= len); CATCH -END_FUNC(STATIC) /* end H5EA__cache_dblock_clear() */ +END_FUNC(STATIC) /* end H5EA__cache_dblock_serialize() */ /*------------------------------------------------------------------------- @@ -1600,9 +1689,12 @@ END_FUNC(STATIC) /* end H5EA__cache_dblock_clear() */ */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__cache_dblock_notify(H5AC_notify_action_t action, H5EA_dblock_t *dblock)) +H5EA__cache_dblock_notify(H5AC_notify_action_t action, void *_thing)) - /* Sanity check */ + /* Local variables */ + H5EA_dblock_t *dblock = (H5EA_dblock_t *)_thing; /* Pointer to the object */ + + /* Check arguments */ HDassert(dblock); /* Check if the file was opened with SWMR-write access */ @@ -1610,14 +1702,21 @@ H5EA__cache_dblock_notify(H5AC_notify_action_t action, H5EA_dblock_t *dblock)) /* Determine which action to take */ switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: /* Create flush dependency on parent */ if(H5EA__create_flush_depend((H5AC_info_t *)dblock->parent, (H5AC_info_t *)dblock) < 0) H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block and parent, address = %llu", (unsigned long long)dblock->addr) break; - case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ - break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: + /* Destroy flush dependency on parent */ + if(H5EA__destroy_flush_depend((H5AC_info_t *)dblock->parent, (H5AC_info_t *)dblock) < 0) + H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block and parent, address = %llu", (unsigned long long)dblock->addr) + break; default: #ifdef NDEBUG @@ -1634,165 +1733,214 @@ END_FUNC(STATIC) /* end H5EA__cache_dblock_notify() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblock_size + * Function: H5EA__cache_dblock_free_icr * - * Purpose: Compute the size in bytes of a extensible array data block - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Destroy/release an "in core representation" of a data + * structure * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sept 18 2008 + * koziol@hdfgroup.org + * July 17, 2013 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, ERR, +herr_t, SUCCEED, FAIL, +H5EA__cache_dblock_free_icr(void *thing)) + + /* Check arguments */ + HDassert(thing); + + /* Release the extensible array data block */ + if(H5EA__dblock_dest((H5EA_dblock_t *)thing) < 0) + H5E_THROW(H5E_CANTFREE, "can't free extensible array data block") + +CATCH + +END_FUNC(STATIC) /* end H5EA__cache_dblock_free_icr() */ + + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_dblock_fsf_size + * + * Purpose: Tell the metadata cache the actual amount of file space + * to free when a dblock entry is destroyed with the free + * file space block set. + * + * This function is needed when the data block is paged, as + * the datablock header and all its pages are allocted as a + * single contiguous chunk of file space, and must be + * deallocated the same way. + * + * The size of the chunk of memory in which the dblock + * header and all its pages is stored in the size field, + * so we simply pass that value back to the cache. + * + * If the datablock is not paged, then the size field of + * the cache_info contains the correct size. However this + * value will be the same as the size field, so we return + * the contents of the size field to the cache in this case + * as well. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 12/5/14 * *------------------------------------------------------------------------- */ -/* ARGSUSED */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5EA__cache_dblock_size(const H5F_t H5_ATTR_UNUSED *f, const H5EA_dblock_t *dblock, - size_t *size_ptr)) +H5EA__cache_dblock_fsf_size(const void *_thing, size_t *fsf_size)) - /* Sanity check */ - HDassert(f); + /* Local variables */ + const H5EA_dblock_t *dblock = (const H5EA_dblock_t *)_thing; /* Pointer to the object */ + + /* Check arguments */ HDassert(dblock); - HDassert(size_ptr); + HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblock->cache_info.type == H5AC_EARRAY_DBLOCK); + HDassert(fsf_size); - /* Set size value */ - if(!dblock->npages) - *size_ptr = dblock->size; - else - *size_ptr = H5EA_DBLOCK_PREFIX_SIZE(dblock); + *fsf_size = dblock->size; -END_FUNC(STATIC) /* end H5EA__cache_dblock_size() */ +END_FUNC(STATIC) /* end H5EA__cache_dblock_fsf_size() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblock_dest + * Function: H5EA__cache_dblk_page_get_load_size * - * Purpose: Destroys an extensible array data block in memory. + * Purpose: Compute the size of the data structure on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Sep 18 2008 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ -/* ARGSUSED */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5EA__cache_dblock_dest(H5F_t *f, H5EA_dblock_t *dblock)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_dblk_page_get_load_size(const void *_image, void *_udata, + size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) - /* Sanity check */ - HDassert(f); - HDassert(dblock); + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5EA_dblk_page_cache_ud_t *udata = (H5EA_dblk_page_cache_ud_t *)_udata; /* User data */ - /* Verify that data block is clean */ - HDassert(dblock->cache_info.is_dirty == FALSE); + /* Check arguments */ + HDassert(udata); + HDassert(udata->hdr); + HDassert(image_len); - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!dblock->cache_info.free_file_space_on_destroy || H5F_addr_defined(dblock->cache_info.addr)); + if(image == NULL) + *image_len = (size_t)H5EA_DBLK_PAGE_SIZE(udata->hdr); + else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } - /* Check for freeing file space for extensible array data block */ - if(dblock->cache_info.free_file_space_on_destroy) { - /* Sanity check address */ - HDassert(H5F_addr_eq(dblock->addr, dblock->cache_info.addr)); +END_FUNC(STATIC) /* end H5EA__cache_dblk_page_get_load_size() */ - /* Release the space on disk */ - /* (Includes space for pages!) */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_EARRAY_DBLOCK, H5AC_dxpl_id, dblock->cache_info.addr, (hsize_t)dblock->size) < 0) - H5E_THROW(H5E_CANTFREE, "unable to free extensible array data block") - } /* end if */ + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_dblk_page_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5EA__cache_dblk_page_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) - /* Release the data block */ - if(H5EA__dblock_dest(dblock) < 0) - H5E_THROW(H5E_CANTFREE, "can't free extensible array data block") + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ -CATCH + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); -END_FUNC(STATIC) /* end H5EA__cache_dblock_dest() */ + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5EA__cache_dblk_page_verify_chksum() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblk_page_load + * Function: H5EA__cache_dblk_page_deserialize * - * Purpose: Loads an extensible array data block page from the disk. + * Purpose: Loads a data structure from the disk. * - * Return: Success: Pointer to a new extensible array data block page + * Return: Success: Pointer to a new B-tree. * Failure: NULL * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Nov 20 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, -H5EA_dblk_page_t *, NULL, NULL, -H5EA__cache_dblk_page_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) +void *, NULL, NULL, +H5EA__cache_dblk_page_deserialize(const void *_image, size_t len, + void *_udata, hbool_t H5_ATTR_UNUSED *dirty)) /* Local variables */ H5EA_dblk_page_t *dblk_page = NULL; /* Data block page info */ H5EA_dblk_page_cache_ud_t *udata = (H5EA_dblk_page_cache_ud_t *)_udata; /* User data for loading data block page */ - size_t size; /* Data block page size */ - H5WB_t *wb = NULL; /* Wrapped buffer for data block page data */ - uint8_t dblk_page_buf[H5EA_DBLK_PAGE_BUF_SIZE]; /* Buffer for data block page */ - uint8_t *buf; /* Pointer to data block page buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata && udata->hdr && udata->parent); + HDassert(udata); + HDassert(udata->hdr); + HDassert(udata->parent); + HDassert(H5F_addr_defined(udata->dblk_page_addr)); /* Allocate the extensible array data block page */ if(NULL == (dblk_page = H5EA__dblk_page_alloc(udata->hdr, udata->parent))) H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array data block page") - /* Set the extensible array data block's information */ - dblk_page->addr = addr; - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(dblk_page_buf, sizeof(dblk_page_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the extensible array data block page on disk */ - size = H5EA_DBLK_PAGE_SIZE(udata->hdr); - - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Read and validate data block page from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_EARRAY_DBLK_PAGE, H5AC_EARRAY_DBLK_PAGE_ID, addr, size, size, buf) < 0) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for extensible array data block page") - - /* Get temporary pointer to serialized header */ - p = buf; + /* Set the extensible array data block page's information */ + dblk_page->addr = udata->dblk_page_addr; /* Internal information */ /* Decode elements in data block page */ /* Convert from raw elements on disk into native elements in memory */ - if((udata->hdr->cparam.cls->decode)(p, dblk_page->elmts, udata->hdr->dblk_page_nelmts, udata->hdr->cb_ctx) < 0) + if((udata->hdr->cparam.cls->decode)(image, dblk_page->elmts, udata->hdr->dblk_page_nelmts, udata->hdr->cb_ctx) < 0) H5E_THROW(H5E_CANTDECODE, "can't decode extensible array data elements") - p += (udata->hdr->dblk_page_nelmts * udata->hdr->cparam.raw_elmt_size); + image += (udata->hdr->dblk_page_nelmts * udata->hdr->cparam.raw_elmt_size); /* Sanity check */ /* (allow for checksum not decoded yet) */ - HDassert((size_t)(p - buf) == (size - H5EA_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM)); /* Set the data block page's size */ - dblk_page->size = size; + dblk_page->size = len; - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - buf) == (dblk_page->size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == dblk_page->size); /* Set return value */ ret_value = dblk_page; @@ -1800,129 +1948,94 @@ H5EA__cache_dblk_page_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) CATCH /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") if(!ret_value) if(dblk_page && H5EA__dblk_page_dest(dblk_page) < 0) H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block page") -END_FUNC(STATIC) /* end H5EA__cache_dblk_page_load() */ +END_FUNC(STATIC) /* end H5EA__cache_dblk_page_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblk_page_flush + * Function: H5EA__cache_dblk_page_image_len * - * Purpose: Flushes a dirty extensible array data block page to disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Nov 20 2008 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5EA__cache_dblk_page_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5EA_dblk_page_t *dblk_page, unsigned H5_ATTR_UNUSED * flags_ptr)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5EA__cache_dblk_page_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) /* Local variables */ - H5WB_t *wb = NULL; /* Wrapped buffer for serializing data */ - uint8_t ser_buf[H5EA_DBLK_PAGE_BUF_SIZE]; /* Serialization buffer */ + const H5EA_dblk_page_t *dblk_page = (const H5EA_dblk_page_t *)_thing; /* Pointer to the object */ - /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(dblk_page); - HDassert(dblk_page->hdr); - - if(dblk_page->cache_info.is_dirty) { - uint8_t *buf; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t size; /* Index block size on disk */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(ser_buf, sizeof(ser_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the data block on disk */ - size = dblk_page->size; - - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Get temporary pointer to serialized info */ - p = buf; - - /* Internal information */ - - /* Encode elements in data block page */ - - /* Convert from native elements in memory into raw elements on disk */ - if((dblk_page->hdr->cparam.cls->encode)(p, dblk_page->elmts, dblk_page->hdr->dblk_page_nelmts, dblk_page->hdr->cb_ctx) < 0) - H5E_THROW(H5E_CANTENCODE, "can't encode extensible array data elements") - p += (dblk_page->hdr->dblk_page_nelmts * dblk_page->hdr->cparam.raw_elmt_size); - - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); + HDassert(image_len); - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); + /* Set the image length size */ + *image_len = dblk_page->size; - /* Write the data block */ - HDassert((size_t)(p - buf) == size); - if(H5F_block_write(f, H5FD_MEM_EARRAY_DBLK_PAGE, addr, size, dxpl_id, buf) < 0) - H5E_THROW(H5E_WRITEERROR, "unable to save extensible array data block page to disk") - - dblk_page->cache_info.is_dirty = FALSE; - } /* end if */ - - if(destroy) - if(H5EA__cache_dblk_page_dest(f, dblk_page) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block page") - -CATCH - - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") - -END_FUNC(STATIC) /* end H5EA__cache_dblk_page_flush() */ +END_FUNC(STATIC) /* end H5EA__cache_dblk_page_image_len() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblk_page_clear + * Function: H5EA__cache_dblk_page_serialize * - * Purpose: Mark a extensible array data block page in memory as non-dirty. + * Purpose: Flushes a dirty object to disk. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Nov 20 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__cache_dblk_page_clear(H5F_t *f, H5EA_dblk_page_t *dblk_page, hbool_t destroy)) +H5EA__cache_dblk_page_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing)) - /* Sanity check */ + /* Local variables */ + H5EA_dblk_page_t *dblk_page = (H5EA_dblk_page_t *)_thing; /* Pointer to the object to serialize */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(f); + HDassert(image); HDassert(dblk_page); + HDassert(dblk_page->hdr); - /* Reset the dirty flag */ - dblk_page->cache_info.is_dirty = FALSE; + /* Internal information */ - if(destroy) - if(H5EA__cache_dblk_page_dest(f, dblk_page) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array data block page") + /* Encode elements in data block page */ + + /* Convert from native elements in memory into raw elements on disk */ + if((dblk_page->hdr->cparam.cls->encode)(image, dblk_page->elmts, dblk_page->hdr->dblk_page_nelmts, dblk_page->hdr->cb_ctx) < 0) + H5E_THROW(H5E_CANTENCODE, "can't encode extensible array data elements") + image += (dblk_page->hdr->dblk_page_nelmts * dblk_page->hdr->cparam.raw_elmt_size); + + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); + + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= len); CATCH -END_FUNC(STATIC) /* end H5EA__cache_dblk_page_clear() */ +END_FUNC(STATIC) /* end H5EA__cache_dblk_page_serialize() */ /*------------------------------------------------------------------------- @@ -1940,7 +2053,10 @@ END_FUNC(STATIC) /* end H5EA__cache_dblk_page_clear() */ */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__cache_dblk_page_notify(H5AC_notify_action_t action, H5EA_dblk_page_t *dblk_page)) +H5EA__cache_dblk_page_notify(H5AC_notify_action_t action, void *_thing)) + + /* Local variables */ + H5EA_dblk_page_t *dblk_page = (H5EA_dblk_page_t *)_thing; /* Pointer to the object */ /* Sanity check */ HDassert(dblk_page); @@ -1950,14 +2066,21 @@ H5EA__cache_dblk_page_notify(H5AC_notify_action_t action, H5EA_dblk_page_t *dblk /* Determine which action to take */ switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: /* Create flush dependency on parent */ if(H5EA__create_flush_depend((H5AC_info_t *)dblk_page->parent, (H5AC_info_t *)dblk_page) < 0) H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block page and parent, address = %llu", (unsigned long long)dblk_page->addr) break; - case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ - break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: + /* Destroy flush dependency on parent */ + if(H5EA__destroy_flush_depend((H5AC_info_t *)dblk_page->parent, (H5AC_info_t *)dblk_page) < 0) + H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency between data block page and parent, address = %llu", (unsigned long long)dblk_page->addr) + break; default: #ifdef NDEBUG @@ -1974,70 +2097,31 @@ END_FUNC(STATIC) /* end H5EA__cache_dblk_page_notify() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblk_page_size - * - * Purpose: Compute the size in bytes of a extensible array data block page - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Nov 20 2008 - * - *------------------------------------------------------------------------- - */ -/* ARGSUSED */ -BEGIN_FUNC(STATIC, NOERR, -herr_t, SUCCEED, -, -H5EA__cache_dblk_page_size(const H5F_t H5_ATTR_UNUSED *f, const H5EA_dblk_page_t *dblk_page, - size_t *size_ptr)) - - /* Sanity check */ - HDassert(f); - HDassert(dblk_page); - HDassert(size_ptr); - - /* Set size value */ - *size_ptr = dblk_page->size; - -END_FUNC(STATIC) /* end H5EA__cache_dblk_page_size() */ - - -/*------------------------------------------------------------------------- - * Function: H5EA__cache_dblk_page_dest - * - * Purpose: Destroys an extensible array data block page in memory. + * Function: H5EA__cache_dblk_page_free_icr * - * Note: Does _not_ free the space for the page on disk, that is - * handled through the data block that "owns" the page. + * Purpose: Destroy/release an "in core representation" of a data + * structure * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Nov 20 2008 + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ -/* ARGSUSED */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5EA__cache_dblk_page_dest(H5F_t H5_ATTR_UNUSED *f, H5EA_dblk_page_t *dblk_page)) +H5EA__cache_dblk_page_free_icr(void *thing)) - /* Sanity check */ - HDassert(f); - HDassert(dblk_page); - - /* Verify that data block page is clean */ - HDassert(dblk_page->cache_info.is_dirty == FALSE); + /* Check arguments */ + HDassert(thing); - /* Release the data block page */ - if(H5EA__dblk_page_dest(dblk_page) < 0) + /* Release the extensible array data block page */ + if(H5EA__dblk_page_dest((H5EA_dblk_page_t *)thing) < 0) H5E_THROW(H5E_CANTFREE, "can't free extensible array data block page") CATCH -END_FUNC(STATIC) /* end H5EA__cache_dblk_page_dest() */ +END_FUNC(STATIC) /* end H5EA__cache_dblk_page_free_icr() */ diff --git a/src/H5EAdbg.c b/src/H5EAdbg.c index ff55722..9c3ce6d 100644 --- a/src/H5EAdbg.c +++ b/src/H5EAdbg.c @@ -119,7 +119,7 @@ H5EA__hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, } /* end if */ /* Load the extensible array header */ - if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, addr, dbg_ctx, H5AC_READ))) + if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, addr, dbg_ctx, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header") /* Print opening message */ @@ -218,14 +218,14 @@ H5EA__iblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t H5_ATTR_UNUSED addr, FILE *s } /* end if */ /* Load the extensible array header */ - if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC_READ))) + if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header") /* Sanity check */ HDassert(H5F_addr_eq(hdr->idx_blk_addr, addr)); /* Protect index block */ - if(NULL == (iblock = H5EA__iblock_protect(hdr, dxpl_id, H5AC_READ))) + if(NULL == (iblock = H5EA__iblock_protect(hdr, dxpl_id, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr) /* Print opening message */ @@ -343,12 +343,12 @@ H5EA__sblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int inde } /* end if */ /* Load the extensible array header */ - if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC_READ))) + if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header") /* Protect super block */ /* (Note: setting parent of super block to 'hdr' for this operation should be OK -QAK) */ - if(NULL == (sblock = H5EA__sblock_protect(hdr, dxpl_id, (H5EA_iblock_t *)hdr, addr, sblk_idx, H5AC_READ))) + if(NULL == (sblock = H5EA__sblock_protect(hdr, dxpl_id, (H5EA_iblock_t *)hdr, addr, sblk_idx, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array super block, address = %llu", (unsigned long long)addr) /* Print opening message */ @@ -437,12 +437,12 @@ H5EA__dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int inde } /* end if */ /* Load the extensible array header */ - if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC_READ))) + if(NULL == (hdr = H5EA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load extensible array header") /* Protect data block */ /* (Note: setting parent of data block to 'hdr' for this operation should be OK -QAK) */ - if(NULL == (dblock = H5EA__dblock_protect(hdr, dxpl_id, hdr, addr, dblk_nelmts, H5AC_READ))) + if(NULL == (dblock = H5EA__dblock_protect(hdr, dxpl_id, hdr, addr, dblk_nelmts, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block, address = %llu", (unsigned long long)addr) /* Print opening message */ diff --git a/src/H5EAdblkpage.c b/src/H5EAdblkpage.c index 37fd68b..5d188c2 100644 --- a/src/H5EAdblkpage.c +++ b/src/H5EAdblkpage.c @@ -210,7 +210,7 @@ END_FUNC(PKG) /* end H5EA__dblk_page_create() */ BEGIN_FUNC(PKG, ERR, H5EA_dblk_page_t *, NULL, NULL, H5EA__dblk_page_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, H5EA_sblock_t *parent, - haddr_t dblk_page_addr, H5AC_protect_t rw)) + haddr_t dblk_page_addr, unsigned flags)) /* Local variables */ H5EA_dblk_page_cache_ud_t udata; /* Information needed for loading data block page */ @@ -223,12 +223,16 @@ HDfprintf(stderr, "%s: Called\n", FUNC); HDassert(hdr); HDassert(H5F_addr_defined(dblk_page_addr)); + /* only the H5AC__READ_ONLY_FLAG may be set */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Set up user data */ udata.hdr = hdr; udata.parent = parent; + udata.dblk_page_addr = dblk_page_addr; /* Protect the data block page */ - if(NULL == (ret_value = (H5EA_dblk_page_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_DBLK_PAGE, dblk_page_addr, &udata, rw))) + if(NULL == (ret_value = (H5EA_dblk_page_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_DBLK_PAGE, dblk_page_addr, &udata, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block page, address = %llu", (unsigned long long)dblk_page_addr) CATCH diff --git a/src/H5EAdblock.c b/src/H5EAdblock.c index dd1e7b0..24be87a 100644 --- a/src/H5EAdblock.c +++ b/src/H5EAdblock.c @@ -304,7 +304,7 @@ END_FUNC(PKG) /* end H5EA__dblock_sblk_idx() */ BEGIN_FUNC(PKG, ERR, H5EA_dblock_t *, NULL, NULL, H5EA__dblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, void *parent, - haddr_t dblk_addr, size_t dblk_nelmts, H5AC_protect_t rw)) + haddr_t dblk_addr, size_t dblk_nelmts, unsigned flags)) /* Local variables */ H5EA_dblock_cache_ud_t udata; /* Information needed for loading data block */ @@ -318,13 +318,17 @@ HDfprintf(stderr, "%s: Called\n", FUNC); HDassert(H5F_addr_defined(dblk_addr)); HDassert(dblk_nelmts); + /* only the H5AC__READ_ONLY_FLAG may be set */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Set up user data */ udata.hdr = hdr; udata.parent = parent; udata.nelmts = dblk_nelmts; + udata.dblk_addr = dblk_addr; /* Protect the data block */ - if(NULL == (ret_value = (H5EA_dblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_DBLOCK, dblk_addr, &udata, rw))) + if(NULL == (ret_value = (H5EA_dblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_DBLOCK, dblk_addr, &udata, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block, address = %llu", (unsigned long long)dblk_addr) CATCH @@ -399,7 +403,7 @@ HDfprintf(stderr, "%s: Called\n", FUNC); HDassert(dblk_nelmts > 0); /* Protect data block */ - if(NULL == (dblock = H5EA__dblock_protect(hdr, dxpl_id, parent, dblk_addr, dblk_nelmts, H5AC_WRITE))) + if(NULL == (dblock = H5EA__dblock_protect(hdr, dxpl_id, parent, dblk_addr, dblk_nelmts, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block, address = %llu", (unsigned long long)dblk_addr) /* Check if this is a paged data block */ diff --git a/src/H5EAhdr.c b/src/H5EAhdr.c index 0b8f4bf..e82ad7f 100644 --- a/src/H5EAhdr.c +++ b/src/H5EAhdr.c @@ -628,16 +628,25 @@ END_FUNC(PKG) /* end H5EA__hdr_modified() */ BEGIN_FUNC(PKG, ERR, H5EA_hdr_t *, NULL, NULL, H5EA__hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr, void *ctx_udata, - H5AC_protect_t rw)) + unsigned flags)) /* Local variables */ + H5EA_hdr_cache_ud_t udata; /* User data for cache callbacks */ /* Sanity check */ HDassert(f); HDassert(H5F_addr_defined(ea_addr)); + /* only the H5AC__READ_ONLY_FLAG may appear in flags */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + + /* Set up user data for cache callbacks */ + udata.f = f; + udata.addr = ea_addr; + udata.ctx_udata = ctx_udata; + /* Protect the header */ - if(NULL == (ret_value = (H5EA_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_EARRAY_HDR, ea_addr, ctx_udata, rw))) + if(NULL == (ret_value = (H5EA_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_EARRAY_HDR, ea_addr, &udata, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array header, address = %llu", (unsigned long long)ea_addr) CATCH diff --git a/src/H5EAiblock.c b/src/H5EAiblock.c index 3c2894a..364b443 100644 --- a/src/H5EAiblock.c +++ b/src/H5EAiblock.c @@ -279,7 +279,7 @@ END_FUNC(PKG) /* end H5EA__iblock_create() */ */ BEGIN_FUNC(PKG, ERR, H5EA_iblock_t *, NULL, NULL, -H5EA__iblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, H5AC_protect_t rw)) +H5EA__iblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, unsigned flags)) #ifdef QAK HDfprintf(stderr, "%s: Called\n", FUNC); @@ -288,8 +288,11 @@ HDfprintf(stderr, "%s: Called\n", FUNC); /* Sanity check */ HDassert(hdr); + /* only the H5AC__READ_ONLY_FLAG may be set */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Protect the index block */ - if(NULL == (ret_value = (H5EA_iblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_IBLOCK, hdr->idx_blk_addr, hdr, rw))) + if(NULL == (ret_value = (H5EA_iblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_IBLOCK, hdr->idx_blk_addr, hdr, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr) CATCH @@ -361,7 +364,7 @@ HDfprintf(stderr, "%s: Called\n", FUNC); HDassert(H5F_addr_defined(hdr->idx_blk_addr)); /* Protect index block */ - if(NULL == (iblock = H5EA__iblock_protect(hdr, dxpl_id, H5AC_WRITE))) + if(NULL == (iblock = H5EA__iblock_protect(hdr, dxpl_id, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr) /* Check for index block having data block pointers */ @@ -436,7 +439,6 @@ H5EA__iblock_dest(H5EA_iblock_t *iblock)) /* Sanity check */ HDassert(iblock); - HDassert(iblock->rc == 0); /* Check if shared header field has been initialized */ if(iblock->hdr) { diff --git a/src/H5EApkg.h b/src/H5EApkg.h index 4df40f6..993a9e1 100644 --- a/src/H5EApkg.h +++ b/src/H5EApkg.h @@ -230,7 +230,6 @@ typedef struct H5EA_iblock_t { haddr_t *sblk_addrs; /* Buffer for addresses of super blocks in index block */ /* Internal array information (not stored) */ - size_t rc; /* Reference count of objects using this block */ H5EA_hdr_t *hdr; /* Shared array header info */ haddr_t addr; /* Address of this index block on disk */ size_t size; /* Size of index block on disk */ @@ -252,7 +251,6 @@ typedef struct H5EA_sblock_t { uint8_t *page_init; /* Bitmap of whether a data block page is initialized */ /* Internal array information (not stored) */ - size_t rc; /* Reference count of objects using this block */ H5EA_hdr_t *hdr; /* Shared array header info */ H5EA_iblock_t *parent; /* Parent object for super block (index block) */ haddr_t addr; /* Address of this index block on disk */ @@ -313,11 +311,19 @@ struct H5EA_t { /* Metadata cache callback user data types */ +/* Info needed for loading header */ +typedef struct H5EA_hdr_cache_ud_t { + H5F_t *f; /* Pointer to file for extensible array */ + haddr_t addr; /* Address of header on disk */ + void *ctx_udata; /* User context for class */ +} H5EA_hdr_cache_ud_t; + /* Info needed for loading super block */ typedef struct H5EA_sblock_cache_ud_t { H5EA_hdr_t *hdr; /* Shared extensible array information */ H5EA_iblock_t *parent; /* Pointer to parent object for super block (index block) */ unsigned sblk_idx; /* Index of super block */ + haddr_t sblk_addr; /* Address of super block */ } H5EA_sblock_cache_ud_t; /* Info needed for loading data block */ @@ -325,12 +331,14 @@ typedef struct H5EA_dblock_cache_ud_t { H5EA_hdr_t *hdr; /* Shared extensible array information */ void *parent; /* Pointer to parent object for data block (index or super block) */ size_t nelmts; /* Number of elements in data block */ + haddr_t dblk_addr; /* Address of data block */ } H5EA_dblock_cache_ud_t; /* Info needed for loading data block page */ typedef struct H5EA_dblk_page_cache_ud_t { H5EA_hdr_t *hdr; /* Shared extensible array information */ H5EA_sblock_t *parent; /* Pointer to parent object for data block page (super block) */ + haddr_t dblk_page_addr; /* Address of data block page */ } H5EA_dblk_page_cache_ud_t; #ifdef H5EA_TESTING @@ -389,7 +397,7 @@ H5_DLL herr_t H5EA__hdr_fuse_incr(H5EA_hdr_t *hdr); H5_DLL size_t H5EA__hdr_fuse_decr(H5EA_hdr_t *hdr); H5_DLL herr_t H5EA__hdr_modified(H5EA_hdr_t *hdr); H5_DLL H5EA_hdr_t *H5EA__hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t ea_addr, - void *ctx_udata, H5AC_protect_t rw); + void *ctx_udata, unsigned flags); H5_DLL herr_t H5EA__hdr_unprotect(H5EA_hdr_t *hdr, hid_t dxpl_id, unsigned cache_flags); H5_DLL herr_t H5EA__hdr_delete(H5EA_hdr_t *hdr, hid_t dxpl_id); H5_DLL herr_t H5EA__hdr_dest(H5EA_hdr_t *hdr); @@ -399,7 +407,7 @@ H5_DLL H5EA_iblock_t *H5EA__iblock_alloc(H5EA_hdr_t *hdr); H5_DLL haddr_t H5EA__iblock_create(H5EA_hdr_t *hdr, hid_t dxpl_id, hbool_t *stats_changed); H5_DLL H5EA_iblock_t *H5EA__iblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, - H5AC_protect_t rw); + unsigned flags); H5_DLL herr_t H5EA__iblock_unprotect(H5EA_iblock_t *iblock, hid_t dxpl_id, unsigned cache_flags); H5_DLL herr_t H5EA__iblock_delete(H5EA_hdr_t *hdr, hid_t dxpl_id); @@ -411,7 +419,8 @@ H5_DLL H5EA_sblock_t *H5EA__sblock_alloc(H5EA_hdr_t *hdr, H5EA_iblock_t *parent, H5_DLL haddr_t H5EA__sblock_create(H5EA_hdr_t *hdr, hid_t dxpl_id, H5EA_iblock_t *parent, hbool_t *stats_changed, unsigned sblk_idx); H5_DLL H5EA_sblock_t *H5EA__sblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, - H5EA_iblock_t *parent, haddr_t sblk_addr, unsigned sblk_idx, H5AC_protect_t rw); + H5EA_iblock_t *parent, haddr_t sblk_addr, unsigned sblk_idx, + unsigned flags); H5_DLL herr_t H5EA__sblock_unprotect(H5EA_sblock_t *sblock, hid_t dxpl_id, unsigned cache_flags); H5_DLL herr_t H5EA__sblock_delete(H5EA_hdr_t *hdr, hid_t dxpl_id, @@ -425,7 +434,7 @@ H5_DLL haddr_t H5EA__dblock_create(H5EA_hdr_t *hdr, hid_t dxpl_id, void *parent, hbool_t *stats_changed, hsize_t dblk_off, size_t nelmts); H5_DLL unsigned H5EA__dblock_sblk_idx(const H5EA_hdr_t *hdr, hsize_t idx); H5_DLL H5EA_dblock_t *H5EA__dblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, - void *parent, haddr_t dblk_addr, size_t dblk_nelmts, H5AC_protect_t rw); + void *parent, haddr_t dblk_addr, size_t dblk_nelmts, unsigned flags); H5_DLL herr_t H5EA__dblock_unprotect(H5EA_dblock_t *dblock, hid_t dxpl_id, unsigned cache_flags); H5_DLL herr_t H5EA__dblock_delete(H5EA_hdr_t *hdr, hid_t dxpl_id, void *parent, @@ -437,7 +446,7 @@ H5_DLL H5EA_dblk_page_t *H5EA__dblk_page_alloc(H5EA_hdr_t *hdr, H5EA_sblock_t *p H5_DLL herr_t H5EA__dblk_page_create(H5EA_hdr_t *hdr, hid_t dxpl_id, H5EA_sblock_t *parent, haddr_t addr); H5_DLL H5EA_dblk_page_t *H5EA__dblk_page_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, - H5EA_sblock_t *parent, haddr_t dblk_page_addr, H5AC_protect_t rw); + H5EA_sblock_t *parent, haddr_t dblk_page_addr, unsigned flags); H5_DLL herr_t H5EA__dblk_page_unprotect(H5EA_dblk_page_t *dblk_page, hid_t dxpl_id, unsigned cache_flags); H5_DLL herr_t H5EA__dblk_page_dest(H5EA_dblk_page_t *dblk_page); diff --git a/src/H5EAsblock.c b/src/H5EAsblock.c index 1cc8bd9..33f34c9 100644 --- a/src/H5EAsblock.c +++ b/src/H5EAsblock.c @@ -276,7 +276,7 @@ END_FUNC(PKG) /* end H5EA__sblock_create() */ BEGIN_FUNC(PKG, ERR, H5EA_sblock_t *, NULL, NULL, H5EA__sblock_protect(H5EA_hdr_t *hdr, hid_t dxpl_id, H5EA_iblock_t *parent, - haddr_t sblk_addr, unsigned sblk_idx, H5AC_protect_t rw)) + haddr_t sblk_addr, unsigned sblk_idx, unsigned flags)) /* Local variables */ H5EA_sblock_cache_ud_t udata; /* Information needed for loading super block */ @@ -290,13 +290,17 @@ HDfprintf(stderr, "%s: Called\n", FUNC); HDassert(hdr); HDassert(H5F_addr_defined(sblk_addr)); + /* only the H5AC__READ_ONLY_FLAG may be set */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Set up user data */ udata.hdr = hdr; udata.parent = parent; udata.sblk_idx = sblk_idx; + udata.sblk_addr = sblk_addr; /* Protect the super block */ - if(NULL == (ret_value = (H5EA_sblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_SBLOCK, sblk_addr, &udata, rw))) + if(NULL == (ret_value = (H5EA_sblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_EARRAY_SBLOCK, sblk_addr, &udata, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array super block, address = %llu", (unsigned long long)sblk_addr) CATCH @@ -370,7 +374,7 @@ HDfprintf(stderr, "%s: Called\n", FUNC); HDassert(H5F_addr_defined(sblk_addr)); /* Protect super block */ - if(NULL == (sblock = H5EA__sblock_protect(hdr, dxpl_id, parent, sblk_addr, sblk_idx, H5AC_WRITE))) + if(NULL == (sblock = H5EA__sblock_protect(hdr, dxpl_id, parent, sblk_addr, sblk_idx, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array super block, address = %llu", (unsigned long long)sblk_addr) /* Iterate over data blocks */ @@ -412,7 +416,6 @@ H5EA__sblock_dest(H5EA_sblock_t *sblock)) /* Sanity check */ HDassert(sblock); - HDassert(sblock->rc == 0); #ifdef QAK HDfprintf(stderr, "%s: sblock->hdr->dblk_page_nelmts = %Zu, sblock->ndblks = %Zu, sblock->dblk_nelmts = %Zu\n", FUNC, sblock->hdr->dblk_page_nelmts, sblock->ndblks, sblock->dblk_nelmts); #endif /* QAK */ @@ -143,7 +143,7 @@ HDfprintf(stderr, "%s: Called\n", FUNC); H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array info") /* Lock the array header into memory */ - if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, fa_addr, ctx_udata, H5AC_WRITE))) + if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, fa_addr, ctx_udata, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to load fixed array header") /* Point fixed array wrapper at header and bump it's ref count */ @@ -203,7 +203,7 @@ H5FA_open(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr, void *ctx_udata)) #ifdef H5FA_DEBUG HDfprintf(stderr, "%s: fa_addr = %a\n", FUNC, fa_addr); #endif /* H5FA_DEBUG */ - if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, fa_addr, ctx_udata, H5AC_READ))) + if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, fa_addr, ctx_udata, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load fixed array header, address = %llu", (unsigned long long)fa_addr) /* Check for pending array deletion */ @@ -361,7 +361,7 @@ HDfprintf(stderr, "%s: fixed array data block address not defined!\n", FUNC, idx HDassert(idx < hdr->cparam.nelmts); /* Protect data block */ - if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, hdr->dblk_addr, H5AC_WRITE))) + if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, hdr->dblk_addr, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block, address = %llu", (unsigned long long)hdr->dblk_addr) /* Check for paging data block */ @@ -402,8 +402,8 @@ HDfprintf(stderr, "%s: fixed array data block address not defined!\n", FUNC, idx } /* end if */ /* Protect the data block page */ - if(NULL == (dblk_page = H5FA__dblk_page_protect(hdr, dxpl_id, dblk_page_addr, dblk_page_nelmts, H5AC_WRITE))) - H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block page, address = %llu", (unsigned long long)dblk_page_addr) + if(NULL == (dblk_page = H5FA__dblk_page_protect(hdr, dxpl_id, dblk_page_addr, dblk_page_nelmts, H5AC__NO_FLAGS_SET))) + H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block page, address = %llu", (unsigned long long)dblk_page_addr) /* Set the element in the data block page */ HDmemcpy(((uint8_t *)dblk_page->elmts) + (hdr->cparam.cls->nat_elmt_size * elmt_idx), elmt, hdr->cparam.cls->nat_elmt_size); @@ -469,7 +469,7 @@ HDfprintf(stderr, "%s: Index %Hu\n", FUNC, idx); else { /* Get the data block */ HDassert(H5F_addr_defined(hdr->dblk_addr)); - if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, hdr->dblk_addr, H5AC_READ))) + if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, hdr->dblk_addr, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block, address = %llu", (unsigned long long)hdr->dblk_addr) /* Check for paged data block */ @@ -509,7 +509,7 @@ HDfprintf(stderr, "%s: Index %Hu\n", FUNC, idx); dblk_page_nelmts = dblock->dblk_page_nelmts; /* Protect the data block page */ - if(NULL == (dblk_page = H5FA__dblk_page_protect(hdr, dxpl_id, dblk_page_addr, dblk_page_nelmts, H5AC_READ))) + if(NULL == (dblk_page = H5FA__dblk_page_protect(hdr, dxpl_id, dblk_page_addr, dblk_page_nelmts, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block page, address = %llu", (unsigned long long)dblk_page_addr) /* Retrieve element from data block */ @@ -594,7 +594,7 @@ HDfprintf(stderr, "%s: Called\n", FUNC); /* Lock the array header into memory */ /* (OK to pass in NULL for callback context, since we know the header must be in the cache) */ - if(NULL == (hdr = H5FA__hdr_protect(fa->f, dxpl_id, fa_addr, NULL, H5AC_WRITE))) + if(NULL == (hdr = H5FA__hdr_protect(fa->f, dxpl_id, fa_addr, NULL, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTLOAD, "unable to load fixed array header") /* Set the shared array header's file context for this operation */ @@ -657,7 +657,7 @@ H5FA_delete(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr, void *ctx_udata)) #ifdef H5FA_DEBUG HDfprintf(stderr, "%s: fa_addr = %a\n", FUNC, fa_addr); #endif /* H5FA_DEBUG */ - if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, fa_addr, ctx_udata, H5AC_WRITE))) + if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, fa_addr, ctx_udata, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array header, address = %llu", (unsigned long long)fa_addr) /* Check for files using shared array header */ diff --git a/src/H5FAcache.c b/src/H5FAcache.c index bbfd94e..64d5e60 100644 --- a/src/H5FAcache.c +++ b/src/H5FAcache.c @@ -55,11 +55,6 @@ #define H5FA_HDR_VERSION 0 /* Header */ #define H5FA_DBLOCK_VERSION 0 /* Data block */ -/* Size of stack buffer for serialization buffers */ -#define H5FA_HDR_BUF_SIZE 512 -#define H5FA_DBLOCK_BUF_SIZE 512 -#define H5FA_DBLK_PAGE_BUF_SIZE 512 - /******************/ /* Local Typedefs */ @@ -76,24 +71,45 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static H5FA_hdr_t *H5FA__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5FA__cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FA_hdr_t *hdr, unsigned * flags_ptr); -static herr_t H5FA__cache_hdr_dest(H5F_t *f, H5FA_hdr_t *hdr); -static herr_t H5FA__cache_hdr_clear(H5F_t *f, H5FA_hdr_t *hdr, hbool_t destroy); -static herr_t H5FA__cache_hdr_size(const H5F_t *f, const H5FA_hdr_t *hdr, size_t *size_ptr); - -static H5FA_dblock_t *H5FA__cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5FA__cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FA_dblock_t *dblock, unsigned * flags_ptr); -static herr_t H5FA__cache_dblock_dest(H5F_t *f, H5FA_dblock_t *dblock); -static herr_t H5FA__cache_dblock_clear(H5F_t *f, H5FA_dblock_t *dblock, hbool_t destroy); -static herr_t H5FA__cache_dblock_notify(H5AC_notify_action_t action, H5FA_dblock_t *dblock); -static herr_t H5FA__cache_dblock_size(const H5F_t *f, const H5FA_dblock_t *dblock, size_t *size_ptr); - -static H5FA_dblk_page_t *H5FA__cache_dblk_page_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5FA__cache_dblk_page_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FA_dblk_page_t *dblk_page, unsigned * flags_ptr); -static herr_t H5FA__cache_dblk_page_dest(H5F_t *f, H5FA_dblk_page_t *dblk_page); -static herr_t H5FA__cache_dblk_page_clear(H5F_t *f, H5FA_dblk_page_t *dblk_page, hbool_t destroy); -static herr_t H5FA__cache_dblk_page_size(const H5F_t *f, const H5FA_dblk_page_t *dblk_page, size_t *size_ptr); +static herr_t H5FA__cache_hdr_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5FA__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5FA__cache_hdr_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5FA__cache_hdr_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5FA__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5FA__cache_hdr_free_icr(void *thing); + +static herr_t H5FA__cache_dblock_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5FA__cache_dblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5FA__cache_dblock_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5FA__cache_dblock_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5FA__cache_dblock_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5FA__cache_dblock_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5FA__cache_dblock_free_icr(void *thing); +static herr_t H5FA__cache_dblock_fsf_size(const void *thing, size_t *fsf_size); + +static herr_t H5FA__cache_dblk_page_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5FA__cache_dblk_page_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5FA__cache_dblk_page_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5FA__cache_dblk_page_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5FA__cache_dblk_page_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5FA__cache_dblk_page_free_icr(void *thing); /*********************/ @@ -102,36 +118,56 @@ static herr_t H5FA__cache_dblk_page_size(const H5F_t *f, const H5FA_dblk_page_t /* H5FA header inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FARRAY_HDR[1] = {{ - H5AC_FARRAY_HDR_ID, - (H5AC_load_func_t)H5FA__cache_hdr_load, - (H5AC_flush_func_t)H5FA__cache_hdr_flush, - (H5AC_dest_func_t)H5FA__cache_hdr_dest, - (H5AC_clear_func_t)H5FA__cache_hdr_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5FA__cache_hdr_size, + H5AC_FARRAY_HDR_ID, /* Metadata client ID */ + "Fixed-array Header", /* Metadata client name (for debugging) */ + H5FD_MEM_FARRAY_HDR, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5FA__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5FA__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ + H5FA__cache_hdr_deserialize, /* 'deserialize' callback */ + H5FA__cache_hdr_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5FA__cache_hdr_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5FA__cache_hdr_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; - /* H5FA data block inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FARRAY_DBLOCK[1] = {{ - H5AC_FARRAY_DBLOCK_ID, - (H5AC_load_func_t)H5FA__cache_dblock_load, - (H5AC_flush_func_t)H5FA__cache_dblock_flush, - (H5AC_dest_func_t)H5FA__cache_dblock_dest, - (H5AC_clear_func_t)H5FA__cache_dblock_clear, - (H5AC_notify_func_t)H5FA__cache_dblock_notify, - (H5AC_size_func_t)H5FA__cache_dblock_size, + H5AC_FARRAY_DBLOCK_ID, /* Metadata client ID */ + "Fixed Array Data Block", /* Metadata client name (for debugging) */ + H5FD_MEM_FARRAY_DBLOCK, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5FA__cache_dblock_get_load_size, /* 'get_load_size' callback */ + H5FA__cache_dblock_verify_chksum, /* 'verify_chksum' callback */ + H5FA__cache_dblock_deserialize, /* 'deserialize' callback */ + H5FA__cache_dblock_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5FA__cache_dblock_serialize, /* 'serialize' callback */ + H5FA__cache_dblock_notify, /* 'notify' callback */ + H5FA__cache_dblock_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + H5FA__cache_dblock_fsf_size, /* 'fsf_size' callback */ }}; /* H5FA data block page inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FARRAY_DBLK_PAGE[1] = {{ - H5AC_FARRAY_DBLK_PAGE_ID, - (H5AC_load_func_t)H5FA__cache_dblk_page_load, - (H5AC_flush_func_t)H5FA__cache_dblk_page_flush, - (H5AC_dest_func_t)H5FA__cache_dblk_page_dest, - (H5AC_clear_func_t)H5FA__cache_dblk_page_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5FA__cache_dblk_page_size, + H5AC_FARRAY_DBLK_PAGE_ID, /* Metadata client ID */ + "Fixed Array Data Block Page", /* Metadata client name (for debugging) */ + H5FD_MEM_FARRAY_DBLK_PAGE, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5FA__cache_dblk_page_get_load_size, /* 'get_load_size' callback */ + H5FA__cache_dblk_page_verify_chksum, /* 'verify_chksum' callback */ + H5FA__cache_dblk_page_deserialize, /* 'deserialize' callback */ + H5FA__cache_dblk_page_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5FA__cache_dblk_page_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5FA__cache_dblk_page_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -147,87 +183,142 @@ const H5AC_class_t H5AC_FARRAY_DBLK_PAGE[1] = {{ /*------------------------------------------------------------------------- - * Function: H5FA__cache_hdr_load + * Function: H5FA__cache_hdr_get_load_size * - * Purpose: Loads a fixed array header from the disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: Success: Pointer to a new fixed array - * Failure: NULL + * Return: Non-negative on success/Negative on failure * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 31, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -H5FA_hdr_t *, NULL, NULL, -H5FA__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5FA__cache_hdr_get_load_size(const void *_image, void *_udata, + size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) /* Local variables */ - H5FA_cls_id_t id; /* ID of fixed array class, as found in file */ - H5FA_hdr_t *hdr = NULL; /* Fixed array info */ - size_t size; /* Header size */ - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5FA_HDR_BUF_SIZE]; /* Buffer for header */ - uint8_t *buf; /* Pointer to header buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5FA_hdr_cache_ud_t *udata = (H5FA_hdr_cache_ud_t *)_udata; /* User data for callback */ /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(udata); + HDassert(udata->f); + HDassert(image_len); - /* Allocate space for the fixed array data structure */ - if(NULL == (hdr = H5FA__hdr_alloc(f))) - H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array shared header") + if(image == NULL) { + /* Set the image length size */ + *image_len = (size_t)H5FA_HEADER_SIZE_FILE(udata->f); + } else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } - /* Set the fixed array header's address */ - hdr->addr = addr; +END_FUNC(STATIC) /* end H5FA__cache_hdr_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5FA__cache_hdr_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5FA__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") + /* Check arguments */ + HDassert(image); - /* Compute the 'base' size of the fixed array header on disk */ - size = H5FA_HEADER_SIZE_HDR(hdr); + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); - /* Get a pointer to a buffer that's large enough for serialized header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") + if(stored_chksum != computed_chksum) + ret_value = FALSE; - /* Read and vaildate header from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_FARRAY_HDR, H5AC_FARRAY_HDR_ID, addr, size, size, buf) < 0) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for fixed array header") +END_FUNC(STATIC) /* end H5FA__cache_hdr_verify_chksum() */ - /* Get temporary pointer to serialized header */ - p = buf; + +/*------------------------------------------------------------------------- + * Function: H5FA__cache_hdr_deserialize + * + * Purpose: Loads a data structure from the disk. + * + * Return: Success: Pointer to a new Fixed array + * Failure: NULL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 12, 2013 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, ERR, +void *, NULL, NULL, +H5FA__cache_hdr_deserialize(const void *_image, size_t len, + void *_udata, hbool_t H5_ATTR_UNUSED *dirty)) + + /* Local variables */ + H5FA_cls_id_t id; /* ID of fixed array class, as found in file */ + H5FA_hdr_t *hdr = NULL; /* Fixed array info */ + H5FA_hdr_cache_ud_t *udata = (H5FA_hdr_cache_ud_t *)_udata; + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + + /* Check arguments */ + HDassert(udata); + HDassert(udata->f); + HDassert(H5F_addr_defined(udata->addr)); + + /* Allocate space for the fixed array data structure */ + if(NULL == (hdr = H5FA__hdr_alloc(udata->f))) + H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array shared header") + + /* Set the fixed array header's address */ + hdr->addr = udata->addr; /* Magic number */ - if(HDmemcmp(p, H5FA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5FA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) H5E_THROW(H5E_BADVALUE, "wrong fixed array header signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5FA_HDR_VERSION) + if(*image++ != H5FA_HDR_VERSION) H5E_THROW(H5E_VERSION, "wrong fixed array header version") /* Fixed array class */ - id = (H5FA_cls_id_t)*p++; + id = (H5FA_cls_id_t)*image++; if(id >= H5FA_NUM_CLS_ID) H5E_THROW(H5E_BADTYPE, "incorrect fixed array class") hdr->cparam.cls = H5FA_client_class_g[id]; /* General array creation/configuration information */ - hdr->cparam.raw_elmt_size = *p++; /* Element size in file (in bytes) */ - hdr->cparam.max_dblk_page_nelmts_bits = *p++; /* Log2(Max. # of elements in data block page) - - * i.e. # of bits needed to store max. # of - * elements in data block page. - */ + hdr->cparam.raw_elmt_size = *image++; /* Element size in file (in bytes) */ + hdr->cparam.max_dblk_page_nelmts_bits = *image++; /* Log2(Max. # of elements in data block page) - + i.e. # of bits needed to store max. # of + elements in data block page. */ /* Array statistics */ - H5F_DECODE_LENGTH(f, p, hdr->cparam.nelmts); /* Number of elements */ + H5F_DECODE_LENGTH(udata->f, image, hdr->cparam.nelmts); /* Number of elements */ /* Internal information */ - H5F_addr_decode(f, &p, &hdr->dblk_addr); /* Address of index block */ + H5F_addr_decode(udata->f, &image, &hdr->dblk_addr); /* Address of index block */ /* Check for data block */ if(H5F_addr_defined(hdr->dblk_addr)) { @@ -250,17 +341,20 @@ H5FA__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata)) /* Sanity check */ /* (allow for checksum not decoded yet) */ - HDassert((size_t)(p - buf) == (size - H5FA_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5FA_SIZEOF_CHKSUM)); - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - buf) == (size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == len); /* Finish initializing fixed array header */ - if(H5FA__hdr_init(hdr, udata) < 0) + if(H5FA__hdr_init(hdr, udata->ctx_udata) < 0) H5E_THROW(H5E_CANTINIT, "initialization failed for fixed array header") - HDassert(hdr->size == size); + HDassert(hdr->size == len); /* Set return value */ ret_value = hdr; @@ -268,521 +362,439 @@ H5FA__cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata)) CATCH /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") if(!ret_value) if(hdr && H5FA__hdr_dest(hdr) < 0) H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array header") -END_FUNC(STATIC) /* end H5FA__cache_hdr_load() */ +END_FUNC(STATIC) /* end H5FA__cache_hdr_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_hdr_flush + * Function: H5FA__cache_hdr_image_len * - * Purpose: Flushes a dirty fixed array header to disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: SUCCEED/FAIL + * Return: Non-negative on success/Negative on failure * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 12, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5FA__cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5FA_hdr_t *hdr, unsigned H5_ATTR_UNUSED * flags_ptr)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5FA__cache_hdr_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5FA_HDR_BUF_SIZE]; /* Buffer for header */ + /* Local variables */ + const H5FA_hdr_t *hdr = (const H5FA_hdr_t *)_thing; /* Pointer to the object */ - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(hdr); + HDassert(image_len); - if(hdr->cache_info.is_dirty) { - uint8_t *buf; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t size; /* Header size on disk */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the array header on disk */ - size = hdr->size; - - /* Get a pointer to a buffer that's large enough for serialized header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") + /* Set the image length size */ + *image_len = hdr->size; - /* Get temporary pointer to serialized header */ - p = buf; +END_FUNC(STATIC) /* end H5FA__cache_hdr_image_len() */ - /* Magic number */ - HDmemcpy(p, H5FA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5FA_HDR_VERSION; + +/*------------------------------------------------------------------------- + * Function: H5FA__cache_hdr_serialize + * + * Purpose: Flushes a dirty object to disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 12, 2013 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5FA__cache_hdr_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing)) - /* Fixed array type */ - *p++ = hdr->cparam.cls->id; + /* Local variables */ + H5FA_hdr_t *hdr = (H5FA_hdr_t *)_thing; /* Pointer to the fixed array header */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ - /* General array creation/configuration information */ - *p++ = hdr->cparam.raw_elmt_size; /* Element size in file (in bytes) */ - *p++ = hdr->cparam.max_dblk_page_nelmts_bits; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */ + /* check arguments */ + HDassert(f); + HDassert(image); + HDassert(hdr); - /* Array statistics */ - H5F_ENCODE_LENGTH(f, p, hdr->stats.nelmts); /* Number of elements for the fixed array */ + /* Magic number */ + HDmemcpy(image, H5FA_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Internal information */ - H5F_addr_encode(f, &p, hdr->dblk_addr); /* Address of fixed array data block */ + /* Version # */ + *image++ = H5FA_HDR_VERSION; - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); + /* Fixed array type */ + *image++ = hdr->cparam.cls->id; - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); + /* General array creation/configuration information */ + *image++ = hdr->cparam.raw_elmt_size; /* Element size in file (in bytes) */ + *image++ = hdr->cparam.max_dblk_page_nelmts_bits; /* Log2(Max. # of elements in data block page) - i.e. # of bits needed to store max. # of elements in data block page */ - /* Write the array header. */ - HDassert((size_t)(p - buf) == size); - if(H5F_block_write(f, H5FD_MEM_FARRAY_HDR, addr, size, dxpl_id, buf) < 0) - H5E_THROW(H5E_WRITEERROR, "unable to save fixed array header to disk") + /* Array statistics */ + H5F_ENCODE_LENGTH(f, image, hdr->stats.nelmts); /* Number of elements for the fixed array */ - hdr->cache_info.is_dirty = FALSE; - } /* end if */ + /* Internal information */ + H5F_addr_encode(f, &image, hdr->dblk_addr); /* Address of fixed array data block */ - if(destroy) - if(H5FA__cache_hdr_dest(f, hdr) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array header") + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); -CATCH + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= len); -END_FUNC(STATIC) /* end H5FA__cache_hdr_flush() */ +END_FUNC(STATIC) /* end H5FA__cache_hdr_serialize() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_hdr_dest + * Function: H5FA__cache_hdr_free_icr * - * Purpose: Destroys a fixed array header in memory. + * Purpose: Destroy/release an "in core representation" of a data + * structure * * Return: SUCCEED/FAIL * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 12, 2013 * *------------------------------------------------------------------------- */ /* ARGSUSED */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5FA__cache_hdr_dest(H5F_t *f, H5FA_hdr_t *hdr)) +H5FA__cache_hdr_free_icr(void *thing)) /* Check arguments */ - HDassert(f); - HDassert(hdr); - - /* Verify that header is clean */ - HDassert(hdr->cache_info.is_dirty == FALSE); - - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!hdr->cache_info.free_file_space_on_destroy || H5F_addr_defined(hdr->cache_info.addr)); - - /* Check for freeing file space for fixed array header */ - if(hdr->cache_info.free_file_space_on_destroy) { - /* Sanity check address */ - HDassert(H5F_addr_eq(hdr->addr, hdr->cache_info.addr)); + HDassert(thing); - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_FARRAY_HDR, H5AC_dxpl_id, hdr->cache_info.addr, (hsize_t)hdr->size) < 0) - H5E_THROW(H5E_CANTFREE, "unable to free fixed array header") - } /* end if */ - - /* Release the fixed array header */ - if(H5FA__hdr_dest(hdr) < 0) + /* Release the extensible array header */ + if(H5FA__hdr_dest((H5FA_hdr_t *)thing) < 0) H5E_THROW(H5E_CANTFREE, "can't free fixed array header") CATCH -END_FUNC(STATIC) /* end H5FA__cache_hdr_dest() */ +END_FUNC(STATIC) /* end H5FA__cache_hdr_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_hdr_clear + * Function: H5FA__cache_dblock_get_load_size * - * Purpose: Mark a fixed array header in memory as non-dirty. + * Purpose: Compute the size of the data structure on disk. * - * Return: SUCCEED/FAIL + * Return: Non-negative on success/Negative on failure * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 12, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5FA__cache_hdr_clear(H5F_t *f, H5FA_hdr_t *hdr, hbool_t destroy)) - - /* Sanity check */ - HDassert(hdr); - - /* Reset the dirty flag. */ - hdr->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5FA__cache_hdr_dest(f, hdr) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array header") +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5FA__cache_dblock_get_load_size(const void *_image, void *_udata, + size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) -CATCH + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5FA_dblock_cache_ud_t *udata = (H5FA_dblock_cache_ud_t *)_udata; /* User data */ + H5FA_dblock_t dblock; /* Fake data block for computing size */ + size_t dblk_page_nelmts; /* # of elements per data block page */ -END_FUNC(STATIC) /* end H5FA__cache_hdr_clear() */ + /* Check arguments */ + HDassert(udata); + HDassert(udata->hdr); + HDassert(image_len); + + if(image == NULL) { + + /* Set up fake data block for computing size on disk */ + /* (Note: extracted from H5FA__dblock_alloc) */ + HDmemset(&dblock, 0, sizeof(dblock)); + + /* Set up fake data block for computing size on disk + * + * need: dblock->hdr + * dblock->npages + * dblock->dblk_page_init_size + */ + + dblock.hdr = udata->hdr; + dblk_page_nelmts = (size_t)1 << udata->hdr->cparam.max_dblk_page_nelmts_bits; + if(udata->hdr->cparam.nelmts > dblk_page_nelmts) { + dblock.npages = (size_t)(((udata->hdr->cparam.nelmts + dblk_page_nelmts) - 1) / dblk_page_nelmts); + dblock.dblk_page_init_size = (dblock.npages + 7) / 8; + } /* end if */ + + /* Set the image length size */ + if(!dblock.npages) + *image_len = (size_t)H5FA_DBLOCK_SIZE(&dblock); + else + *image_len = (size_t)H5FA_DBLOCK_PREFIX_SIZE(&dblock); + } else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } + +END_FUNC(STATIC) /* end H5FA__cache_dblock_get_load_size() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_hdr_size + * Function: H5FA__cache_dblock_verify_chksum * - * Purpose: Compute the size in bytes of a fixed array header - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. * - * Return: SUCCEED/FAIL + * Return: Success: TRUE/FALSE + * Failure: Negative * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Vailin Choi; Aug 2015 * *------------------------------------------------------------------------- */ -/* ARGSUSED */ BEGIN_FUNC(STATIC, NOERR, -herr_t, SUCCEED, -, -H5FA__cache_hdr_size(const H5F_t H5_ATTR_UNUSED *f, const H5FA_hdr_t *hdr, - size_t *size_ptr)) +htri_t, TRUE, -, +H5FA__cache_dblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) - /* Sanity check */ - HDassert(f); - HDassert(hdr); - HDassert(size_ptr); + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); - /* Set size value */ - *size_ptr = hdr->size; + if(stored_chksum != computed_chksum) + ret_value = FALSE; -END_FUNC(STATIC) /* end H5FA__cache_hdr_size() */ +END_FUNC(STATIC) /* end H5FA__cache_dblock_verify_chksum() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_dblock_load + * Function: H5FA__cache_dblock_deserialize * - * Purpose: Loads a fixed array data block from the disk. + * Purpose: Loads a data structure from the disk. * - * Return: Success: Pointer to a new fixed array data block - * Failure: NULL + * Return: Success: Pointer to a new B-tree. + * Failure: NULL * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 14, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, -H5FA_dblock_t *, NULL, NULL, -H5FA__cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) +void *, NULL, NULL, +H5FA__cache_dblock_deserialize(const void *_image, size_t len, + void *_udata, hbool_t H5_ATTR_UNUSED *dirty)) /* Local variables */ H5FA_dblock_t *dblock = NULL; /* Data block info */ H5FA_dblock_cache_ud_t *udata = (H5FA_dblock_cache_ud_t *)_udata; /* User data for loading data block */ - size_t size; /* Data block size */ - H5WB_t *wb = NULL; /* Wrapped buffer for data block data */ - uint8_t dblock_buf[H5FA_DBLOCK_BUF_SIZE]; /* Buffer for data block */ - uint8_t *buf; /* Pointer to data block buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ haddr_t arr_addr; /* Address of array header in the file */ /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata && udata->hdr); + HDassert(udata); + HDassert(udata->hdr); /* Allocate the fixed array data block */ if(NULL == (dblock = H5FA__dblock_alloc(udata->hdr))) H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array data block") - /* Set the fixed array data block's information */ - dblock->addr = addr; - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(dblock_buf, sizeof(dblock_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the fixed array data block on disk */ - if(!dblock->npages) - size = (size_t)H5FA_DBLOCK_SIZE(dblock); - else - size = H5FA_DBLOCK_PREFIX_SIZE(dblock); + HDassert(((!dblock->npages) && (len == (size_t)H5FA_DBLOCK_SIZE(dblock))) + || (len == (size_t)H5FA_DBLOCK_PREFIX_SIZE(dblock))); - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Read and validate data block from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_FARRAY_DBLOCK, H5AC_FARRAY_DBLOCK_ID, addr, size, size, buf) < 0) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for fixed array data block") - - /* Get temporary pointer to serialized header */ - p = buf; + /* Set the fixed array data block's information */ + dblock->addr = udata->dblk_addr; /* Magic number */ - if(HDmemcmp(p, H5FA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5FA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) H5E_THROW(H5E_BADVALUE, "wrong fixed array data block signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5FA_DBLOCK_VERSION) + if(*image++ != H5FA_DBLOCK_VERSION) H5E_THROW(H5E_VERSION, "wrong fixed array data block version") /* Fixed array type */ - if(*p++ != (uint8_t)udata->hdr->cparam.cls->id) + if(*image++ != (uint8_t)udata->hdr->cparam.cls->id) H5E_THROW(H5E_BADTYPE, "incorrect fixed array class") /* Address of header for array that owns this block (just for file integrity checks) */ - H5F_addr_decode(f, &p, &arr_addr); + H5F_addr_decode(udata->hdr->f, &image, &arr_addr); if(H5F_addr_ne(arr_addr, udata->hdr->addr)) H5E_THROW(H5E_BADVALUE, "wrong fixed array header address") /* Page initialization flags */ if(dblock->npages > 0) { - HDmemcpy(dblock->dblk_page_init, p, dblock->dblk_page_init_size); - p += dblock->dblk_page_init_size; + HDmemcpy(dblock->dblk_page_init, image, dblock->dblk_page_init_size); + image += dblock->dblk_page_init_size; } /* end if */ /* Only decode elements if the data block is not paged */ if(!dblock->npages) { /* Decode elements in data block */ /* Convert from raw elements on disk into native elements in memory */ - if((udata->hdr->cparam.cls->decode)(p, dblock->elmts, (size_t)udata->hdr->stats.nelmts, udata->hdr->cb_ctx) < 0) + if((udata->hdr->cparam.cls->decode)(image, dblock->elmts, (size_t)udata->hdr->cparam.nelmts, udata->hdr->cb_ctx) < 0) H5E_THROW(H5E_CANTDECODE, "can't decode fixed array data elements") - p += (udata->hdr->stats.nelmts * udata->hdr->cparam.raw_elmt_size); + image += (udata->hdr->cparam.nelmts * udata->hdr->cparam.raw_elmt_size); } /* end if */ /* Sanity check */ /* (allow for checksum not decoded yet) */ - HDassert((size_t)(p - buf) == (size - H5FA_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5FA_SIZEOF_CHKSUM)); /* Set the data block's size */ dblock->size = H5FA_DBLOCK_SIZE(dblock); - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - buf) == (size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == len); /* Set return value */ ret_value = dblock; CATCH - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") if(!ret_value) if(dblock && H5FA__dblock_dest(dblock) < 0) H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block") -END_FUNC(STATIC) /* end H5FA__cache_dblock_load() */ +END_FUNC(STATIC) /* end H5FA__cache_dblock_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_dblock_flush + * Function: H5FA__cache_dblock_image_len * - * Purpose: Flushes a dirty fixed array data block to disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: SUCCEED/FAIL + * Return: Non-negative on success/Negative on failure * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 14, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5FA__cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5FA_dblock_t *dblock, unsigned H5_ATTR_UNUSED * flags_ptr)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5FA__cache_dblock_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) /* Local variables */ - H5WB_t *wb = NULL; /* Wrapped buffer for serializing data */ - uint8_t ser_buf[H5FA_DBLOCK_BUF_SIZE]; /* Serialization buffer */ + const H5FA_dblock_t *dblock = (const H5FA_dblock_t *)_thing; /* Pointer to the object */ - /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(dblock); - HDassert(dblock->hdr); - - if(dblock->cache_info.is_dirty) { - uint8_t *buf; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t size; /* Index block size on disk */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(ser_buf, sizeof(ser_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the data block on disk */ - if(!dblock->npages) - size = (size_t)dblock->size; - else - size = H5FA_DBLOCK_PREFIX_SIZE(dblock); - - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Get temporary pointer to serialized info */ - p = buf; - - /* Magic number */ - HDmemcpy(p, H5FA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5FA_DBLOCK_VERSION; - - /* Fixed array type */ - *p++ = dblock->hdr->cparam.cls->id; - - /* Address of array header for array which owns this block */ - H5F_addr_encode(f, &p, dblock->hdr->addr); - - /* Page init flags */ - if(dblock->npages > 0) { - /* Store the 'page init' bitmasks */ - HDmemcpy(p, dblock->dblk_page_init, dblock->dblk_page_init_size); - p += dblock->dblk_page_init_size; - } /* end if */ - - /* Only encode elements if the data block is not paged */ - if(!dblock->npages) { - /* Encode elements in data block */ - - /* Convert from native elements in memory into raw elements on disk */ - H5_CHECK_OVERFLOW(dblock->hdr->cparam.nelmts, /* From: */hsize_t, /* To: */size_t); - if((dblock->hdr->cparam.cls->encode)(p, dblock->elmts, (size_t)dblock->hdr->cparam.nelmts, dblock->hdr->cb_ctx) < 0) - H5E_THROW(H5E_CANTENCODE, "can't encode fixed array data elements") - p += (dblock->hdr->cparam.nelmts * dblock->hdr->cparam.raw_elmt_size); - } /* end if */ - - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); - - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); - - /* Write the data block */ - HDassert((size_t)(p - buf) == size); - if(H5F_block_write(f, H5FD_MEM_FARRAY_DBLOCK, addr, size, dxpl_id, buf) < 0) - H5E_THROW(H5E_WRITEERROR, "unable to save fixed array data block to disk") + HDassert(image_len); - dblock->cache_info.is_dirty = FALSE; - } /* end if */ - - if(destroy) - if(H5FA__cache_dblock_dest(f, dblock) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block") - -CATCH - - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") + /* Set the image length size */ + if(!dblock->npages) + *image_len = (size_t)dblock->size; + else + *image_len = H5FA_DBLOCK_PREFIX_SIZE(dblock); -END_FUNC(STATIC) /* end H5FA__cache_dblock_flush() */ +END_FUNC(STATIC) /* end H5FA__cache_dblock_image_len() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_dblock_dest + * Function: H5FA__cache_dblock_serialize * - * Purpose: Destroys a fixed array data block in memory. + * Purpose: Flushes a dirty object to disk. * - * Return: SUCCEED/FAIL + * Return: Non-negative on success/Negative on failure * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 14, 2013 * *------------------------------------------------------------------------- */ -/* ARGSUSED */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5FA__cache_dblock_dest(H5F_t *f, H5FA_dblock_t *dblock)) +H5FA__cache_dblock_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing)) - /* Sanity check */ + /* Local variables */ + H5FA_dblock_t *dblock = (H5FA_dblock_t *)_thing; /* Pointer to the object to serialize */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ HDassert(f); + HDassert(image); HDassert(dblock); + HDassert(dblock->hdr); - /* Verify that data block is clean */ - HDassert(dblock->cache_info.is_dirty == FALSE); + /* Magic number */ + HDmemcpy(image, H5FA_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!dblock->cache_info.free_file_space_on_destroy || H5F_addr_defined(dblock->cache_info.addr)); + /* Version # */ + *image++ = H5FA_DBLOCK_VERSION; - /* Check for freeing file space for fixed array data block */ - if(dblock->cache_info.free_file_space_on_destroy) { - /* Sanity check address */ - HDassert(H5F_addr_eq(dblock->addr, dblock->cache_info.addr)); + /* Fixed array type */ + *image++ = dblock->hdr->cparam.cls->id; - /* Release the space on disk */ - /* (Includes space for pages!) */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_FARRAY_DBLOCK, H5AC_dxpl_id, dblock->cache_info.addr, (hsize_t)dblock->size) < 0) - H5E_THROW(H5E_CANTFREE, "unable to free fixed array data block") + /* Address of array header for array which owns this block */ + H5F_addr_encode(f, &image, dblock->hdr->addr); + + /* Page init flags */ + if(dblock->npages > 0) { + /* Store the 'page init' bitmasks */ + HDmemcpy(image, dblock->dblk_page_init, dblock->dblk_page_init_size); + image += dblock->dblk_page_init_size; } /* end if */ - /* Release the data block */ - if(H5FA__dblock_dest(dblock) < 0) - H5E_THROW(H5E_CANTFREE, "can't free fixed array data block") + /* Only encode elements if the data block is not paged */ + if(!dblock->npages) { + /* Encode elements in data block */ -CATCH + /* Convert from native elements in memory into raw elements on disk */ + H5_CHECK_OVERFLOW(dblock->hdr->cparam.nelmts, /* From: */hsize_t, /* To: */size_t); + if((dblock->hdr->cparam.cls->encode)(image, dblock->elmts, (size_t)dblock->hdr->cparam.nelmts, dblock->hdr->cb_ctx) < 0) + H5E_THROW(H5E_CANTENCODE, "can't encode fixed array data elements") + image += (dblock->hdr->cparam.nelmts * dblock->hdr->cparam.raw_elmt_size); + } /* end if */ -END_FUNC(STATIC) /* end H5FA__cache_dblock_dest() */ + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); - -/*------------------------------------------------------------------------- - * Function: H5FA__cache_dblock_clear - * - * Purpose: Mark a fixed array data block in memory as non-dirty. - * - * Return: SUCCEED/FAIL - * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 - * - *------------------------------------------------------------------------- - */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5FA__cache_dblock_clear(H5F_t *f, H5FA_dblock_t *dblock, hbool_t destroy)) + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); /* Sanity check */ - HDassert(dblock); - - /* Reset the dirty flag */ - dblock->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5FA__cache_dblock_dest(f, dblock) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block") + HDassert((size_t)(image - (uint8_t *)_image) <= len); CATCH -END_FUNC(STATIC) /* end H5FA__cache_dblock_clear() */ +END_FUNC(STATIC) /* end H5FA__cache_dblock_serialize() */ + /*------------------------------------------------------------------------- @@ -799,7 +811,10 @@ END_FUNC(STATIC) /* end H5FA__cache_dblock_clear() */ */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5FA__cache_dblock_notify(H5AC_notify_action_t action, H5FA_dblock_t *dblock)) +H5FA__cache_dblock_notify(H5AC_notify_action_t action, void *_thing)) + + /* Local variables */ + H5FA_dblock_t *dblock = (H5FA_dblock_t *)_thing; /* Sanity check */ HDassert(dblock); @@ -809,13 +824,21 @@ H5FA__cache_dblock_notify(H5AC_notify_action_t action, H5FA_dblock_t *dblock)) /* Determine which action to take */ switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: - /* Create flush dependency on extensible array header */ + case H5AC_NOTIFY_ACTION_AFTER_LOAD: + /* Create flush dependency on parent */ if(H5FA__create_flush_depend((H5AC_info_t *)dblock->hdr, (H5AC_info_t *)dblock) < 0) H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block and header, address = %llu", (unsigned long long)dblock->addr) break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ + /* Destroy flush dependency on parent */ + if(H5FA__destroy_flush_depend((H5AC_info_t *)dblock->hdr, (H5AC_info_t *)dblock) < 0) + H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency") + break; default: @@ -831,115 +854,220 @@ CATCH END_FUNC(STATIC) /* end H5FA__cache_dblock_notify() */ + /*------------------------------------------------------------------------- - * Function: H5FA__cache_dblock_size + * Function: H5FA__cache_dblock_free_icr * - * Purpose: Compute the size in bytes of a fixed array data block - * on disk, and return it in *size_ptr. + * Purpose: Destroy/release an "in core representation" of a data + * structure * - * Return: SUCCEED (Can't fail) + * Return: SUCCEED/FAIL * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 14, 2013 * *------------------------------------------------------------------------- */ /* ARGSUSED */ +BEGIN_FUNC(STATIC, ERR, +herr_t, SUCCEED, FAIL, +H5FA__cache_dblock_free_icr(void *_thing)) + + H5FA_dblock_t *dblock = (H5FA_dblock_t *)_thing; /* Pointer to the object */ + + /* Check arguments */ + HDassert(dblock); + + /* Release the fixed array data block */ + if(H5FA__dblock_dest(dblock) < 0) + H5E_THROW(H5E_CANTFREE, "can't free fixed array data block") + +CATCH + +END_FUNC(STATIC) /* end H5FA__cache_dblock_free_icr() */ + + +/*------------------------------------------------------------------------- + * Function: H5FA__cache_dblock_fsf_size + * + * Purpose: Tell the metadata cache the actual amount of file space + * to free when a dblock entry is destroyed with the free + * file space block set. + * + * This function is needed when the data block is paged, as + * the datablock header and all its pages are allocted as a + * single contiguous chunk of file space, and must be + * deallocated the same way. + * + * The size of the chunk of memory in which the dblock + * header and all its pages is stored in the size field, + * so we simply pass that value back to the cache. + * + * If the datablock is not paged, then the size field of + * the cache_info contains the correct size. However this + * value will be the same as the size field, so we return + * the contents of the size field to the cache in this case + * as well. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 12/5/14 + * + *------------------------------------------------------------------------- + */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5FA__cache_dblock_size(const H5F_t H5_ATTR_UNUSED *f, const H5FA_dblock_t *dblock, - size_t *size_ptr)) +H5FA__cache_dblock_fsf_size(const void *_thing, size_t *fsf_size)) - /* Sanity check */ - HDassert(f); + const H5FA_dblock_t *dblock = (const H5FA_dblock_t *)_thing; /* Pointer to the object */ + + /* Check arguments */ HDassert(dblock); - HDassert(size_ptr); + HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FARRAY_DBLOCK); + HDassert(fsf_size); - /* Set size value */ - if(!dblock->npages) - *size_ptr = (size_t)dblock->size; - else - *size_ptr = H5FA_DBLOCK_PREFIX_SIZE(dblock); + *fsf_size = dblock->size; -END_FUNC(STATIC) /* end H5FA__cache_dblock_size() */ +END_FUNC(STATIC) /* end H5FA__cache_dblock_fsf_size() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_dblk_page_load + * Function: H5FA__cache_dblk_page_get_load_size * - * Purpose: Loads a fixed array data block page from the disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: Success: Pointer to a new fixed array data block page - * Failure: NULL + * Return: Non-negative on success/Negative on failure * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 14, 2013 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5FA__cache_dblk_page_get_load_size(const void *_image, void *_udata, + size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5FA_dblk_page_cache_ud_t *udata = (H5FA_dblk_page_cache_ud_t *)_udata; /* User data */ + + /* Check arguments */ + HDassert(udata); + HDassert(udata->hdr); + HDassert(udata->nelmts > 0); + HDassert(image_len); + + if(image == NULL) + *image_len = (size_t)H5FA_DBLK_PAGE_SIZE(udata->hdr, udata->nelmts); + else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } + +END_FUNC(STATIC) /* end H5FA__cache_dblk_page_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5FA__cache_dblk_page_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5FA__cache_dblk_page_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5FA__cache_dblk_page_verify_chksum() */ + + +/*------------------------------------------------------------------------- + * Function: H5FA__cache_dblk_page_deserialize + * + * Purpose: Loads a data structure from the disk. + * + * Return: Success: Pointer to a new B-tree. + * Failure: NULL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 14, 2013 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, -H5FA_dblk_page_t *, NULL, NULL, -H5FA__cache_dblk_page_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) +void *, NULL, NULL, +H5FA__cache_dblk_page_deserialize(const void *_image, size_t len, + void *_udata, hbool_t H5_ATTR_UNUSED *dirty)) /* Local variables */ H5FA_dblk_page_t *dblk_page = NULL; /* Data block page info */ H5FA_dblk_page_cache_ud_t *udata = (H5FA_dblk_page_cache_ud_t *)_udata; /* User data for loading data block page */ - size_t size; /* Data block page size */ - H5WB_t *wb = NULL; /* Wrapped buffer for data block page data */ - uint8_t dblk_page_buf[H5FA_DBLK_PAGE_BUF_SIZE]; /* Buffer for data block page */ - uint8_t *buf; /* Pointer to data block page buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata && udata->hdr && udata->nelmts > 0); + HDassert(udata); + HDassert(udata->hdr); + HDassert(udata->nelmts > 0); + HDassert(H5F_addr_defined(udata->dblk_page_addr)); /* Allocate the fixed array data block page */ if(NULL == (dblk_page = H5FA__dblk_page_alloc(udata->hdr, udata->nelmts))) H5E_THROW(H5E_CANTALLOC, "memory allocation failed for fixed array data block page") /* Set the fixed array data block's information */ - dblk_page->addr = addr; - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(dblk_page_buf, sizeof(dblk_page_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the fixed array data block page on disk */ - size = H5FA_DBLK_PAGE_SIZE(udata->hdr, udata->nelmts); - - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Read and validate data block page from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_FARRAY_DBLK_PAGE, H5AC_FARRAY_DBLK_PAGE_ID, addr, size, size, buf) < 0) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for fixed array data block page") - - /* Get temporary pointer to serialized header */ - p = buf; + dblk_page->addr = udata->dblk_page_addr; /* Internal information */ /* Decode elements in data block page */ /* Convert from raw elements on disk into native elements in memory */ - if((udata->hdr->cparam.cls->decode)(p, dblk_page->elmts, udata->nelmts, udata->hdr->cb_ctx) < 0) + if((udata->hdr->cparam.cls->decode)(image, dblk_page->elmts, udata->nelmts, udata->hdr->cb_ctx) < 0) H5E_THROW(H5E_CANTDECODE, "can't decode fixed array data elements") - p += (udata->nelmts * udata->hdr->cparam.raw_elmt_size); + image += (udata->nelmts * udata->hdr->cparam.raw_elmt_size); /* Sanity check */ /* (allow for checksum not decoded yet) */ - HDassert((size_t)(p - buf) == (size - H5FA_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5FA_SIZEOF_CHKSUM)); /* Set the data block page's size */ - dblk_page->size = size; + dblk_page->size = len; - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - buf) == (dblk_page->size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == dblk_page->size); /* Set return value */ ret_value = dblk_page; @@ -947,191 +1075,120 @@ H5FA__cache_dblk_page_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) CATCH /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") if(!ret_value) if(dblk_page && H5FA__dblk_page_dest(dblk_page) < 0) H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block page") -END_FUNC(STATIC) /* end H5FA__cache_dblk_page_load() */ +END_FUNC(STATIC) /* end H5FA__cache_dblk_page_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_dblk_page_flush + * Function: H5FA__cache_dblk_page_image_len * - * Purpose: Flushes a dirty fixed array data block page to disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: SUCCEED/FAIL + * Return: Non-negative on success/Negative on failure * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 14, 2013 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5FA__cache_dblk_page_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5FA_dblk_page_t *dblk_page, unsigned H5_ATTR_UNUSED * flags_ptr)) +BEGIN_FUNC(STATIC, NOERR, +herr_t, SUCCEED, -, +H5FA__cache_dblk_page_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr)) /* Local variables */ - H5WB_t *wb = NULL; /* Wrapped buffer for serializing data */ - uint8_t ser_buf[H5FA_DBLK_PAGE_BUF_SIZE]; /* Serialization buffer */ + const H5FA_dblk_page_t *dblk_page = (const H5FA_dblk_page_t *)_thing; /* Pointer to the object */ - /* Sanity check */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(dblk_page); - HDassert(dblk_page->hdr); - - if(dblk_page->cache_info.is_dirty) { - uint8_t *buf; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t size; /* Index block size on disk */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - - /* Wrap the local buffer for serialized info */ - if(NULL == (wb = H5WB_wrap(ser_buf, sizeof(ser_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer") - - /* Compute the size of the data block on disk */ - size = dblk_page->size; - - /* Get a pointer to a buffer that's large enough for serialized info */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - H5E_THROW(H5E_CANTGET, "can't get actual buffer") - - /* Get temporary pointer to serialized info */ - p = buf; - - /* Internal information */ - - /* Encode elements in data block page */ - - /* Convert from native elements in memory into raw elements on disk */ - if((dblk_page->hdr->cparam.cls->encode)(p, dblk_page->elmts, dblk_page->nelmts, dblk_page->hdr->cb_ctx) < 0) - H5E_THROW(H5E_CANTENCODE, "can't encode fixed array data elements") - p += (dblk_page->nelmts * dblk_page->hdr->cparam.raw_elmt_size); - - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); - - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); - - /* Write the data block */ - HDassert((size_t)(p - buf) == size); - if(H5F_block_write(f, H5FD_MEM_FARRAY_DBLK_PAGE, addr, size, dxpl_id, buf) < 0) - H5E_THROW(H5E_WRITEERROR, "unable to save fixed array data block page to disk") - - dblk_page->cache_info.is_dirty = FALSE; - } /* end if */ + HDassert(image_len); - if(destroy) - if(H5FA__cache_dblk_page_dest(f, dblk_page) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block page") - -CATCH + /* Set the image length size */ + *image_len = dblk_page->size; - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer") - -END_FUNC(STATIC) /* end H5FA__cache_dblk_page_flush() */ +END_FUNC(STATIC) /* end H5FA__cache_dblk_page_image_len() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_dblk_page_dest + * Function: H5FA__cache_dblk_page_serialize * - * Purpose: Destroys a fixed array data block page in memory. + * Purpose: Flushes a dirty object to disk. * - * Note: Does _not_ free the space for the page on disk, that is - * handled through the data block that "owns" the page. - * - * Return: SUCCEED/FAIL - * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 14, 2013 * *------------------------------------------------------------------------- */ /* ARGSUSED */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5FA__cache_dblk_page_dest(H5F_t H5_ATTR_UNUSED *f, H5FA_dblk_page_t *dblk_page)) +H5FA__cache_dblk_page_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing)) + + /* Local variables */ + H5FA_dblk_page_t *dblk_page = (H5FA_dblk_page_t *)_thing; /* Pointer to the object to serialize */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ /* Sanity check */ HDassert(f); + HDassert(image); HDassert(dblk_page); + HDassert(dblk_page->hdr); - /* Verify that data block page is clean */ - HDassert(dblk_page->cache_info.is_dirty == FALSE); + /* Internal information */ - /* Release the data block page */ - if(H5FA__dblk_page_dest(dblk_page) < 0) - H5E_THROW(H5E_CANTFREE, "can't free fixed array data block page") + /* Encode elements in data block page */ -CATCH + /* Convert from native elements in memory into raw elements on disk */ + if((dblk_page->hdr->cparam.cls->encode)(image, dblk_page->elmts, dblk_page->nelmts, dblk_page->hdr->cb_ctx) < 0) + H5E_THROW(H5E_CANTENCODE, "can't encode fixed array data elements") + image += (dblk_page->nelmts * dblk_page->hdr->cparam.raw_elmt_size); -END_FUNC(STATIC) /* end H5FA__cache_dblk_page_dest() */ + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); - -/*------------------------------------------------------------------------- - * Function: H5FA__cache_dblk_page_clear - * - * Purpose: Mark a fixed array data block page in memory as non-dirty. - * - * Return: SUCCEED/FAIL - * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 - * - *------------------------------------------------------------------------- - */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5FA__cache_dblk_page_clear(H5F_t *f, H5FA_dblk_page_t *dblk_page, hbool_t destroy)) + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); /* Sanity check */ - HDassert(dblk_page); - - /* Reset the dirty flag */ - dblk_page->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5FA__cache_dblk_page_dest(f, dblk_page) < 0) - H5E_THROW(H5E_CANTFREE, "unable to destroy fixed array data block page") + HDassert((size_t)(image - (uint8_t *)_image) <= len); CATCH -END_FUNC(STATIC) /* end H5FA__cache_dblk_page_clear() */ +END_FUNC(STATIC) /* end H5FA__cache_dblk_page_serialize() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_dblk_page_size + * Function: H5FA__cache_dblk_page_free_icr * - * Purpose: Compute the size in bytes of a fixed array data block page - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Destroy/release an "in core representation" of a data + * structure * - * Return: SUCCEED (Can't fail) + * Return: Non-negative on success/Negative on failure * - * Programmer: Vailin Choi - * Thursday, April 30, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 14, 2013 * *------------------------------------------------------------------------- */ -/* ARGSUSED */ -BEGIN_FUNC(STATIC, NOERR, -herr_t, SUCCEED, -, -H5FA__cache_dblk_page_size(const H5F_t H5_ATTR_UNUSED *f, const H5FA_dblk_page_t *dblk_page, - size_t *size_ptr)) +BEGIN_FUNC(STATIC, ERR, +herr_t, SUCCEED, FAIL, +H5FA__cache_dblk_page_free_icr(void *thing)) - /* Sanity check */ - HDassert(f); - HDassert(dblk_page); - HDassert(size_ptr); + /* Check arguments */ + HDassert(thing); - /* Set size value */ - *size_ptr = dblk_page->size; + /* Release the fixed array data block page */ + if(H5FA__dblk_page_dest((H5FA_dblk_page_t *)thing) < 0) + H5E_THROW(H5E_CANTFREE, "can't free fixed array data block page") + +CATCH -END_FUNC(STATIC) /* end H5FA__cache_dblk_page_size() */ +END_FUNC(STATIC) /* end H5FA__cache_dblk_page_free_icr() */ diff --git a/src/H5FAdbg.c b/src/H5FAdbg.c index 281efdd..1d1e569 100644 --- a/src/H5FAdbg.c +++ b/src/H5FAdbg.c @@ -117,7 +117,7 @@ H5FA__hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, } /* end if */ /* Load the fixed array header */ - if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, addr, dbg_ctx, H5AC_READ))) + if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, addr, dbg_ctx, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load fixed array header") /* Print opening message */ @@ -198,11 +198,11 @@ H5FA__dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int inde } /* end if */ /* Load the fixed array header */ - if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC_READ))) + if(NULL == (hdr = H5FA__hdr_protect(f, dxpl_id, hdr_addr, dbg_ctx, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load fixed array header") /* Protect data block */ - if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, addr, H5AC_READ))) + if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, addr, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block, address = %llu", (unsigned long long)addr) /* Print opening message */ @@ -246,8 +246,8 @@ H5FA__dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int inde if(((page_idx + 1) == dblock->npages) && (nelmts_left = hdr->cparam.nelmts % dblock->dblk_page_nelmts)) dblk_page_nelmts = (size_t)nelmts_left; - if(NULL == (dblk_page = H5FA__dblk_page_protect(hdr, dxpl_id, dblk_page_addr, dblk_page_nelmts, H5AC_READ))) - H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block page, address = %llu", (unsigned long long)dblk_page_addr) + if(NULL == (dblk_page = H5FA__dblk_page_protect(hdr, dxpl_id, dblk_page_addr, dblk_page_nelmts, H5AC__READ_ONLY_FLAG))) + H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block page, address = %llu", (unsigned long long)dblk_page_addr) HDfprintf(stream, "%*sElements in page %Zu:\n", indent, "", page_idx); for(u = 0; u < dblk_page_nelmts; u++) { diff --git a/src/H5FAdblkpage.c b/src/H5FAdblkpage.c index aaedb96..4337504 100644 --- a/src/H5FAdblkpage.c +++ b/src/H5FAdblkpage.c @@ -207,7 +207,7 @@ END_FUNC(PKG) /* end H5FA__dblk_page_create() */ BEGIN_FUNC(PKG, ERR, H5FA_dblk_page_t *, NULL, NULL, H5FA__dblk_page_protect(H5FA_hdr_t *hdr, hid_t dxpl_id, haddr_t dblk_page_addr, - size_t dblk_page_nelmts, H5AC_protect_t rw)) + size_t dblk_page_nelmts, unsigned flags)) /* Local variables */ H5FA_dblk_page_cache_ud_t udata; /* Information needed for loading data block page */ @@ -220,12 +220,16 @@ HDfprintf(stderr, "%s: Called\n", FUNC); HDassert(hdr); HDassert(H5F_addr_defined(dblk_page_addr)); + /* only the H5AC__READ_ONLY_FLAG is permitted */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Set up user data */ udata.hdr = hdr; udata.nelmts = dblk_page_nelmts; + udata.dblk_page_addr = dblk_page_addr; /* Protect the data block page */ - if(NULL == (ret_value = (H5FA_dblk_page_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FARRAY_DBLK_PAGE, dblk_page_addr, &udata, rw))) + if(NULL == (ret_value = (H5FA_dblk_page_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FARRAY_DBLK_PAGE, dblk_page_addr, &udata, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block page, address = %llu", (unsigned long long)dblk_page_addr) CATCH diff --git a/src/H5FAdblock.c b/src/H5FAdblock.c index 73838a1..9336a85 100644 --- a/src/H5FAdblock.c +++ b/src/H5FAdblock.c @@ -263,7 +263,7 @@ END_FUNC(PKG) /* end H5FA__dblock_create() */ BEGIN_FUNC(PKG, ERR, H5FA_dblock_t *, NULL, NULL, H5FA__dblock_protect(H5FA_hdr_t *hdr, hid_t dxpl_id, haddr_t dblk_addr, - H5AC_protect_t rw)) + unsigned flags)) /* Local variables */ H5FA_dblock_cache_ud_t udata; /* Information needed for loading data block */ @@ -276,11 +276,15 @@ HDfprintf(stderr, "%s: Called\n", FUNC); HDassert(hdr); HDassert(H5F_addr_defined(dblk_addr)); + /* only the H5AC__READ_ONLY_FLAG flag is permitted */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Set up user data */ udata.hdr = hdr; + udata.dblk_addr = dblk_addr; /* Protect the data block */ - if(NULL == (ret_value = (H5FA_dblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FARRAY_DBLOCK, dblk_addr, &udata, rw))) + if(NULL == (ret_value = (H5FA_dblock_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FARRAY_DBLOCK, dblk_addr, &udata, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block, address = %llu", (unsigned long long)dblk_addr) CATCH @@ -350,7 +354,7 @@ HDfprintf(stderr, "%s: Called\n", FUNC); HDassert(H5F_addr_defined(dblk_addr)); /* Protect data block */ - if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, dblk_addr, H5AC_WRITE))) + if(NULL == (dblock = H5FA__dblock_protect(hdr, dxpl_id, dblk_addr, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array data block, address = %llu", (unsigned long long)dblk_addr) /* Check if data block is paged */ diff --git a/src/H5FAhdr.c b/src/H5FAhdr.c index 2827fd7..79fe72a 100644 --- a/src/H5FAhdr.c +++ b/src/H5FAhdr.c @@ -409,16 +409,25 @@ END_FUNC(PKG) /* end H5FA__hdr_modified() */ BEGIN_FUNC(PKG, ERR, H5FA_hdr_t *, NULL, NULL, H5FA__hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr, void *ctx_udata, - H5AC_protect_t rw)) + unsigned flags)) /* Local variables */ + H5FA_hdr_cache_ud_t udata; /* User data for cache callbacks */ /* Sanity check */ HDassert(f); HDassert(H5F_addr_defined(fa_addr)); + /* only the H5AC__READ_ONLY_FLAG is permitted */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + + /* Set up user data for cache callbacks */ + udata.f = f; + udata.addr = fa_addr; + udata.ctx_udata = ctx_udata; + /* Protect the header */ - if(NULL == (ret_value = (H5FA_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_FARRAY_HDR, fa_addr, ctx_udata, rw))) + if(NULL == (ret_value = (H5FA_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_FARRAY_HDR, fa_addr, &udata, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to protect fixed array header, address = %llu", (unsigned long long)fa_addr) CATCH diff --git a/src/H5FApkg.h b/src/H5FApkg.h index e57b23a..77276cf 100644 --- a/src/H5FApkg.h +++ b/src/H5FApkg.h @@ -207,15 +207,24 @@ struct H5FA_t { /* Metadata cache callback user data types */ +/* Info needed for loading header */ +typedef struct H5FA_hdr_cache_ud_t { + H5F_t *f; /* Pointer to file for fixed array */ + haddr_t addr; /* Address of header on disk */ + void *ctx_udata; /* User context for class */ +} H5FA_hdr_cache_ud_t; + /* Info needed for loading data block */ typedef struct H5FA_dblock_cache_ud_t { H5FA_hdr_t *hdr; /* Shared fixed array information */ + haddr_t dblk_addr; /* Address of data block on disk */ } H5FA_dblock_cache_ud_t; /* Info needed for loading data block page */ typedef struct H5FA_dblk_page_cache_ud_t { H5FA_hdr_t *hdr; /* Shared fixed array information */ size_t nelmts; /* Number of elements in data block page */ + haddr_t dblk_page_addr; /* Address of data block page on disk */ } H5FA_dblk_page_cache_ud_t; @@ -261,7 +270,7 @@ H5_DLL herr_t H5FA__hdr_fuse_incr(H5FA_hdr_t *hdr); H5_DLL size_t H5FA__hdr_fuse_decr(H5FA_hdr_t *hdr); H5_DLL herr_t H5FA__hdr_modified(H5FA_hdr_t *hdr); H5_DLL H5FA_hdr_t *H5FA__hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t fa_addr, - void *ctx_udata, H5AC_protect_t rw); + void *ctx_udata, unsigned flags); H5_DLL herr_t H5FA__hdr_unprotect(H5FA_hdr_t *hdr, hid_t dxpl_id, unsigned cache_flags); H5_DLL herr_t H5FA__hdr_delete(H5FA_hdr_t *hdr, hid_t dxpl_id); H5_DLL herr_t H5FA__hdr_dest(H5FA_hdr_t *hdr); @@ -271,7 +280,7 @@ H5_DLL H5FA_dblock_t *H5FA__dblock_alloc(H5FA_hdr_t *hdr); H5_DLL haddr_t H5FA__dblock_create(H5FA_hdr_t *hdr, hid_t dxpl_id, hbool_t *hdr_dirty); H5_DLL unsigned H5FA__dblock_sblk_idx(const H5FA_hdr_t *hdr, hsize_t idx); H5_DLL H5FA_dblock_t *H5FA__dblock_protect(H5FA_hdr_t *hdr, hid_t dxpl_id, - haddr_t dblk_addr, H5AC_protect_t rw); + haddr_t dblk_addr, unsigned flags); H5_DLL herr_t H5FA__dblock_unprotect(H5FA_dblock_t *dblock, hid_t dxpl_id, unsigned cache_flags); H5_DLL herr_t H5FA__dblock_delete(H5FA_hdr_t *hdr, hid_t dxpl_id, @@ -283,7 +292,7 @@ H5_DLL herr_t H5FA__dblk_page_create(H5FA_hdr_t *hdr, hid_t dxpl_id, haddr_t addr, size_t nelmts); H5_DLL H5FA_dblk_page_t *H5FA__dblk_page_alloc(H5FA_hdr_t *hdr, size_t nelmts); H5_DLL H5FA_dblk_page_t *H5FA__dblk_page_protect(H5FA_hdr_t *hdr, hid_t dxpl_id, - haddr_t dblk_page_addr, size_t dblk_page_nelmts, H5AC_protect_t rw); + haddr_t dblk_page_addr, size_t dblk_page_nelmts, unsigned flags); H5_DLL herr_t H5FA__dblk_page_unprotect(H5FA_dblk_page_t *dblk_page, hid_t dxpl_id, unsigned cache_flags); H5_DLL herr_t H5FA__dblk_page_dest(H5FA_dblk_page_t *dblk_page); diff --git a/src/H5FDfamily.c b/src/H5FDfamily.c index 51a1b67..0ead309 100644 --- a/src/H5FDfamily.c +++ b/src/H5FDfamily.c @@ -907,7 +907,7 @@ H5FD_family_query(const H5FD_t * _file, unsigned long *flags /* out */) /* Check for flags that are set by h5repart */ if(file && file->repart_members) - *flags |= H5FD_FEAT_DIRTY_SBLK_LOAD; /* Mark the superblock dirty when it is loaded (so the family member sizes are rewritten) */ + *flags |= H5FD_FEAT_DIRTY_DRVRINFO_LOAD; /* Mark the superblock dirty when it is loaded (so the family member sizes are rewritten) */ } /* end if */ FUNC_LEAVE_NOAPI(SUCCEED) diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h index 92df63f..cabca06 100644 --- a/src/H5FDpublic.h +++ b/src/H5FDpublic.h @@ -198,12 +198,12 @@ typedef enum H5F_mem_t H5FD_mem_t; */ #define H5FD_FEAT_IGNORE_DRVRINFO 0x00000020 /* - * Defining H5FD_FEAT_DIRTY_SBLK_LOAD for a VFL driver means that - * the library will mark the superblock dirty when the file is opened + * Defining the H5FD_FEAT_DIRTY_DRVRINFO_LOAD for a VFL driver means that + * the library will mark the driver info dirty when the file is opened * R/W. This will cause the driver info to be re-encoded when the file * is flushed/closed. */ -#define H5FD_FEAT_DIRTY_SBLK_LOAD 0x00000040 +#define H5FD_FEAT_DIRTY_DRVRINFO_LOAD 0x00000040 /* * Defining H5FD_FEAT_POSIX_COMPAT_HANDLE for a VFL driver means that * the handle for the VFD (returned with the 'get_handle' callback) is @@ -206,7 +206,7 @@ HDfprintf(stderr, "%s: Opening free space manager, fs_addr = %a, nclasses = %Zu\ cache_udata.addr = fs_addr; /* Protect the free space header */ - if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC_READ))) + if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, NULL, "unable to load free space header") #ifdef H5FS_DEBUG HDfprintf(stderr, "%s: fspace->sect_addr = %a\n", FUNC, fspace->sect_addr); @@ -317,7 +317,7 @@ HDfprintf(stderr, "%s: Deleting free space manager, fs_addr = %a\n", FUNC, fs_ad #endif /* H5FS_DEBUG */ /* Protect the free space header */ - if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC_WRITE))) + if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space header") /* Sanity check */ @@ -349,8 +349,19 @@ HDfprintf(stderr, "%s: Expunging free space section info from cache\n", FUNC); #endif /* H5FS_DEBUG */ /* Evict the free space section info from the metadata cache */ /* (Free file space) */ - if(H5AC_expunge_entry(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, H5AC__FREE_FILE_SPACE_FLAG) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "unable to remove free space section info from cache") + { + unsigned cache_flags = H5AC__NO_FLAGS_SET; + + /* if the indirect block is in real file space, tell + * the cache to free its file space. + */ + if (!H5F_IS_TMP_ADDR(f, fspace->sect_addr)) + cache_flags |= H5AC__FREE_FILE_SPACE_FLAG; + + if(H5AC_expunge_entry(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, cache_flags) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "unable to remove free space section info from cache") + } + #ifdef H5FS_DEBUG HDfprintf(stderr, "%s: Done expunging free space section info from cache\n", FUNC); #endif /* H5FS_DEBUG */ @@ -923,8 +934,8 @@ H5FS_free(H5F_t *f, H5FS_t *fspace, hid_t dxpl_id) cache_udata.f = f; cache_udata.dxpl_id = dxpl_id; cache_udata.fspace = fspace; - if(NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, &cache_udata, H5AC_READ))) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space section info") + if(NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, &cache_udata, H5AC__READ_ONLY_FLAG))) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space section info") /* Unload and release ownership of the free-space manager section info */ if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, cache_flags) < 0) @@ -964,8 +975,8 @@ H5FS_free(H5F_t *f, H5FS_t *fspace, hid_t dxpl_id) cache_udata.nclasses = 0; cache_udata.classes = NULL; cache_udata.cls_init_udata = NULL; - if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fspace->addr, &cache_udata, H5AC_READ))) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space section info") + if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fspace->addr, &cache_udata, H5AC__READ_ONLY_FLAG))) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space section info") /* Unpin the free-space manager header */ if(H5AC_unpin_entry(fspace) < 0) diff --git a/src/H5FScache.c b/src/H5FScache.c index f68bf0f..93d7ed3 100644 --- a/src/H5FScache.c +++ b/src/H5FScache.c @@ -49,9 +49,6 @@ #define H5FS_HDR_VERSION 0 /* Header */ #define H5FS_SINFO_VERSION 0 /* Serialized sections */ -/* Size of stack buffer for serialized headers */ -#define H5FS_HDR_BUF_SIZE 256 - /******************/ /* Local Typedefs */ @@ -60,7 +57,7 @@ /* User data for skip list iterator callback for iterating over section size nodes when syncing */ typedef struct { H5FS_sinfo_t *sinfo; /* Free space section info */ - uint8_t **p; /* Pointer to address of buffer pointer to serialize with */ + uint8_t **image; /* Pointer to address of buffer pointer to serialize with */ unsigned sect_cnt_size; /* # of bytes to encode section size counts in */ } H5FS_iter_ud_t; @@ -75,22 +72,42 @@ typedef struct { /********************/ /* Section info routines */ -static herr_t H5FS_sinfo_serialize_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata); -static herr_t H5FS_sinfo_serialize_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata); +static herr_t H5FS__sinfo_serialize_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata); +static herr_t H5FS__sinfo_serialize_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata); /* Metadata cache callbacks */ -static H5FS_t *H5FS_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5FS_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_t *fspace, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5FS_cache_hdr_dest(H5F_t *f, H5FS_t *fspace); -static herr_t H5FS_cache_hdr_clear(H5F_t *f, H5FS_t *fspace, hbool_t destroy); -static herr_t H5FS_cache_hdr_size(const H5F_t *f, const H5FS_t *fspace, size_t *size_ptr); - -static H5FS_sinfo_t *H5FS_cache_sinfo_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5FS_cache_sinfo_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_sinfo_t *sinfo, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5FS_cache_sinfo_dest(H5F_t *f, H5FS_sinfo_t *sinfo); -static herr_t H5FS_cache_sinfo_clear(H5F_t *f, H5FS_sinfo_t *sinfo, hbool_t destroy); -static herr_t H5FS_cache_sinfo_notify(H5AC_notify_action_t action, H5FS_sinfo_t *sinfo); -static herr_t H5FS_cache_sinfo_size(const H5F_t *f, const H5FS_sinfo_t *sinfo, size_t *size_ptr); +static herr_t H5FS__cache_hdr_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5FS__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5FS__cache_hdr_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5FS__cache_hdr_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5FS__cache_hdr_pre_serialize(const H5F_t *f, hid_t dxpl_id, + void *thing, haddr_t addr, size_t len, size_t compressed_len, + haddr_t *new_addr, size_t *new_len, size_t *new_compressed_len, + unsigned *flags); +static herr_t H5FS__cache_hdr_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5FS__cache_hdr_free_icr(void *thing); + +static herr_t H5FS__cache_sinfo_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5FS__cache_sinfo_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5FS__cache_sinfo_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5FS__cache_sinfo_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5FS__cache_sinfo_pre_serialize(const H5F_t *f, hid_t dxpl_id, + void *thing, haddr_t addr, size_t len, size_t compressed_len, + haddr_t *new_addr, size_t *new_len, size_t *new_compressed_len, + unsigned *flags); +static herr_t H5FS__cache_sinfo_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5FS__cache_sinfo_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5FS__cache_sinfo_free_icr(void *thing); /*********************/ @@ -99,24 +116,38 @@ static herr_t H5FS_cache_sinfo_size(const H5F_t *f, const H5FS_sinfo_t *sinfo, s /* H5FS header inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FSPACE_HDR[1] = {{ - H5AC_FSPACE_HDR_ID, - (H5AC_load_func_t)H5FS_cache_hdr_load, - (H5AC_flush_func_t)H5FS_cache_hdr_flush, - (H5AC_dest_func_t)H5FS_cache_hdr_dest, - (H5AC_clear_func_t)H5FS_cache_hdr_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5FS_cache_hdr_size, + H5AC_FSPACE_HDR_ID, /* Metadata client ID */ + "Free Space Header", /* Metadata client name (for debugging) */ + H5FD_MEM_FSPACE_HDR, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5FS__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5FS__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ + H5FS__cache_hdr_deserialize, /* 'deserialize' callback */ + H5FS__cache_hdr_image_len, /* 'image_len' callback */ + H5FS__cache_hdr_pre_serialize, /* 'pre_serialize' callback */ + H5FS__cache_hdr_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5FS__cache_hdr_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; -/* H5FS serialized sections inherit cache-like properties from H5AC */ +/* H5FS section info inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FSPACE_SINFO[1] = {{ - H5AC_FSPACE_SINFO_ID, - (H5AC_load_func_t)H5FS_cache_sinfo_load, - (H5AC_flush_func_t)H5FS_cache_sinfo_flush, - (H5AC_dest_func_t)H5FS_cache_sinfo_dest, - (H5AC_clear_func_t)H5FS_cache_sinfo_clear, - (H5AC_notify_func_t)H5FS_cache_sinfo_notify, - (H5AC_size_func_t)H5FS_cache_sinfo_size, + H5AC_FSPACE_SINFO_ID, /* Metadata client ID */ + "Free Space Section Info", /* Metadata client name (for debugging) */ + H5FD_MEM_FSPACE_SINFO, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5FS__cache_sinfo_get_load_size, /* 'get_load_size' callback */ + H5FS__cache_sinfo_verify_chksum, /* 'verify_chksum' callback */ + H5FS__cache_sinfo_deserialize, /* 'deserialize' callback */ + H5FS__cache_sinfo_image_len, /* 'image_len' callback */ + H5FS__cache_sinfo_pre_serialize, /* 'pre_serialize' callback */ + H5FS__cache_sinfo_serialize, /* 'serialize' callback */ + H5FS__cache_sinfo_notify, /* 'notify' callback */ + H5FS__cache_sinfo_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -129,41 +160,117 @@ const H5AC_class_t H5AC_FSPACE_SINFO[1] = {{ /* Local Variables */ /*******************/ -/* Declare a free list to manage free space section data to/from disk */ -H5FL_BLK_DEFINE_STATIC(sect_block); - /*------------------------------------------------------------------------- - * Function: H5FS_cache_hdr_load + * Function: H5FS__cache_hdr_get_load_size * - * Purpose: Loads a free space manager header from the disk. + * Purpose: Compute the size of the data structure on disk. * - * Return: Success: Pointer to a new free space header - * Failure: NULL + * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * May 2 2006 + * koziol@hdfgroup.org + * August 14, 2013 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS__cache_hdr_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5FS_hdr_cache_ud_t *udata = (H5FS_hdr_cache_ud_t *)_udata; /* User-data for metadata cache callback */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(udata); + HDassert(udata->f); + HDassert(image_len); + + if(image == NULL) { + /* Set the image length size */ + *image_len = (size_t)H5FS_HEADER_SIZE(udata->f); + } else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FS__cache_hdr_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS__cache_hdr_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +htri_t +H5FS__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FS__cache_hdr_verify_chksum() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS__cache_hdr_deserialize + * + * Purpose: Given a buffer containing the on disk image of the free space + * manager section info, allocate an instance of H5FS_t, load + * it with the data contained in the image, and return a pointer + * to the new instance. + * + * Return: Success: Pointer to new object + * Failure: NULL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * August 18 2013 * *------------------------------------------------------------------------- */ -static H5FS_t * -H5FS_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5FS__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { - H5FS_t *fspace = NULL; /* Free space header info */ - H5FS_hdr_cache_ud_t *udata = (H5FS_hdr_cache_ud_t *)_udata; /* user data for callback */ - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5FS_HDR_BUF_SIZE]; /* Buffer for header */ - uint8_t *hdr; /* Pointer to header buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5FS_t *fspace = NULL; /* Free space header info */ + H5FS_hdr_cache_ud_t *udata = (H5FS_hdr_cache_ud_t *)_udata; /* User data for callback */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ unsigned nclasses; /* Number of section classes */ H5FS_t *ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check arguments */ - HDassert(f); + HDassert(image); HDassert(udata); + HDassert(udata->f); /* Allocate a new free space manager */ if(NULL == (fspace = H5FS__new(udata->f, udata->nclasses, udata->classes, udata->cls_init_udata))) @@ -172,423 +279,676 @@ H5FS_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) /* Set free space manager's internal information */ fspace->addr = udata->addr; - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, NULL, "can't wrap buffer") - - /* Get a pointer to a buffer that's large enough for header */ - if(NULL == (hdr = (uint8_t *)H5WB_actual(wb, fspace->hdr_size))) - HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, NULL, "can't get actual buffer") - - /* Read and validate header from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_FSPACE_HDR, H5AC_FSPACE_HDR_ID, addr, fspace->hdr_size, fspace->hdr_size, hdr) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_BADVALUE, NULL, "incorrect metadata checksum for free space header") - - p = hdr; - /* Magic number */ - if(HDmemcmp(p, H5FS_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5FS_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space header signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5FS_HDR_VERSION) + if(*image++ != H5FS_HDR_VERSION) HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space header version") /* Client ID */ - fspace->client = (H5FS_client_t)*p++; + fspace->client = (H5FS_client_t)*image++; if(fspace->client >= H5FS_NUM_CLIENT_ID) HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "unknown client ID in free space header") /* Total space tracked */ - H5F_DECODE_LENGTH(udata->f, p, fspace->tot_space); + H5F_DECODE_LENGTH(udata->f, image, fspace->tot_space); /* Total # of free space sections tracked */ - H5F_DECODE_LENGTH(udata->f, p, fspace->tot_sect_count); + H5F_DECODE_LENGTH(udata->f, image, fspace->tot_sect_count); /* # of serializable free space sections tracked */ - H5F_DECODE_LENGTH(udata->f, p, fspace->serial_sect_count); + H5F_DECODE_LENGTH(udata->f, image, fspace->serial_sect_count); /* # of ghost free space sections tracked */ - H5F_DECODE_LENGTH(udata->f, p, fspace->ghost_sect_count); + H5F_DECODE_LENGTH(udata->f, image, fspace->ghost_sect_count); /* # of section classes */ /* (only check if we actually have some classes) */ - UINT16DECODE(p, nclasses); + UINT16DECODE(image, nclasses); if(fspace->nclasses > 0 && fspace->nclasses != nclasses) HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "section class count mismatch") /* Shrink percent */ - UINT16DECODE(p, fspace->shrink_percent); + UINT16DECODE(image, fspace->shrink_percent); /* Expand percent */ - UINT16DECODE(p, fspace->expand_percent); + UINT16DECODE(image, fspace->expand_percent); - /* Size of address space free space sections are within (log2 of actual value) */ - UINT16DECODE(p, fspace->max_sect_addr); + /* Size of address space free space sections are within + * (log2 of actual value) + */ + UINT16DECODE(image, fspace->max_sect_addr); /* Max. size of section to track */ - H5F_DECODE_LENGTH(udata->f, p, fspace->max_sect_size); + H5F_DECODE_LENGTH(udata->f, image, fspace->max_sect_size); /* Address of serialized free space sections */ - H5F_addr_decode(udata->f, &p, &fspace->sect_addr); + H5F_addr_decode(udata->f, &image, &fspace->sect_addr); /* Size of serialized free space sections */ - H5F_DECODE_LENGTH(udata->f, p, fspace->sect_size); + H5F_DECODE_LENGTH(udata->f, image, fspace->sect_size); /* Allocated size of serialized free space sections */ - H5F_DECODE_LENGTH(udata->f, p, fspace->alloc_sect_size); + H5F_DECODE_LENGTH(udata->f, image, fspace->alloc_sect_size); + + /* checksum verification already done in verify_chksum cb */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - (const uint8_t *)hdr) == (fspace->hdr_size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) <= len); /* Set return value */ ret_value = fspace; done: /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_FSPACE, H5E_CLOSEERROR, NULL, "can't close wrapped buffer") if(!ret_value && fspace) if(H5FS__hdr_dest(fspace) < 0) HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, NULL, "unable to destroy free space header") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5FS_cache_hdr_load() */ /*lint !e818 Can't make udata a pointer to const */ +} /* end H5FS__cache_hdr_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5FS_cache_hdr_flush + * Function: H5FS__cache_hdr_image_len * - * Purpose: Flushes a dirty free space header to disk. + * Purpose: Compute the size of the data structure on disk and return + * it in *image_len. * - * Return: SUCCEED/FAIL + * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * May 2 2006 + * koziol@hdfgroup.org + * August 14, 2013 * *------------------------------------------------------------------------- */ static herr_t -H5FS_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_t *fspace, unsigned H5_ATTR_UNUSED * flags_ptr) +H5FS__cache_hdr_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5FS_HDR_BUF_SIZE]; /* Buffer for header */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5FS_t *fspace = (const H5FS_t *)_thing; /* Pointer to the object */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(fspace); + HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR); + HDassert(image_len); + + /* Set the image length size */ + *image_len = fspace->hdr_size; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FS__cache_hdr_image_len() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS__cache_hdf_pre_serialize + * + * Purpose: The free space manager header contains the address, size, and + * allocation size of the free space manager section info. However, + * since it is possible for the section info to either not be allocated + * at all, or be allocated in temporary (AKA imaginary) files space, + * it is possible for the above mentioned fields to contain giberish + * when the free space manager header is serialized. + * + * This function exists to prevent this problem. It does so by + * forcing allocation of real file space for the section information. + * + * Note that in the Version 2 cache, this problem was dealt with by + * simply flushing the section info before flushing the header. This + * was possible, since the clients handled file I/O directly. As + * this responsibility has moved to the cache in Version 3, this + * solution is no longer directly applicable. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS__cache_hdr_pre_serialize(const H5F_t *f, hid_t dxpl_id, void *_thing, + haddr_t addr, size_t H5_ATTR_UNUSED len, size_t H5_ATTR_UNUSED compressed_len, + haddr_t *new_addr, size_t *new_len, size_t H5_ATTR_UNUSED *new_compressed_len, + unsigned *flags) +{ + H5FS_t *fspace = (H5FS_t *)_thing; /* Pointer to the object */ + herr_t ret_value = SUCCEED; /* Return value */ - /* check arguments */ + FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) + + /* Sanity check */ HDassert(f); - HDassert(H5F_addr_defined(addr)); HDassert(fspace); - HDassert(H5F_addr_defined(fspace->addr)); + HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR); + HDassert(H5F_addr_defined(addr)); + HDassert(new_addr); + HDassert(new_len); + HDassert(flags); - /* Check if the header "owns" the section info */ if(fspace->sinfo) { - /* Sanity check - should not be trying to destroy header if it still - * "owns" section info + /* This implies that the header "owns" the section info. + * + * Unfortunately, the comments in the code are not clear as to + * what this means, but from reviewing the code (most particularly + * H5FS_close(), H5FS_sinfo_lock, and H5FS_sinfo_unlock()), I + * gather that it means that the header is maintaining a pointer to + * an instance of H5FS_sinfo_t in which free space data is + * maintained, and either: + * + * 1) The instance of H5FS_sinfo_t is not in the metadata cache. + * + * This will be TRUE iff H5F_addr_defined(fspace->sect_addr) + * is FALSE, and fspace->sinfo is not NULL. This is sometimes + * referred to as "floating" section info in the comments. + * + * If the section info structure contains free space data + * that must be placed on disk eventually, then + * + * fspace->serial_sect_count > 0 + * + * and + * + * H5F_addr_defined(fspace->addr) + * + * will both be TRUE. If this contition does not hold, then + * either the free space info is not persistant + * (!H5F_addr_defined(fspace->addr)???) or the section info + * contains no free space data that must be written to file + * ( fspace->serial_sect_count == 0 ). + * + * 2) The instance of H5FS_sinfo_t is in the metadata cache with + * address in temporary file space (AKA imaginary file space). + * The entry may or may not be protected, and if protected, it + * may be protected either RW or RO (as indicated by + * fspace->sinfo_protected and fspace->sinfo_accmod). + * + * 3) The instance of H5FS_sinfo_t is in the metadata cache with + * address in real file space. As in case 2) above, the entry + * may or may not be protected, and if protected, it + * may be protected either RW or RO (as indicated by + * fspace->sinfo_protected and fspace->sinfo_accmod). + * + * Observe that fspace->serial_sect_count > 0 must be TRUE in + * cases 2) and 3), as the section info should not be stored on + * disk if it doesn't exist. Similarly, since the section info + * will not be stored to disk unless the header is, + * H5F_addr_defined(fspace->addr) must hold as well. + * + * As the objective is to touch up the free space manager header + * so that it contains sensical data on the size and location of + * the section information, we have to handle each of the above + * cases differently. + * + * Case 1) If either fspace->serial_sect_count == 0 or + * ! H5F_addr_defined(fspace->addr) do nothing as either + * the free space manager data is not persistant, or the + * section info is empty. + * + * Otherwise, allocate space for the section info in real + * file space, insert the section info at this location, and + * set fspace->sect_addr, fspace->sect_size, and + * fspace->alloc_sect_size to reflect the new location + * of the section info. Note that it is not necessary to + * force a write of the section info. + * + * Case 2) Allocate space for the section info in real file space, + * and tell the metadata cache to relocate the entry. + * Update fspace->sect_addr, fspace->sect_size, and + * fspace->alloc_sect_size to reflect the new location. + * + * Case 3) Nothing to be done in this case, although it is useful + * to perform sanity checks. + * + * Note that while we may alter the contents of the free space + * header in cases 1) and 2), there is no need to mark the header + * as dirty, as the metadata cache would not be attempting to + * serialize the header if it though it was clean. */ - HDassert(!destroy); - - /* Check if the section info is dirty */ - if(fspace->sinfo->dirty) { - if(fspace->serial_sect_count > 0) { - /* Check if we need to allocate space for section info */ - if(H5F_IS_TMP_ADDR(f, fspace->sect_addr) || !H5F_addr_defined(fspace->sect_addr)) { - /* Sanity check */ - HDassert(fspace->sect_size > 0); - - /* Allocate space for the section info in file */ - if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size))) - HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") - fspace->alloc_sect_size = (size_t)fspace->sect_size; - - /* Mark header dirty */ - /* (don't use cache API, since we're in a callback) */ - fspace->cache_info.is_dirty = TRUE; - } /* end if */ - - /* Write section info to file */ - if(H5FS_cache_sinfo_flush(f, dxpl_id, FALSE, fspace->sect_addr, fspace->sinfo, NULL) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFLUSH, FAIL, "unable to save free space section info to disk") + if(fspace->serial_sect_count > 0 && H5F_addr_defined(fspace->addr)) { + /* Sanity check */ + HDassert(fspace->sect_size > 0); + + if(!H5F_addr_defined(fspace->sect_addr)) { /* case 1 */ + /* allocate file space for the section info, and insert it + * into the metadata cache. + */ + if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size))) + HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") + + fspace->alloc_sect_size = (size_t)fspace->sect_size; + if(H5AC_insert_entry((H5F_t *)f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sections to cache") + + HDassert(fspace->sinfo->cache_info.size == fspace->alloc_sect_size); + + /* the metadata cache is now managing the section info, + * so set fspace->sinfo to NULL. + */ + fspace->sinfo = NULL; } /* end if */ - - /* Mark section info clean */ - fspace->sinfo->dirty = FALSE; - } /* end if */ + else if(H5F_IS_TMP_ADDR(f, fspace->sect_addr)) { /* case 2 */ + haddr_t new_sect_addr; + + /* move the section info from temporary (AKA imaginary) file + * space to real file space. + */ + + /* if my reading of the code is correct, this should always + * be the case. If not, we will have to add code to resize + * file space allocation for section info as well as moving it. + */ + HDassert(fspace->sect_size > 0); + HDassert(fspace->alloc_sect_size == (size_t)fspace->sect_size); + + /* Allocate space for the section info in file */ + if(HADDR_UNDEF == (new_sect_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size))) + HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") + + fspace->alloc_sect_size = (size_t)fspace->sect_size; + HDassert(fspace->sinfo->cache_info.size == fspace->alloc_sect_size); + + /* Let the metadata cache know the section info moved */ + if(H5AC_move_entry((H5F_t *)f, H5AC_FSPACE_SINFO, fspace->sect_addr, new_sect_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move section info") + + fspace->sect_addr = new_sect_addr; + } /* end else-if */ + else { /* case 3 -- nothing to do but sanity checking */ + /* if my reading of the code is correct, this should always + * be the case. If not, we will have to add code to resize + * file space allocation for section info. + */ + HDassert(fspace->sect_size > 0); + HDassert(fspace->alloc_sect_size == (size_t)fspace->sect_size); + } /* end else */ + } /* end else */ + else { + /* for one reason or another (see comment above) there should + * not be any file space allocated for the section info. + */ + HDassert(!H5F_addr_defined(fspace->sect_addr)); + } /* end else */ } /* end if */ - else if(fspace->serial_sect_count > 0) - /* Sanity check that section info has address */ - HDassert(H5F_addr_defined(fspace->sect_addr)); + else if(H5F_addr_defined(fspace->sect_addr)) { + /* Here the metadata cache is managing the section info. + * + * Do some sanity checks, and then test to see if the section + * info is in real file space. If it isn't relocate it into + * real file space lest the header be written to file with + * a nonsense section info address. + */ + HDassert(fspace->serial_sect_count > 0); + HDassert(fspace->sect_size > 0); + HDassert(fspace->alloc_sect_size == (size_t)fspace->sect_size); + + if(H5F_IS_TMP_ADDR(f, fspace->sect_addr)) { + unsigned sect_status = 0; + haddr_t new_sect_addr; + + /* we have work to do -- must relocate section info into + * real file space. + * + * Since the section info address is in temporary space (AKA + * imaginary space), it follows that the entry must be in + * cache. Further, since fspace->sinfo is NULL, it must be + * unprotected and un-pinned. Start by verifying this. + */ + if(H5AC_get_entry_status(f, fspace->sect_addr, §_status) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info status") + + HDassert(sect_status & H5AC_ES__IN_CACHE); + HDassert((sect_status & H5AC_ES__IS_PROTECTED) == 0); + HDassert((sect_status & H5AC_ES__IS_PINNED) == 0); - if(fspace->cache_info.is_dirty) { - uint8_t *hdr; /* Pointer to header buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ + /* Allocate space for the section info in file */ + if(HADDR_UNDEF == (new_sect_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size))) + HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't wrap buffer") + fspace->alloc_sect_size = (size_t)fspace->sect_size; - /* Get a pointer to a buffer that's large enough for header */ - if(NULL == (hdr = (uint8_t *)H5WB_actual(wb, fspace->hdr_size))) - HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "can't get actual buffer") + /* Sanity check */ + HDassert(!H5F_addr_eq(fspace->sect_addr, new_sect_addr)); - /* Get temporary pointer to header */ - p = hdr; + /* Let the metadata cache know the section info moved */ + if(H5AC_move_entry((H5F_t *)f, H5AC_FSPACE_SINFO, fspace->sect_addr, new_sect_addr) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTMOVE, FAIL, "unable to move section info") - /* Magic number */ - HDmemcpy(p, H5FS_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; + /* Update the internal address for the section info */ + fspace->sect_addr = new_sect_addr; - /* Version # */ - *p++ = H5FS_HDR_VERSION; + /* No need to mark the header dirty, as we are about to + * serialize it. + */ + } /* end if */ + } /* end else-if */ + else { /* there is no section info at present */ + /* do some sanity checks */ + HDassert(fspace->serial_sect_count == 0); + HDassert(fspace->tot_sect_count == fspace->ghost_sect_count); + } /* end else */ - /* Client ID */ - *p++ = fspace->client; + /* what ever happened above, set *flags to 0 */ + *flags = 0; - /* Total space tracked */ - H5F_ENCODE_LENGTH(f, p, fspace->tot_space); +done: + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5FS__cache_hdr_pre_serialize() */ - /* Total # of free space sections tracked */ - H5F_ENCODE_LENGTH(f, p, fspace->tot_sect_count); + +/*------------------------------------------------------------------------- + * Function: H5FS__cache_hdr_serialize + * + * Purpose: Given an instance of H5FS_t and a suitably sized buffer, + * serialize the contents of the instance of H5FS_t and write + * its contents to the buffer. This buffer will be used to + * write the image of the instance to file. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FS__cache_hdr_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) +{ + H5FS_t *fspace = (H5FS_t *)_thing; /* Pointer to the object */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + herr_t ret_value = SUCCEED; /* Return value */ - /* # of serializable free space sections tracked */ - H5F_ENCODE_LENGTH(f, p, fspace->serial_sect_count); + FUNC_ENTER_STATIC_NOERR - /* # of ghost free space sections tracked */ - H5F_ENCODE_LENGTH(f, p, fspace->ghost_sect_count); + /* Check arguments */ + HDassert(f); + HDassert(image); + HDassert(fspace); + HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR); + HDassert(fspace->hdr_size == len); + + /* The section information does not always exits, and if it does, + * it is not always in the cache. To make matters more interesting, + * even if it is in the cache, it may not be in real file space. + * + * The pre-serialize function should have moved the section info + * into real file space if necessary before this function was called. + * The following asserts are a cursory check on this. + */ + HDassert((! H5F_addr_defined(fspace->sect_addr)) || (! H5F_IS_TMP_ADDR(f, fspace->sect_addr))); + HDassert((! H5F_addr_defined(fspace->sect_addr)) || + ((fspace->serial_sect_count > 0) && + (fspace->sect_size > 0) && + (fspace->alloc_sect_size == (size_t)fspace->sect_size))); - /* # of section classes */ - UINT16ENCODE(p, fspace->nclasses); + /* Magic number */ + HDmemcpy(image, H5FS_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Shrink percent */ - UINT16ENCODE(p, fspace->shrink_percent); + /* Version # */ + *image++ = H5FS_HDR_VERSION; - /* Expand percent */ - UINT16ENCODE(p, fspace->expand_percent); + /* Client ID */ + *image++ = fspace->client; - /* Size of address space free space sections are within (log2 of actual value) */ - UINT16ENCODE(p, fspace->max_sect_addr); + /* Total space tracked */ + H5F_ENCODE_LENGTH(f, image, fspace->tot_space); - /* Max. size of section to track */ - H5F_ENCODE_LENGTH(f, p, fspace->max_sect_size); + /* Total # of free space sections tracked */ + H5F_ENCODE_LENGTH(f, image, fspace->tot_sect_count); - /* Address of serialized free space sections */ - H5F_addr_encode(f, &p, fspace->sect_addr); + /* # of serializable free space sections tracked */ + H5F_ENCODE_LENGTH(f, image, fspace->serial_sect_count); - /* Size of serialized free space sections */ - H5F_ENCODE_LENGTH(f, p, fspace->sect_size); + /* # of ghost free space sections tracked */ + H5F_ENCODE_LENGTH(f, image, fspace->ghost_sect_count); - /* Allocated size of serialized free space sections */ - H5F_ENCODE_LENGTH(f, p, fspace->alloc_sect_size); + /* # of section classes */ + UINT16ENCODE(image, fspace->nclasses); - /* Compute checksum */ - metadata_chksum = H5_checksum_metadata(hdr, (size_t)(p - (uint8_t *)hdr), 0); + /* Shrink percent */ + UINT16ENCODE(image, fspace->shrink_percent); - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); + /* Expand percent */ + UINT16ENCODE(image, fspace->expand_percent); - /* Write the free space header. */ - HDassert((size_t)(p - hdr) == fspace->hdr_size); - if(H5F_block_write(f, H5FD_MEM_FSPACE_HDR, addr, fspace->hdr_size, dxpl_id, hdr) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFLUSH, FAIL, "unable to save free space header to disk") + /* Size of address space free space sections are within (log2 of + * actual value) + */ + UINT16ENCODE(image, fspace->max_sect_addr); - fspace->cache_info.is_dirty = FALSE; - } /* end if */ + /* Max. size of section to track */ + H5F_ENCODE_LENGTH(f, image, fspace->max_sect_size); - if(destroy) - if(H5FS_cache_hdr_dest(f, fspace) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space header") + /* Address of serialized free space sections */ + H5F_addr_encode(f, &image, fspace->sect_addr); -done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_FSPACE, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") + /* Size of serialized free space sections */ + H5F_ENCODE_LENGTH(f, image, fspace->sect_size); + + /* Allocated size of serialized free space sections */ + H5F_ENCODE_LENGTH(f, image, fspace->alloc_sect_size); + + /* Compute checksum */ + metadata_chksum = H5_checksum_metadata((uint8_t *)_image, (size_t)(image - (uint8_t *)_image), 0); + + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + + /* sanity checks */ + HDassert((size_t)(image - (uint8_t *)_image) == fspace->hdr_size); FUNC_LEAVE_NOAPI(ret_value) -} /* H5FS_cache_hdr_flush() */ +} /* H5FS__cache_hdr_serialize() */ + +/***************************************/ +/* no H5FS__cache_hdr_notify() function */ +/***************************************/ /*------------------------------------------------------------------------- - * Function: H5FS_cache_hdr_dest + * Function: H5FS__cache_hdr_free_icr * - * Purpose: Destroys a free space header in memory. + * Purpose: Destroys a free space header in memory. * - * Return: SUCCEED/FAIL + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Programmer: Quincey Koziol - * May 2 2006 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * May 2 2006 * *------------------------------------------------------------------------- */ static herr_t -H5FS_cache_hdr_dest(H5F_t *f, H5FS_t *fspace) +H5FS__cache_hdr_free_icr(void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5FS_t *fspace = (H5FS_t *)_thing; /* Pointer to the object */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* Check arguments */ + /* Sanity checks */ HDassert(fspace); + HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR); /* We should not still be holding on to the free space section info */ HDassert(!fspace->sinfo); - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!fspace->cache_info.free_file_space_on_destroy || H5F_addr_defined(fspace->cache_info.addr)); - - /* Check for freeing file space for free space header */ - if(fspace->cache_info.free_file_space_on_destroy) { - /* Sanity check */ - HDassert(H5F_addr_defined(fspace->addr)); - - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_FSPACE_HDR, H5AC_dxpl_id, fspace->cache_info.addr, (hsize_t)fspace->hdr_size) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space header") - } /* end if */ - /* Destroy free space header */ if(H5FS__hdr_dest(fspace) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space header") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5FS_cache_hdr_dest() */ +} /* end H5FS__cache_hdr_free_icr() */ + +/********************************************************/ +/* metadata cache callback definitions for section info */ +/********************************************************/ /*------------------------------------------------------------------------- - * Function: H5FS_cache_hdr_clear + * Function: H5FS__cache_sinfo_get_load_size() * - * Purpose: Mark a free space header in memory as non-dirty. + * Purpose: Compute the size of the on disk image of the free space + * manager section info, and place this value in *image_len. * - * Return: SUCCEED/FAIL + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * May 2 2006 + * Programmer: John Mainzer + * 7/7/14 * *------------------------------------------------------------------------- */ -static herr_t -H5FS_cache_hdr_clear(H5F_t *f, H5FS_t *fspace, hbool_t destroy) +static herr_t +H5FS__cache_sinfo_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + const H5FS_t *fspace; /* free space manager */ + H5FS_sinfo_cache_ud_t *udata = (H5FS_sinfo_cache_ud_t *)_udata; /* User data for callback */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* - * Check arguments. - */ + /* Sanity checks */ + HDassert(udata); + fspace = udata->fspace; HDassert(fspace); + HDassert(fspace->sect_size > 0); + HDassert(image_len); - /* Reset the dirty flag. */ - fspace->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5FS_cache_hdr_dest(f, fspace) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space header") + if(image == NULL) + *image_len = (size_t)(fspace->sect_size); + else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5FS_cache_hdr_clear() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FS__cache_sinfo_get_load_size() */ /*------------------------------------------------------------------------- - * Function: H5FS_cache_hdr_size + * Function: H5FS__cache_sinfo_verify_chksum * - * Purpose: Compute the size in bytes of a free space header - * on disk, and return it in *size_ptr. + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. * - * Return: SUCCEED (Can't fail) + * Return: Success: TRUE/FALSE + * Failure: Negative * - * Programmer: Quincey Koziol - * May 2 2006 + * Programmer: Vailin Choi; Aug 2015 * *------------------------------------------------------------------------- */ -static herr_t -H5FS_cache_hdr_size(const H5F_t H5_ATTR_UNUSED *f, const H5FS_t *fspace, size_t *size_ptr) +htri_t +H5FS__cache_sinfo_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ - /* check arguments */ - HDassert(f); - HDassert(fspace); - HDassert(size_ptr); + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); - /* Set size value */ - *size_ptr = fspace->hdr_size; + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5FS_cache_hdr_size() */ + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FS__cache_sinfo_verify_chksum() */ /*------------------------------------------------------------------------- - * Function: H5FS_cache_sinfo_load + * Function: H5FS__cache_sinfo_deserialize * - * Purpose: Loads free space sections from the disk. + * Purpose: Given a buffer containing the on disk image of the free space + * manager section info, allocate an instance of H5FS_sinfo_t, load + * it with the data contained in the image, and return a pointer to + * the new instance. * - * Return: Success: Pointer to a new free space section info - * Failure: NULL + * Return: Success: Pointer to in core representation + * Failure: NULL * - * Programmer: Quincey Koziol - * July 31 2006 + * Programmer: John Mainzer + * 7/7/14 * *------------------------------------------------------------------------- */ -static H5FS_sinfo_t * -H5FS_cache_sinfo_load(H5F_t *f, hid_t dxpl_id, haddr_t H5_ATTR_UNUSED addr, void *_udata) +static void * +H5FS__cache_sinfo_deserialize(const void *_image, size_t len, void *_udata, + hbool_t *dirty) { - H5FS_sinfo_t *sinfo = NULL; /* Free space section info */ - H5FS_sinfo_cache_ud_t *udata = (H5FS_sinfo_cache_ud_t *)_udata; /* user data for callback */ - haddr_t fs_addr; /* Free space header address */ - size_t old_sect_size; /* Old section size */ - uint8_t *buf = NULL; /* Temporary buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ - H5FS_sinfo_t *ret_value; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT - - /* Check arguments */ - HDassert(f); + H5FS_sinfo_cache_ud_t *udata = (H5FS_sinfo_cache_ud_t *)_udata; /* User data for callback */ + H5FS_t *fspace; /* free space manager */ + H5FS_sinfo_t *sinfo = NULL; /* Free space section info */ + haddr_t fs_addr; /* Free space header address */ + size_t old_sect_size; /* Old section size */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum */ + void * ret_value; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(image); HDassert(udata); + fspace = udata->fspace; + HDassert(fspace); + HDassert(fspace->sect_size == len); + HDassert(dirty); /* Allocate a new free space section info */ - if(NULL == (sinfo = H5FS_sinfo_new(udata->f, udata->fspace))) + if(NULL == (sinfo = H5FS_sinfo_new(udata->f, fspace))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - /* Allocate space for the buffer to serialize the sections into */ + /* initialize old_sect_size */ H5_CHECKED_ASSIGN(old_sect_size, size_t, udata->fspace->sect_size, hsize_t); - if(NULL == (buf = H5FL_BLK_MALLOC(sect_block, (size_t)udata->fspace->sect_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - /* Read and validate free space sections from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_FSPACE_SINFO, H5AC_FSPACE_SINFO_ID, udata->fspace->sect_addr, (size_t)udata->fspace->sect_size, (size_t)udata->fspace->sect_size, buf) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_BADVALUE, NULL, "incorrect metadata checksum for free space sections") - - /* Deserialize free sections from buffer available */ - p = buf; /* Magic number */ - if(HDmemcmp(p, H5FS_SINFO_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5FS_SINFO_MAGIC, (size_t)H5_SIZEOF_MAGIC)) HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space sections signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5FS_SINFO_VERSION) + if(*image++ != H5FS_SINFO_VERSION) HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space sections version") /* Address of free space header for these sections */ - H5F_addr_decode(udata->f, &p, &fs_addr); + H5F_addr_decode(udata->f, &image, &fs_addr); if(H5F_addr_ne(fs_addr, udata->fspace->addr)) HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "incorrect header address for free space sections") /* Check for any serialized sections */ - if(udata->fspace->serial_sect_count > 0) { + if(fspace->serial_sect_count > 0) { hsize_t old_tot_sect_count; /* Total section count from header */ hsize_t old_serial_sect_count; /* Total serializable section count from header */ hsize_t old_ghost_sect_count; /* Total ghost section count from header */ @@ -599,27 +959,27 @@ H5FS_cache_sinfo_load(H5F_t *f, hid_t dxpl_id, haddr_t H5_ATTR_UNUSED addr, void sect_cnt_size = H5VM_limit_enc_size((uint64_t)udata->fspace->serial_sect_count); /* Reset the section count, the "add" routine will update it */ - old_tot_sect_count = udata->fspace->tot_sect_count; - old_serial_sect_count = udata->fspace->serial_sect_count; - old_ghost_sect_count = udata->fspace->ghost_sect_count; - old_tot_space = udata->fspace->tot_space; - udata->fspace->tot_sect_count = 0; - udata->fspace->serial_sect_count = 0; - udata->fspace->ghost_sect_count = 0; - udata->fspace->tot_space = 0; - - /* Walk through the buffer, deserializing sections */ + old_tot_sect_count = fspace->tot_sect_count; + old_serial_sect_count = fspace->serial_sect_count; + old_ghost_sect_count = fspace->ghost_sect_count; + old_tot_space = fspace->tot_space; + fspace->tot_sect_count = 0; + fspace->serial_sect_count = 0; + fspace->ghost_sect_count = 0; + fspace->tot_space = 0; + + /* Walk through the image, deserializing sections */ do { hsize_t sect_size; /* Current section size */ size_t node_count; /* # of sections of this size */ size_t u; /* Local index variable */ /* The number of sections of this node's size */ - UINT64DECODE_VAR(p, node_count, sect_cnt_size); + UINT64DECODE_VAR(image, node_count, sect_cnt_size); HDassert(node_count); /* The size of the sections for this node */ - UINT64DECODE_VAR(p, sect_size, sinfo->sect_len_size); + UINT64DECODE_VAR(image, sect_size, sinfo->sect_len_size); HDassert(sect_size); /* Loop over nodes of this size */ @@ -630,435 +990,466 @@ H5FS_cache_sinfo_load(H5F_t *f, hid_t dxpl_id, haddr_t H5_ATTR_UNUSED addr, void unsigned des_flags; /* Flags from deserialize callback */ /* The address of the section */ - UINT64DECODE_VAR(p, sect_addr, sinfo->sect_off_size); + UINT64DECODE_VAR(image, sect_addr, sinfo->sect_off_size); /* The type of this section */ - sect_type = *p++; + sect_type = *image++; /* Call 'deserialize' callback for this section */ des_flags = 0; HDassert(udata->fspace->sect_cls[sect_type].deserialize); - if(NULL == (new_sect = (*udata->fspace->sect_cls[sect_type].deserialize)(&udata->fspace->sect_cls[sect_type], udata->dxpl_id, p, sect_addr, sect_size, &des_flags))) + if(NULL == (new_sect = (*fspace->sect_cls[sect_type].deserialize) (&fspace->sect_cls[sect_type], udata->dxpl_id, image, sect_addr, sect_size, &des_flags))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTDECODE, NULL, "can't deserialize section") - /* Update offset in serialization buffer */ - p += udata->fspace->sect_cls[sect_type].serial_size; + /* Update offset in serialization image */ + image += udata->fspace->sect_cls[sect_type].serial_size; /* Insert section in free space manager, unless requested not to */ if(!(des_flags & H5FS_DESERIALIZE_NO_ADD)) if(H5FS_sect_add(udata->f, udata->dxpl_id, udata->fspace, new_sect, H5FS_ADD_DESERIALIZING, NULL) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, NULL, "can't add section to free space manager") } /* end for */ - } while(p < ((buf + old_sect_size) - H5FS_SIZEOF_CHKSUM)); + } while(image < (((const uint8_t *)_image + old_sect_size) - H5FS_SIZEOF_CHKSUM)); /* Sanity check */ - HDassert((size_t)(p - buf) == (old_sect_size - H5FS_SIZEOF_CHKSUM)); - HDassert(old_sect_size == udata->fspace->sect_size); - HDassert(old_tot_sect_count == udata->fspace->tot_sect_count); - HDassert(old_serial_sect_count == udata->fspace->serial_sect_count); - HDassert(old_ghost_sect_count == udata->fspace->ghost_sect_count); - HDassert(old_tot_space == udata->fspace->tot_space); + HDassert((size_t)(image - (const uint8_t *)_image) == (old_sect_size - H5FS_SIZEOF_CHKSUM)); + HDassert(old_sect_size == fspace->sect_size); + HDassert(old_tot_sect_count == fspace->tot_sect_count); + HDassert(old_serial_sect_count == fspace->serial_sect_count); + HDassert(old_ghost_sect_count == fspace->ghost_sect_count); + HDassert(old_tot_space == fspace->tot_space); } /* end if */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - (const uint8_t *)buf) == (old_sect_size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == old_sect_size); /* Set return value */ ret_value = sinfo; done: - if(buf) - buf = H5FL_BLK_FREE(sect_block, buf); if(!ret_value && sinfo) if(H5FS_sinfo_dest(sinfo) < 0) HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, NULL, "unable to destroy free space info") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5FS_cache_sinfo_load() */ /*lint !e818 Can't make udata a pointer to const */ +} /* end H5FS__cache_sinfo_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5FS_sinfo_serialize_sect_cb + * Function: H5FS__cache_sinfo_image_len * - * Purpose: Skip list iterator callback to serialize free space sections - * of a particular size + * Purpose: Compute the size of the data structure on disk and return + * it in *image_len. * - * Return: SUCCEED/FAIL + * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * Monday, May 8, 2006 + * koziol@hdfgroup.org + * August 14, 2013 * *------------------------------------------------------------------------- */ static herr_t -H5FS_sinfo_serialize_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata) +H5FS__cache_sinfo_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5FS_section_class_t *sect_cls; /* Class of section */ - H5FS_section_info_t *sect= (H5FS_section_info_t *)_item; /* Free space section to work on */ - H5FS_iter_ud_t *udata = (H5FS_iter_ud_t *)_udata; /* Callback info */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT + const H5FS_sinfo_t *sinfo = (const H5FS_sinfo_t *)_thing; /* Pointer to the object */ + const H5FS_t *fspace; /* Free space header */ - /* Check arguments. */ - HDassert(sect); - HDassert(udata->sinfo); - HDassert(udata->p); - - /* Get section's class */ - sect_cls = &udata->sinfo->fspace->sect_cls[sect->type]; + FUNC_ENTER_STATIC_NOERR - /* Check if this section should be serialized (i.e. is not a ghost section) */ - if(!(sect_cls->flags & H5FS_CLS_GHOST_OBJ)) { - /* The address of the section */ - UINT64ENCODE_VAR(*udata->p, sect->addr, udata->sinfo->sect_off_size); - - /* The type of this section */ - *(*udata->p)++ = (uint8_t)sect->type; - - /* Call 'serialize' callback for this section */ - if(sect_cls->serialize) { - if((*sect_cls->serialize)(sect_cls, sect, *udata->p) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTSERIALIZE, FAIL, "can't syncronize section") + /* Sanity checks */ + HDassert(sinfo); + HDassert(sinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(sinfo->cache_info.type == H5AC_FSPACE_SINFO); + fspace = sinfo->fspace; + HDassert(fspace); + HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR); + HDassert(image_len); - /* Update offset in serialization buffer */ - (*udata->p) += sect_cls->serial_size; - } /* end if */ - else - HDassert(sect_cls->serial_size == 0); - } /* end if */ + /* Set the image length size */ + H5_CHECKED_ASSIGN(*image_len, size_t, sinfo->fspace->alloc_sect_size, hsize_t); -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5FS_sinfo_serialize_sect_cb() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FS__cache_sinfo_image_len() */ /*------------------------------------------------------------------------- - * Function: H5FS_sinfo_serialize_node_cb + * Function: H5FS__cache_sinfo_pre_serialize * - * Purpose: Skip list iterator callback to serialize free space sections - * in a bin + * Purpose: The objective of this function is to test to see if file space + * for the section info is located in temporary (AKA imaginary) file + * space. If it is, relocate file space for the section info to + * regular file space. * - * Return: SUCCEED/FAIL + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * Monday, May 8, 2006 + * Programmer: John Mainzer + * 7/7/14 * *------------------------------------------------------------------------- */ -static herr_t -H5FS_sinfo_serialize_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata) +static herr_t +H5FS__cache_sinfo_pre_serialize(const H5F_t *f, hid_t dxpl_id, void *_thing, + haddr_t addr, size_t len, size_t H5_ATTR_UNUSED compressed_len, haddr_t *new_addr, + size_t *new_len, size_t H5_ATTR_UNUSED *new_compressed_len, unsigned *flags) { - H5FS_node_t *fspace_node = (H5FS_node_t *)_item; /* Free space size node to work on */ - H5FS_iter_ud_t *udata = (H5FS_iter_ud_t *)_udata; /* Callback info */ - herr_t ret_value = SUCCEED; /* Return value */ + H5FS_sinfo_t *sinfo = (H5FS_sinfo_t *)_thing; /* Pointer to the object */ + H5FS_t *fspace; /* Free space header */ + haddr_t sinfo_addr; /* Address for section info */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* Check arguments. */ - HDassert(fspace_node); - HDassert(udata->sinfo); - HDassert(udata->p); + /* Sanity checks */ + HDassert(f); + HDassert(sinfo); + HDassert(sinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(sinfo->cache_info.type == H5AC_FSPACE_SINFO); + fspace = sinfo->fspace; + HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR); + HDassert(fspace->cache_info.is_pinned); + HDassert(H5F_addr_defined(addr)); + HDassert(H5F_addr_eq(fspace->sect_addr, addr)); + HDassert(fspace->sect_size == len); + HDassert(new_addr); + HDassert(new_len); + HDassert(flags); - /* Check if this node has any serializable sections */ - if(fspace_node->serial_count > 0) { - /* The number of serializable sections of this node's size */ - UINT64ENCODE_VAR(*udata->p, fspace_node->serial_count, udata->sect_cnt_size); + /* we shouldn't be called if the section info is empty */ + HDassert(fspace->serial_sect_count > 0); - /* The size of the sections for this node */ - UINT64ENCODE_VAR(*udata->p, fspace_node->sect_size, udata->sinfo->sect_len_size); + sinfo_addr = addr; /* this will change if we relocate the section data */ - /* Iterate through all the sections of this size */ - HDassert(fspace_node->sect_list); - if(H5SL_iterate(fspace_node->sect_list, H5FS_sinfo_serialize_sect_cb, udata) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section nodes") + /* Check for section info at temporary address */ + if(H5F_IS_TMP_ADDR(f, fspace->sect_addr)) { + /* Sanity check */ + HDassert(fspace->sect_size > 0); + HDassert(H5F_addr_eq(fspace->sect_addr, addr)); + + /* Allocate space for the section info in file */ + if(HADDR_UNDEF == (sinfo_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size))) + HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") + + fspace->alloc_sect_size = (size_t)fspace->sect_size; + + /* Sanity check */ + HDassert(!H5F_addr_eq(sinfo->fspace->sect_addr, sinfo_addr)); + + /* Let the metadata cache know the section info moved */ + if(H5AC_move_entry((H5F_t *)f, H5AC_FSPACE_SINFO, sinfo->fspace->sect_addr, sinfo_addr) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTMOVE, FAIL, "unable to move section info") + + /* Update the internal address for the section info */ + sinfo->fspace->sect_addr = sinfo_addr; + + /* Mark free space header as dirty */ + if(H5AC_mark_entry_dirty(fspace) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty") + } /* end if */ + + if(!H5F_addr_eq(addr, sinfo_addr)) { + *new_addr = sinfo_addr; + *flags = H5C__SERIALIZE_MOVED_FLAG; } /* end if */ + else + *flags = 0; done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5FS_sinfo_serialize_node_cb() */ +} /* end H5FS__cache_sinfo_pre_serialize() */ /*------------------------------------------------------------------------- - * Function: H5FS_cache_sinfo_flush + * Function: H5FS__cache_sinfo_serialize * - * Purpose: Flushes a dirty free space section info to disk. + * Purpose: Given an instance of H5FS_sinfo_t and a suitably sized buffer, + * serialize the contents of the instance of H5FS_sinfo_t and write + * its contents to the buffer. This buffer will be used to write + * the image of the instance to file. * - * Return: SUCCEED/FAIL + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * July 31 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5FS_cache_sinfo_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5FS_sinfo_t *sinfo, unsigned H5_ATTR_UNUSED * flags_ptr) +static herr_t +H5FS__cache_sinfo_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5FS_sinfo_t *sinfo = (H5FS_sinfo_t *)_thing; /* Pointer to the object */ + H5FS_t *fspace; /* Free space header */ + H5FS_iter_ud_t udata; /* User data for callbacks */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + unsigned bin; /* Current bin we are on */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* check arguments */ + /* Sanity checks */ HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(image); HDassert(sinfo); - HDassert(sinfo->fspace); - HDassert(sinfo->fspace->sect_cls); - - if(sinfo->cache_info.is_dirty || sinfo->dirty) { - H5FS_iter_ud_t udata; /* User data for callbacks */ - uint8_t *buf = NULL; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - unsigned bin; /* Current bin we are on */ - - /* Sanity check address */ - if(H5F_addr_ne(addr, sinfo->fspace->sect_addr)) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, FAIL, "incorrect address for free space sections") + HDassert(sinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(sinfo->cache_info.type == H5AC_FSPACE_SINFO); + fspace = sinfo->fspace; + HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR); + HDassert(fspace->cache_info.is_pinned); + HDassert(fspace->sect_size == len); + HDassert(fspace->sect_cls); - /* Allocate temporary buffer */ - if((buf = H5FL_BLK_MALLOC(sect_block, (size_t)sinfo->fspace->sect_size)) == NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - - p = buf; - - /* Magic number */ - HDmemcpy(p, H5FS_SINFO_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5FS_SINFO_VERSION; - - /* Address of free space header for these sections */ - H5F_addr_encode(f, &p, sinfo->fspace->addr); - - /* Set up user data for iterator */ - udata.sinfo = sinfo; - udata.p = &p; - udata.sect_cnt_size = H5VM_limit_enc_size((uint64_t)sinfo->fspace->serial_sect_count); - - /* Iterate over all the bins */ - for(bin = 0; bin < sinfo->nbins; bin++) - /* Check if there are any sections in this bin */ - if(sinfo->bins[bin].bin_list) - /* Iterate over list of section size nodes for bin */ - if(H5SL_iterate(sinfo->bins[bin].bin_list, H5FS_sinfo_serialize_node_cb, &udata) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section size nodes") - - /* Compute checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); - - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); - - /* Sanity check */ - HDassert((size_t)(p - buf) == sinfo->fspace->sect_size); - HDassert(sinfo->fspace->sect_size <= sinfo->fspace->alloc_sect_size); - - /* Check for section info at temporary address */ - if(H5F_IS_TMP_ADDR(f, sinfo->fspace->sect_addr)) { - /* Sanity check */ - HDassert(sinfo->fspace->sect_size > 0); - HDassert(H5F_addr_eq(sinfo->fspace->sect_addr, addr)); - - /* Allocate space for the section info in file */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, sinfo->fspace->sect_size))) - HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections") - sinfo->fspace->alloc_sect_size = (size_t)sinfo->fspace->sect_size; + /* Magic number */ + HDmemcpy(image, H5FS_SINFO_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Sanity check */ - HDassert(!H5F_addr_eq(sinfo->fspace->sect_addr, addr)); + /* Version # */ + *image++ = H5FS_SINFO_VERSION; - /* Let the metadata cache know the section info moved */ - if(H5AC_move_entry(f, H5AC_FSPACE_SINFO, sinfo->fspace->sect_addr, addr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move indirect block") + /* Address of free space header for these sections */ + H5F_addr_encode(f, &image, sinfo->fspace->addr); - /* Update the internal address for the section info */ - sinfo->fspace->sect_addr = addr; + /* Set up user data for iterator */ + udata.sinfo = sinfo; + udata.image = ℑ + udata.sect_cnt_size = H5VM_limit_enc_size((uint64_t)sinfo->fspace->serial_sect_count); - /* Mark free space header as dirty */ - if(H5AC_mark_entry_dirty(sinfo->fspace) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty") - } /* end if */ + /* Iterate over all the bins */ + for(bin = 0; bin < sinfo->nbins; bin++) + /* Check if there are any sections in this bin */ + if(sinfo->bins[bin].bin_list) + /* Iterate over list of section size nodes for bin */ + if(H5SL_iterate(sinfo->bins[bin].bin_list, H5FS__sinfo_serialize_node_cb, &udata) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section size nodes") - /* Write buffer to disk */ - if(H5F_block_write(f, H5FD_MEM_FSPACE_SINFO, sinfo->fspace->sect_addr, (size_t)sinfo->fspace->sect_size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFLUSH, FAIL, "unable to save free space sections to disk") - buf = H5FL_BLK_FREE(sect_block, buf); + /* Compute checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); - sinfo->cache_info.is_dirty = FALSE; - sinfo->dirty = FALSE; - } /* end if */ + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); - if(destroy) - if(H5FS_cache_sinfo_dest(f, sinfo) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space section info") + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) == sinfo->fspace->sect_size); + HDassert(sinfo->fspace->sect_size <= sinfo->fspace->alloc_sect_size); done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5FS_cache_sinfo_flush() */ +} /* end H5FS__cache_sinfo_serialize() */ /*------------------------------------------------------------------------- - * Function: H5FS_cache_sinfo_dest + * Function: H5FS__cache_sinfo_notify * - * Purpose: Destroys a free space section info in memory. + * Purpose: Handle cache action notifications * * Return: SUCCEED/FAIL * - * Programmer: Quincey Koziol - * July 31 2006 + * Programmer: Dana Robinson + * Fall 2012 * *------------------------------------------------------------------------- */ -static herr_t -H5FS_cache_sinfo_dest(H5F_t *f, H5FS_sinfo_t *sinfo) +herr_t +H5FS__cache_sinfo_notify(H5AC_notify_action_t action, void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5FS_sinfo_t *sinfo = (H5FS_sinfo_t *)_thing; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT - - /* Check arguments */ + + /* Sanity check */ HDassert(sinfo); - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!sinfo->cache_info.free_file_space_on_destroy || H5F_addr_defined(sinfo->cache_info.addr)); + /* Check if the file was opened with SWMR-write access */ + if(sinfo->fspace->swmr_write) { + /* Determine which action to take */ + switch(action) { + case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: + /* Create flush dependency on parent */ + if(H5FS__create_flush_depend((H5AC_info_t *)sinfo->fspace, (H5AC_info_t *)sinfo) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency between data block and header, address = %llu", (unsigned long long)sinfo->fspace->sect_addr) + break; - /* Check for freeing file space for free space section info */ - if(sinfo->cache_info.free_file_space_on_destroy) { - /* Sanity check */ - HDassert(sinfo->fspace->alloc_sect_size > 0); + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(!H5F_IS_TMP_ADDR(f, sinfo->cache_info.addr)) - if(H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, H5AC_dxpl_id, sinfo->cache_info.addr, (hsize_t)sinfo->fspace->alloc_sect_size) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space section info") - } /* end if */ + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: + /* Destroy flush dependency on parent */ + if(H5FS__destroy_flush_depend((H5AC_info_t *)sinfo->fspace, (H5AC_info_t *)sinfo) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency") + break; - /* Destroy free space info */ - if(H5FS_sinfo_dest(sinfo) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space info") + default: +#ifdef NDEBUG + HGOTO_ERROR(H5E_FSPACE, H5E_BADVALUE, FAIL, "unknown action from metadata cache") +#else /* NDEBUG */ + HDassert(0 && "Unknown action?!?"); +#endif /* NDEBUG */ + } /* end switch */ + } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5FS_cache_sinfo_dest() */ +} /* end H5FS__cache_sinfo_notify() */ /*------------------------------------------------------------------------- - * Function: H5FS_cache_sinfo_clear + * Function: H5FS__cache_sinfo_free_icr * - * Purpose: Mark a free space section info in memory as non-dirty. + * Purpose: Free the memory used for the in core representation of the + * free space manager section info. * - * Return: SUCCEED/FAIL + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Programmer: Quincey Koziol - * July 31 2006 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5FS_cache_sinfo_clear(H5F_t *f, H5FS_sinfo_t *sinfo, hbool_t destroy) +static herr_t +H5FS__cache_sinfo_free_icr(void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5FS_sinfo_t *sinfo = (H5FS_sinfo_t *)_thing; /* Pointer to the object */ + H5FS_t *fspace; /* Free space header */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ HDassert(sinfo); + HDassert(sinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(sinfo->cache_info.type == H5AC_FSPACE_SINFO); + fspace = sinfo->fspace; + HDassert(fspace->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(fspace->cache_info.type == H5AC_FSPACE_HDR); + HDassert(fspace->cache_info.is_pinned); - /* Reset the dirty flag. */ - sinfo->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5FS_cache_sinfo_dest(f, sinfo) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space section info") + /* Destroy free space info */ + if(H5FS_sinfo_dest(sinfo) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space info") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5FS_cache_sinfo_clear() */ +} /* end H5FS__cache_sinfo_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5FS_cache_sinfo_notify + * Function: H5FS__sinfo_serialize_sect_cb * - * Purpose: Handle cache action notifications + * Purpose: Skip list iterator callback to serialize free space sections + * of a particular size * - * Return: SUCCEED/FAIL + * Return: Non-negative on success/Negative on failure * - * Programmer: Dana Robinson - * Fall 2012 + * Programmer: Quincey Koziol + * Monday, May 8, 2006 * *------------------------------------------------------------------------- */ -herr_t -H5FS_cache_sinfo_notify(H5AC_notify_action_t action, H5FS_sinfo_t *sinfo) +static herr_t +H5FS__sinfo_serialize_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata) { + H5FS_section_class_t *sect_cls; /* Class of section */ + H5FS_section_info_t *sect= (H5FS_section_info_t *)_item; /* Free space section to work on */ + H5FS_iter_ud_t *udata = (H5FS_iter_ud_t *)_udata; /* Callback info */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT - - /* Sanity check */ - HDassert(sinfo); + FUNC_ENTER_STATIC - /* Check if the file was opened with SWMR-write access */ - if(sinfo->fspace->swmr_write) { - /* Determine which action to take */ - switch(action) { - case H5AC_NOTIFY_ACTION_AFTER_INSERT: - /* Create flush dependency on extensible array header */ - if(H5FS__create_flush_depend((H5AC_info_t *)sinfo->fspace, (H5AC_info_t *)sinfo) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency between data block and header, address = %llu", (unsigned long long)sinfo->fspace->sect_addr) - break; + /* Check arguments. */ + HDassert(sect); + HDassert(udata->sinfo); + HDassert(udata->image); - case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ - break; + /* Get section's class */ + sect_cls = &udata->sinfo->fspace->sect_cls[sect->type]; - default: -#ifdef NDEBUG - HGOTO_ERROR(H5E_FSPACE, H5E_BADVALUE, FAIL, "unknown action from metadata cache") -#else /* NDEBUG */ - HDassert(0 && "Unknown action?!?"); -#endif /* NDEBUG */ - } /* end switch */ + /* Check if this section should be serialized (i.e. is not a ghost section) */ + if(!(sect_cls->flags & H5FS_CLS_GHOST_OBJ)) { + /* The address of the section */ + UINT64ENCODE_VAR(*udata->image, sect->addr, udata->sinfo->sect_off_size); + + /* The type of this section */ + *(*udata->image)++ = (uint8_t)sect->type; + + /* Call 'serialize' callback for this section */ + if(sect_cls->serialize) { + if((*sect_cls->serialize)(sect_cls, sect, *udata->image) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_CANTSERIALIZE, FAIL, "can't syncronize section") + + /* Update offset in serialization buffer */ + (*udata->image) += sect_cls->serial_size; + } /* end if */ + else + HDassert(sect_cls->serial_size == 0); } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5FS_cache_sinfo_notify() */ +} /* H5FS__sinfo_serialize_sect_cb() */ /*------------------------------------------------------------------------- - * Function: H5FS_cache_sinfo_size + * Function: H5FS__sinfo_serialize_node_cb * - * Purpose: Compute the size in bytes of a free space section info - * on disk, and return it in *size_ptr. + * Purpose: Skip list iterator callback to serialize free space sections + * in a bin * - * Return: SUCCEED (Can't fail) + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * July 31 2006 + * Programmer: Quincey Koziol + * Monday, May 8, 2006 * *------------------------------------------------------------------------- */ static herr_t -H5FS_cache_sinfo_size(const H5F_t H5_ATTR_UNUSED *f, const H5FS_sinfo_t *sinfo, size_t *size_ptr) +H5FS__sinfo_serialize_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + H5FS_node_t *fspace_node = (H5FS_node_t *)_item; /* Free space size node to work on */ + H5FS_iter_ud_t *udata = (H5FS_iter_ud_t *)_udata; /* Callback info */ + herr_t ret_value = SUCCEED; /* Return value */ - /* check arguments */ - HDassert(sinfo); - HDassert(size_ptr); + FUNC_ENTER_STATIC - /* Set size value */ - H5_CHECKED_ASSIGN(*size_ptr, size_t, sinfo->fspace->alloc_sect_size, hsize_t); + /* Check arguments. */ + HDassert(fspace_node); + HDassert(udata->sinfo); + HDassert(udata->image); - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5FS_cache_sinfo_size() */ + /* Check if this node has any serializable sections */ + if(fspace_node->serial_count > 0) { + /* The number of serializable sections of this node's size */ + UINT64ENCODE_VAR(*udata->image, fspace_node->serial_count, udata->sect_cnt_size); + + /* The size of the sections for this node */ + UINT64ENCODE_VAR(*udata->image, fspace_node->sect_size, udata->sinfo->sect_len_size); + /* Iterate through all the sections of this size */ + HDassert(fspace_node->sect_list); + if(H5SL_iterate(fspace_node->sect_list, H5FS__sinfo_serialize_sect_cb, udata) < 0) + HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section nodes") + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FS__sinfo_serialize_node_cb() */ diff --git a/src/H5FSdbg.c b/src/H5FSdbg.c index 11a2232..4599b52 100644 --- a/src/H5FSdbg.c +++ b/src/H5FSdbg.c @@ -116,7 +116,7 @@ H5FS_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int /* * Load the free space header. */ - if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, addr, &cache_udata, H5AC_READ))) + if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, FAIL, "unable to load free space header") /* Print opening message */ @@ -256,7 +256,7 @@ H5FS_sects_debug(H5F_t *f, hid_t dxpl_id, haddr_t H5_ATTR_UNUSED addr, FILE *str /* * Load the free space header. */ - if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC_READ))) + if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, FAIL, "unable to load free space header") /* Retrieve the client id */ diff --git a/src/H5FSpkg.h b/src/H5FSpkg.h index 70c83f0..62da2e3 100644 --- a/src/H5FSpkg.h +++ b/src/H5FSpkg.h @@ -183,7 +183,9 @@ struct H5FS_t { unsigned sinfo_lock_count; /* # of times the section info has been locked */ hbool_t sinfo_protected; /* Whether the section info was protected when locked */ hbool_t sinfo_modified; /* Whether the section info has been modified while locked */ - H5AC_protect_t sinfo_accmode; /* Access mode for protecting the section info */ + unsigned sinfo_accmode; /* Access mode for protecting the section info */ + /* must be either H5C__NO_FLAGS_SET (i.e r/w) */ + /* or H5AC__READ_ONLY_FLAG (i.e. r/o). */ size_t max_cls_serial_size; /* Max. additional size of serialized form of section */ hsize_t threshold; /* Threshold for alignment */ hsize_t alignment; /* Alignment */ diff --git a/src/H5FSsection.c b/src/H5FSsection.c index 5bd4d95..7fb1944 100644 --- a/src/H5FSsection.c +++ b/src/H5FSsection.c @@ -203,7 +203,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5FS_sinfo_lock(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5AC_protect_t accmode) +H5FS_sinfo_lock(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, unsigned accmode) { H5FS_sinfo_cache_ud_t cache_udata; /* User-data for cache callback */ herr_t ret_value = SUCCEED; /* Return value */ @@ -219,14 +219,21 @@ HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu, fspace->sect_size = %Hu\n" HDassert(f); HDassert(fspace); + /* only H5AC__READ_ONLY_FLAG may appear in accmode */ + HDassert((accmode & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* If the free space header doesn't already "own" the section info, load * section info or create it */ if(fspace->sinfo) { /* Check if the section info was protected & we want a different access mode */ + + /* only H5AC__READ_ONLY_FLAG may appear in fspace->sinfo_accmode */ + HDassert(((fspace->sinfo_accmode) & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + if(fspace->sinfo_protected && accmode != fspace->sinfo_accmode) { /* Check if we need to switch from read-only access to read-write */ - if(H5AC_WRITE == accmode) { + if(0 == (accmode & (unsigned)(~H5AC__READ_ONLY_FLAG))) { /* Unprotect the read-only section info */ if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space section info") @@ -235,11 +242,11 @@ HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu, fspace->sect_size = %Hu\n" cache_udata.f = f; cache_udata.dxpl_id = dxpl_id; cache_udata.fspace = fspace; - if(NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, &cache_udata, H5AC_WRITE))) + if(NULL == (fspace->sinfo = (H5FS_sinfo_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to load free space sections") /* Switch the access mode we have */ - fspace->sinfo_accmode = H5AC_WRITE; + fspace->sinfo_accmode = H5AC__NO_FLAGS_SET; } /* end if */ } /* end if */ } /* end if */ @@ -329,7 +336,7 @@ HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu, fspace->sect_size = %Hu\n" /* Check if we modified any section */ if(modified) { /* Check if the section info was protected with a different access mode */ - if(fspace->sinfo_protected && fspace->sinfo_accmode != H5AC_WRITE) + if(fspace->sinfo_protected && (0 != ((fspace->sinfo_accmode) & H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTDIRTY, FAIL, "attempt to modify read-only section info") /* If we modified the section info, mark it dirty */ @@ -903,7 +910,7 @@ H5FS_sect_remove(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, HDassert(sect); /* Get a pointer to the section info */ - if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC_WRITE) < 0) + if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info") sinfo_valid = TRUE; @@ -1369,7 +1376,7 @@ HDfprintf(stderr, "%s: *sect = {%a, %Hu, %u, %s}\n", FUNC, sect->addr, sect->siz HDassert(sect->size); /* Get a pointer to the section info */ - if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC_WRITE) < 0) + if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info") sinfo_valid = TRUE; @@ -1466,7 +1473,7 @@ HDfprintf(stderr, "%s: fspace->ghost_sect_count = %Hu\n", FUNC, fspace->ghost_se H5FS_section_info_t *sect; /* Temporary free space section */ /* Get a pointer to the section info */ - if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC_WRITE) < 0) + if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info") sinfo_valid = TRUE; @@ -1586,7 +1593,7 @@ H5FS_sect_try_merge(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5FS_section_info_t HDassert(sect->size); /* Get a pointer to the section info */ - if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC_WRITE) < 0) + if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info") sinfo_valid = TRUE; saved_fs_size = sect->size; @@ -1809,7 +1816,7 @@ HDfprintf(stderr, "%s: fspace->ghost_sect_count = %Hu\n", FUNC, fspace->ghost_se #endif /* QAK */ if(fspace->tot_sect_count > 0) { /* Get a pointer to the section info */ - if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC_WRITE) < 0) + if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info") sinfo_valid = TRUE; @@ -1951,7 +1958,7 @@ HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu\n", FUNC, fspace->tot_sect_c unsigned bin; /* Current bin we are on */ /* Get a pointer to the section info */ - if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC_READ) < 0) + if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__READ_ONLY_FLAG) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info") sinfo_valid = TRUE; @@ -2040,7 +2047,7 @@ H5FS_sect_change_class(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, HDassert(new_class < fspace->nclasses); /* Get a pointer to the section info */ - if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC_WRITE) < 0) + if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info") sinfo_valid = TRUE; @@ -2353,7 +2360,7 @@ H5FS_sect_try_shrink_eoa(const H5F_t *f, hid_t dxpl_id, const H5FS_t *fspace, vo /* Check arguments. */ HDassert(fspace); - if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC_WRITE) < 0) + if(H5FS_sinfo_lock(f, dxpl_id, fspace, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info") sinfo_valid = TRUE; diff --git a/src/H5Fint.c b/src/H5Fint.c index 61c0eee..3410036 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -886,6 +886,14 @@ H5F_dest(H5F_t *f, hid_t dxpl_id, hbool_t flush) } } /* end if */ + /* if it exists, unpin the driver information block cache entry, + * since we're about to destroy the cache + */ + if(f->shared->drvinfo) + if(H5AC_unpin_entry(f->shared->drvinfo) < 0) + /* Push error, but keep going*/ + HDONE_ERROR(H5E_FSPACE, H5E_CANTUNPIN, FAIL, "unable to unpin drvinfo") + /* Unpin the superblock, since we're about to destroy the cache */ if(H5AC_unpin_entry(f->shared->sblock) < 0) /* Push error, but keep going*/ diff --git a/src/H5Fio.c b/src/H5Fio.c index fafe5e8..b7e925e 100644 --- a/src/H5Fio.c +++ b/src/H5Fio.c @@ -209,9 +209,10 @@ H5F_flush_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id) if(NULL == (fio_info.dxpl = (H5P_genplist_t *)H5I_object(dxpl_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list") - /* Flush out the metadata accumulator */ - if(H5F__accum_flush(&fio_info) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush metadata accumulator") + + /* Flush and reset the accumulator */ + if(H5F__accum_reset(&fio_info, TRUE) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator") /* Flush file buffers to disk. */ if(H5FD_flush(f->shared->lf, dxpl_id, FALSE) < 0) @@ -414,4 +415,3 @@ H5F_read_check_metadata(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, done: FUNC_LEAVE_NOAPI(ret_value); } /* end H5F_read_check_metadata */ - diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index d2c43b5..18bc7ef 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -83,6 +83,21 @@ #define H5F_SUPERBLOCK_FIXED_SIZE ( H5F_SIGNATURE_LEN \ + 1) /* superblock version */ +/* The H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE is the minimal amount of super block + * variable length data guarnateed to load the sizeof offsets and the sizeof + * lengths fields in all versions of the superblock. + * + * This is necessary in the V3 cache, as on the initial load, we need to + * get enough of the superblock to determine its version and size so that + * the metadata cache can load the correct amount of data from file to + * allow the second deserialization attempt to succeed. + * + * The value selected will have to be revisited for each new version + * of the super block. Note that the current value is one byte larger + * than it needs to be. + */ +#define H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE 7 + /* Macros for computing variable-size superblock size */ #define H5F_SUPERBLOCK_VARLEN_SIZE_COMMON \ (2 /* freespace, and root group versions */ \ @@ -115,14 +130,14 @@ + (sizeof_addr) /* EOF address */ \ + (sizeof_addr) /* root group object header address */ \ + H5F_SIZEOF_CHKSUM) /* superblock checksum (keep this last) */ -#define H5F_SUPERBLOCK_VARLEN_SIZE(v, f) ( \ - (v == 0 ? H5F_SUPERBLOCK_VARLEN_SIZE_V0(H5F_SIZEOF_ADDR(f), H5F_SIZEOF_SIZE(f)) : 0) \ - + (v == 1 ? H5F_SUPERBLOCK_VARLEN_SIZE_V1(H5F_SIZEOF_ADDR(f), H5F_SIZEOF_SIZE(f)) : 0) \ - + (v == 2 ? H5F_SUPERBLOCK_VARLEN_SIZE_V2(H5F_SIZEOF_ADDR(f)) : 0)) +#define H5F_SUPERBLOCK_VARLEN_SIZE(v, sizeof_addr, sizeof_size) ( \ + (v == 0 ? H5F_SUPERBLOCK_VARLEN_SIZE_V0(sizeof_addr, sizeof_size) : 0) \ + + (v == 1 ? H5F_SUPERBLOCK_VARLEN_SIZE_V1(sizeof_addr, sizeof_size) : 0) \ + + (v == 2 ? H5F_SUPERBLOCK_VARLEN_SIZE_V2(sizeof_addr) : 0)) /* Total size of superblock, depends on superblock version */ -#define H5F_SUPERBLOCK_SIZE(v, f) ( H5F_SUPERBLOCK_FIXED_SIZE \ - + H5F_SUPERBLOCK_VARLEN_SIZE(v, f)) +#define H5F_SUPERBLOCK_SIZE(s) ( H5F_SUPERBLOCK_FIXED_SIZE \ + + H5F_SUPERBLOCK_VARLEN_SIZE((s)->super_vers, (s)->sizeof_addr, (s)->sizeof_size)) /* For superblock version 0 & 1: Offset to the file consistency flags (status_flags) in the superblock (excluding H5F_SUPERBLOCK_FIXED_SIZE) */ @@ -156,6 +171,26 @@ typedef struct H5F_super_ud_t { * H5Fefc.c) */ typedef struct H5F_efc_t H5F_efc_t; +/* Structure for passing 'user data' to superblock cache callbacks */ +typedef struct H5F_superblock_cache_ud_t { +/* IN: */ + H5F_t *f; /* Pointer to file */ + hbool_t ignore_drvrinfo; /* Indicate if the driver info should be ignored */ +/* OUT: */ + unsigned sym_leaf_k; /* Symbol table leaf node's 'K' value */ + unsigned btree_k[H5B_NUM_BTREE_ID]; /* B-tree key values for each type */ + haddr_t stored_eof; /* End-of-file in file */ + hbool_t drvrinfo_removed; /* Indicate if the driver info was removed */ + unsigned super_vers; /* Superblock version obtained in get_load_size callback. + * It will be used later in verify_chksum callback + */ +} H5F_superblock_cache_ud_t; + +typedef struct H5F_drvrinfo_cache_ud_t { + H5F_t *f; /* Pointer to file */ + haddr_t driver_addr; /* address of driver info block */ +} H5F_drvrinfo_cache_ud_t; + /* Structure for metadata & "small [raw] data" block aggregation fields */ struct H5F_blk_aggr_t { unsigned long feature_flag; /* Feature flag type */ @@ -205,6 +240,8 @@ typedef struct H5F_mtab_t { typedef struct H5F_super_t { H5AC_info_t cache_info; /* Cache entry information structure */ unsigned super_vers; /* Superblock version */ + uint8_t sizeof_addr; /* Size of addresses in file */ + uint8_t sizeof_size; /* Size of offsets in file */ uint8_t status_flags; /* File status flags */ unsigned sym_leaf_k; /* Size of leaves in symbol tables */ unsigned btree_k[H5B_NUM_BTREE_ID]; /* B-tree key values for each type */ @@ -226,6 +263,13 @@ typedef struct H5F_super_t { struct H5F_file_t { H5FD_t *lf; /* Lower level file handle for I/O */ H5F_super_t *sblock; /* Pointer to (pinned) superblock for file */ + H5O_drvinfo_t *drvinfo; /* Pointer to the (pinned) driver info + * cache entry. This field is only defined + * for older versions of the super block, + * and then only when a driver information + * block is present. At all other times + * it should be NULL. + */ unsigned nrefs; /* Ref count for times file is opened */ unsigned flags; /* Access Permissions for file */ H5F_mtab_t mtab; /* File mount table */ @@ -322,6 +366,7 @@ H5FL_EXTERN(H5F_t); H5FL_EXTERN(H5F_file_t); H5_DLLVAR const H5AC_class_t H5AC_SUPERBLOCK[1]; +H5_DLLVAR const H5AC_class_t H5AC_DRVRINFO[1]; /******************************/ diff --git a/src/H5Fsuper.c b/src/H5Fsuper.c index d5e378e..2ef6964 100644 --- a/src/H5Fsuper.c +++ b/src/H5Fsuper.c @@ -258,17 +258,20 @@ H5F__super_read(H5F_t *f, hid_t dxpl_id, hbool_t initial_read) { H5P_genplist_t *dxpl; /* DXPL object */ H5F_super_t * sblock = NULL; /* Superblock structure */ + H5F_superblock_cache_ud_t udata; /* User data for cache callbacks */ + H5P_genplist_t *c_plist; /* File creation property list */ unsigned sblock_flags = H5AC__NO_FLAGS_SET; /* flags used in superblock unprotect call */ - haddr_t super_addr; /* Absolute address of superblock */ - H5AC_protect_t rw; /* read/write permissions for file */ - H5F_super_ud_t udata; /* User data passed to sblock protect */ - herr_t ret_value = SUCCEED; /* return value */ + haddr_t super_addr; /* Absolute address of superblock */ + haddr_t eof; /* End of file address */ + unsigned rw_flags; /* Read/write permissions for file */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE_TAG(dxpl_id, H5AC__SUPERBLOCK_TAG, FAIL) - udata.dirtied = FALSE; /* Boolean (dirtied or not ) for sblock protect call */ - udata.initial_read = initial_read; /* Indicate superblock read for initial file open: */ - /* whether to skip the check for truncated file in H5F_sblock_load() */ + /* initialize the drvinfo to NULL -- we will overwrite this if there + * is a driver information block + */ + f->shared->drvinfo = NULL; /* Get the DXPL plist object for DXPL ID */ if(NULL == (dxpl = (H5P_genplist_t *)H5I_object(dxpl_id))) @@ -288,23 +291,374 @@ H5F__super_read(H5F_t *f, hid_t dxpl_id, hbool_t initial_read) } /* end if */ /* Determine file intent for superblock protect */ - if(H5F_INTENT(f) & H5F_ACC_RDWR) - rw = H5AC_WRITE; - else - rw = H5AC_READ; + + /* Must tell cache at protect time that the super block is to be + * flushed last (and collectively in the parallel case). + */ + rw_flags = H5AC__FLUSH_LAST_FLAG; +#ifdef H5_HAVE_PARALLEL + rw_flags |= H5C__FLUSH_COLLECTIVELY_FLAG; +#endif /* H5_HAVE_PARALLEL */ + if(!(H5F_INTENT(f) & H5F_ACC_RDWR)) + rw_flags |= H5AC__READ_ONLY_FLAG; + + /* Get the shared file creation property list */ + if(NULL == (c_plist = (H5P_genplist_t *)H5I_object(f->shared->fcpl_id))) + HGOTO_ERROR(H5E_FILE, H5E_BADTYPE, FAIL, "can't get property list") + + /* Make certain we can read the fixed-size portion of the superblock */ + if(H5F__set_eoa(f, H5FD_MEM_SUPER, + (haddr_t)(H5F_SUPERBLOCK_FIXED_SIZE + H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "set end of space allocation request failed") + + /* Set up the user data for cache callbacks */ + udata.f = f; + udata.ignore_drvrinfo = H5F_HAS_FEATURE(f, H5FD_FEAT_IGNORE_DRVRINFO); + udata.sym_leaf_k = 0; + if(H5P_get(c_plist, H5F_CRT_BTREE_RANK_NAME, udata.btree_k) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get rank for btree internal nodes") + udata.stored_eof = HADDR_UNDEF; + udata.drvrinfo_removed = FALSE; /* Look up the superblock */ - if(NULL == (sblock = (H5F_super_t *)H5AC_protect(f, dxpl_id, H5AC_SUPERBLOCK, (haddr_t)0, &udata, rw))) + if(NULL == (sblock = (H5F_super_t *)H5AC_protect(f, dxpl_id, H5AC_SUPERBLOCK, (haddr_t)0, &udata, rw_flags))) HGOTO_ERROR(H5E_FILE, H5E_CANTPROTECT, FAIL, "unable to load superblock") - /* Mark the superblock dirty if it was modified during loading or VFD indicated to do so */ - if((H5AC_WRITE == rw) && (udata.dirtied || H5F_HAS_FEATURE(f, H5FD_FEAT_DIRTY_SBLK_LOAD))) - sblock_flags |= H5AC__DIRTIED_FLAG; - /* Pin the superblock in the cache */ if(H5AC_pin_protected_entry(sblock) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTPIN, FAIL, "unable to pin superblock") + /* Mark the superblock dirty if it was modified during loading */ + if(((rw_flags & H5AC__READ_ONLY_FLAG) == 0) && udata.ignore_drvrinfo && udata.drvrinfo_removed) { + HDassert(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2); + sblock_flags |= H5AC__DIRTIED_FLAG; + } /* end if */ + + /* The superblock must be flushed last (and collectively in parallel) */ + sblock_flags |= H5AC__FLUSH_LAST_FLAG; +#ifdef H5_HAVE_PARALLEL + sblock_flags |= H5AC__FLUSH_COLLECTIVELY_FLAG; +#endif /* H5_HAVE_PARALLEL */ + + /* Check if superblock address is different from base address and adjust + * base address and "end of address" address if so. + */ + if(!H5F_addr_eq(super_addr, sblock->base_addr)) { + /* Check if the superblock moved earlier in the file */ + if(H5F_addr_lt(super_addr, sblock->base_addr)) + udata.stored_eof -= (sblock->base_addr - super_addr); + else + /* The superblock moved later in the file */ + udata.stored_eof += (super_addr - sblock->base_addr); + + /* Adjust base address for offsets of the HDF5 data in the file */ + sblock->base_addr = super_addr; + + /* Set the base address for the file in the VFD now */ + if(H5F__set_base_addr(f, sblock->base_addr) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "failed to set base address for file driver") + + /* Indicate that the superblock should be marked dirty */ + if((rw_flags & H5AC__READ_ONLY_FLAG) == 0) + sblock_flags |= H5AC__DIRTIED_FLAG; + } /* end if */ + + /* Set information in the file's creation property list */ + if(H5P_set(c_plist, H5F_CRT_SUPER_VERS_NAME, &sblock->super_vers) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set superblock version") + if(H5P_set(c_plist, H5F_CRT_ADDR_BYTE_NUM_NAME, &sblock->sizeof_addr) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set byte number in an address") + if(H5P_set(c_plist, H5F_CRT_OBJ_BYTE_NUM_NAME, &sblock->sizeof_size) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set byte number for object size") + + /* Handle the B-tree 'K' values */ + if(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) { + /* Sanity check */ + HDassert(udata.sym_leaf_k != 0); + + /* Set the symbol table internal node 'K' value */ + if(H5P_set(c_plist, H5F_CRT_SYM_LEAF_NAME, &udata.sym_leaf_k) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set rank for symbol table leaf nodes") + sblock->sym_leaf_k = udata.sym_leaf_k; + + /* Set the B-tree internal node values, etc */ + if(H5P_set(c_plist, H5F_CRT_BTREE_RANK_NAME, udata.btree_k) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set rank for btree internal nodes") + HDmemcpy(sblock->btree_k, udata.btree_k, sizeof(unsigned) * (size_t)H5B_NUM_BTREE_ID); + } /* end if */ + else { + /* Get the (default) B-tree internal node values, etc */ + /* (Note: these may be reset in a superblock extension) */ + if(H5P_get(c_plist, H5F_CRT_BTREE_RANK_NAME, sblock->btree_k) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get rank for btree internal nodes") + if(H5P_get(c_plist, H5F_CRT_SYM_LEAF_NAME, &sblock->sym_leaf_k) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get rank for btree internal nodes") + } /* end else */ + + /* + * The user-defined data is the area of the file before the base + * address. + */ + if(H5P_set(c_plist, H5F_CRT_USER_BLOCK_NAME, &sblock->base_addr) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set userblock size") + + /* + * Make sure that the data is not truncated. One case where this is + * possible is if the first file of a family of files was opened + * individually. + */ + /* (This check can be skipped when the file is opened for SWMR read, + * as the file can appear truncated if only part of it has been + * been flushed to disk by the single writer process.) + */ + /* Can skip this test when it is not the initial file open-- + * H5F_super_read() call from H5F_evict_tagged_metadata() for + * refreshing object. + * When flushing file buffers and fractal heap is involved, + * the library will allocate actual space for tmp addresses + * via the file layer. The aggregator allocates a block, + * thus the eoa might be greater than eof. + * Note: the aggregator is changed again after being reset + * earlier before H5AC_flush due to allocation of tmp addresses. + */ + if (!(H5F_INTENT(f) & H5F_ACC_SWMR_READ) && initial_read) { + if(HADDR_UNDEF == (eof = H5FD_get_eof(f->shared->lf, H5FD_MEM_DEFAULT))) + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to determine file size") + + /* (Account for the stored EOA being absolute offset -QAK) */ + if((eof + sblock->base_addr) < udata.stored_eof) + HGOTO_ERROR(H5E_FILE, H5E_TRUNCATED, FAIL, "truncated file: eof = %llu, sblock->base_addr = %llu, stored_eof = %llu", (unsigned long long)eof, (unsigned long long)sblock->base_addr, (unsigned long long)udata.stored_eof) + } /* end if */ + + /* + * Tell the file driver how much address space has already been + * allocated so that it knows how to allocate additional memory. + */ + + /* Decode the optional driver information block */ + if(H5F_addr_defined(sblock->driver_addr)) { + H5O_drvinfo_t *drvinfo; /* Driver info */ + H5F_drvrinfo_cache_ud_t drvrinfo_udata; /* User data for metadata callbacks */ + unsigned drvinfo_flags = H5AC__NO_FLAGS_SET; /* Flags used in driver info block unprotect call */ + + /* Sanity check - driver info block should only be defined for + * superblock version < 2. + */ + HDassert(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2); + + /* Set up user data */ + drvrinfo_udata.f = f; + drvrinfo_udata.driver_addr = sblock->driver_addr; + + /* extend EOA so we can read at least the fixed sized + * portion of the driver info block + */ + if(H5FD_set_eoa(f->shared->lf, H5FD_MEM_SUPER, sblock->driver_addr + H5F_DRVINFOBLOCK_HDR_SIZE) < 0) /* will extend eoa later if required */ + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, \ + "set end of space allocation request failed") + + /* Look up the driver info block */ + if(NULL == (drvinfo = (H5O_drvinfo_t *)H5AC_protect(f, dxpl_id, H5AC_DRVRINFO, sblock->driver_addr, &drvrinfo_udata, rw_flags))) + HGOTO_ERROR(H5E_FILE, H5E_CANTPROTECT, FAIL, "unable to load driver info block") + + /* Loading the driver info block is enough to set up the right info */ + + /* Check if we need to rewrite the driver info block info */ + if ( ( (rw_flags & H5AC__READ_ONLY_FLAG) == 0 ) && + ( H5F_HAS_FEATURE(f, H5FD_FEAT_DIRTY_DRVRINFO_LOAD) ) ) { + + drvinfo_flags |= H5AC__DIRTIED_FLAG; + } /* end if */ + + /* set the pin entry flag so that the driver information block + * cache entry will be pinned in the cache. + */ + drvinfo_flags |= H5AC__PIN_ENTRY_FLAG; + + /* Release the driver info block */ + if(H5AC_unprotect(f, dxpl_id, H5AC_DRVRINFO, sblock->driver_addr, drvinfo, drvinfo_flags) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTUNPROTECT, FAIL, "unable to release driver info block") + + /* save a pointer to the driver information cache entry */ + f->shared->drvinfo = drvinfo; + } /* end if */ + + /* (Account for the stored EOA being absolute offset -NAF) */ + if(H5F__set_eoa(f, H5FD_MEM_SUPER, udata.stored_eof - sblock->base_addr) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set end-of-address marker for file") + + /* Decode the optional superblock extension info */ + if(H5F_addr_defined(sblock->ext_addr)) { + H5O_loc_t ext_loc; /* "Object location" for superblock extension */ + H5O_btreek_t btreek; /* v1 B-tree 'K' value message from superblock extension */ + H5O_drvinfo_t drvinfo; /* Driver info message from superblock extension */ + size_t u; /* Local index variable */ + htri_t status; /* Status for message existing */ + + /* Sanity check - superblock extension should only be defined for + * superblock version >= 2. + */ + HDassert(sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2); + + /* Check for superblock extension being located "outside" the stored + * 'eoa' value, which can occur with the split/multi VFD. + */ + if(H5F_addr_gt(sblock->ext_addr, udata.stored_eof)) { + /* Set the 'eoa' for the object header memory type large enough + * to give some room for a reasonably sized superblock extension. + * (This is _rather_ a kludge -QAK) + */ + if(H5F__set_eoa(f, H5FD_MEM_OHDR, (haddr_t)(sblock->ext_addr + 1024)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set end-of-address marker for file") + } /* end if */ + + /* Open the superblock extension */ + if(H5F_super_ext_open(f, sblock->ext_addr, &ext_loc) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENOBJ, FAIL, "unable to open file's superblock extension") + + /* Check for the extension having a 'driver info' message */ + if((status = H5O_msg_exists(&ext_loc, H5O_DRVINFO_ID, dxpl_id)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_EXISTS, FAIL, "unable to read object header") + if(status) { + /* Check for ignoring the driver info for this file */ + if(!udata.ignore_drvrinfo) { + + /* Retrieve the 'driver info' structure */ + if(NULL == H5O_msg_read(&ext_loc, H5O_DRVINFO_ID, &drvinfo, dxpl_id)) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "driver info message not present") + + /* Validate and decode driver information */ + if(H5FD_sb_load(f->shared->lf, drvinfo.name, drvinfo.buf) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, FAIL, "unable to decode driver information") + + /* Reset driver info message */ + H5O_msg_reset(H5O_DRVINFO_ID, &drvinfo); + } /* end else */ + } /* end if */ + + /* Read in the shared OH message information if there is any */ + if(H5SM_get_info(&ext_loc, c_plist, dxpl_id) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to read SOHM table information") + + /* Check for the extension having a 'v1 B-tree "K"' message */ + if((status = H5O_msg_exists(&ext_loc, H5O_BTREEK_ID, dxpl_id)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_EXISTS, FAIL, "unable to read object header") + if(status) { + /* Retrieve the 'v1 B-tree "K"' structure */ + if(NULL == H5O_msg_read(&ext_loc, H5O_BTREEK_ID, &btreek, dxpl_id)) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "v1 B-tree 'K' info message not present") + + /* Set non-default v1 B-tree 'K' value info from file */ + sblock->btree_k[H5B_CHUNK_ID] = btreek.btree_k[H5B_CHUNK_ID]; + sblock->btree_k[H5B_SNODE_ID] = btreek.btree_k[H5B_SNODE_ID]; + sblock->sym_leaf_k = btreek.sym_leaf_k; + + /* Set non-default v1 B-tree 'K' values in the property list */ + if(H5P_set(c_plist, H5F_CRT_BTREE_RANK_NAME, btreek.btree_k) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set rank for btree internal nodes") + if(H5P_set(c_plist, H5F_CRT_SYM_LEAF_NAME, &btreek.sym_leaf_k) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set rank for symbol table leaf nodes") + } /* end if */ + + /* Check for the extension having a 'free-space manager info' message */ + if((status = H5O_msg_exists(&ext_loc, H5O_FSINFO_ID, dxpl_id)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_EXISTS, FAIL, "unable to read object header") + if(status) { + H5O_fsinfo_t fsinfo; /* Free-space manager info message from superblock extension */ + + /* Retrieve the 'free-space manager info' structure */ + if(NULL == H5O_msg_read(&ext_loc, H5O_FSINFO_ID, &fsinfo, dxpl_id)) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get free-space manager info message") + + /* Check for non-default info */ + if(f->shared->fs_strategy != fsinfo.strategy) { + f->shared->fs_strategy = fsinfo.strategy; + + /* Set non-default strategy in the property list */ + if(H5P_set(c_plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, &fsinfo.strategy) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set file space strategy") + } /* end if */ + if(f->shared->fs_threshold != fsinfo.threshold) { + f->shared->fs_threshold = fsinfo.threshold; + + /* Set non-default threshold in the property list */ + if(H5P_set(c_plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, &fsinfo.threshold) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "unable to set file space strategy") + } /* end if */ + + /* Set free-space manager addresses */ + f->shared->fs_addr[0] = HADDR_UNDEF; + for(u = 1; u < NELMTS(f->shared->fs_addr); u++) + f->shared->fs_addr[u] = fsinfo.fs_addr[u-1]; + } /* end if */ + + /* Close superblock extension */ + if(H5F_super_ext_close(f, &ext_loc, dxpl_id, FALSE) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close file's superblock extension") + } /* end if */ + + /* Update the driver info if VFD indicated to do so */ + /* (NOTE: only for later versions of superblock, earlier versions are handled + * earlier in this routine. + */ + if(((rw_flags & H5AC__READ_ONLY_FLAG) == 0) && + sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2 && + H5F_addr_defined(sblock->ext_addr)) { + /* Check for modifying the driver info when opening the file */ + if(H5F_HAS_FEATURE(f, H5FD_FEAT_DIRTY_DRVRINFO_LOAD)) { + size_t driver_size; /* Size of driver info block (bytes) */ + + /* Check for driver info message */ + H5_CHECKED_ASSIGN(driver_size, size_t, H5FD_sb_size(f->shared->lf), hsize_t); + if(driver_size > 0) { + H5O_drvinfo_t drvinfo; /* Driver info */ + uint8_t dbuf[H5F_MAX_DRVINFOBLOCK_SIZE]; /* Driver info block encoding buffer */ + + /* Sanity check */ + HDassert(driver_size <= H5F_MAX_DRVINFOBLOCK_SIZE); + + /* Encode driver-specific data */ + if(H5FD_sb_encode(f->shared->lf, drvinfo.name, dbuf) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode driver information") + + /* Set the driver info information for the superblock extension */ + drvinfo.len = driver_size; + drvinfo.buf = dbuf; + + /* Write driver info information to the superblock extension */ + +#if 1 /* bug fix test code -- tidy this up if all goes well */ /* JRM */ + /* KLUGE ALERT!! + * + * H5F_super_ext_write_msg() expects f->shared->sblock to + * be set -- verify that it is NULL, and then set it. + * Set it back to NULL when we are done. + */ + HDassert(f->shared->sblock == NULL); + f->shared->sblock = sblock; +#endif /* JRM */ + + if(H5F_super_ext_write_msg(f, dxpl_id, &drvinfo, H5O_DRVINFO_ID, FALSE) < 0) + HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "error in writing message to superblock extension") + +#if 1 /* bug fix test code -- tidy this up if all goes well */ /* JRM */ + f->shared->sblock = NULL; +#endif /* JRM */ + + } /* end if */ + } /* end if */ + /* Check for eliminating the driver info block */ + else if(H5F_HAS_FEATURE(f, H5FD_FEAT_IGNORE_DRVRINFO)) { + /* Remove the driver info message from the superblock extension */ + if(H5F_super_ext_remove_msg(f, dxpl_id, H5O_DRVINFO_ID) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "error in removing message from superblock extension") + + /* Check if the superblock extension was removed */ + if(!H5F_addr_defined(sblock->ext_addr)) + sblock_flags |= H5AC__DIRTIED_FLAG; + } /* end if */ + } /* end if */ + /* Set the pointer to the pinned superblock */ f->shared->sblock = sblock; @@ -313,6 +667,32 @@ done: if(sblock && H5AC_unprotect(f, dxpl_id, H5AC_SUPERBLOCK, (haddr_t)0, sblock, sblock_flags) < 0) HDONE_ERROR(H5E_FILE, H5E_CANTUNPROTECT, FAIL, "unable to close superblock") + /* If we have failed, make sure no entries are left in the + * metadata cache, so that it can be shut down and discarded. + */ + if(ret_value < 0) { + /* Unpin and discard drvinfo cache entry */ + if(f->shared->drvinfo) { + if(H5AC_unpin_entry(f->shared->drvinfo) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTUNPIN, FAIL, "unable to unpin driver info") + + /* Evict the driver info block from the cache */ + if(H5AC_expunge_entry(f, dxpl_id, H5AC_DRVRINFO, sblock->driver_addr, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTEXPUNGE, FAIL, "unable to expunge driver info block") + } /* end if */ + + /* Unpin & discard superblock */ + if(sblock) { + /* Unpin superblock in cache */ + if(H5AC_unpin_entry(sblock) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTUNPIN, FAIL, "unable to unpin superblock") + + /* Evict the superblock from the cache */ + if(H5AC_expunge_entry(f, dxpl_id, H5AC_SUPERBLOCK, (haddr_t)0, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTEXPUNGE, FAIL, "unable to expunge superblock") + } /* end if */ + } /* end if */ + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) } /* end H5F__super_read() */ @@ -338,6 +718,8 @@ H5F__super_init(H5F_t *f, hid_t dxpl_id) { H5F_super_t *sblock = NULL; /* Superblock cache structure */ hbool_t sblock_in_cache = FALSE; /* Whether the superblock has been inserted into the metadata cache */ + H5O_drvinfo_t *drvinfo = NULL; /* Driver info */ + hbool_t drvinfo_in_cache = FALSE; /* Whether the driver info block has been inserted into the metadata cache */ H5P_genplist_t *plist; /* File creation property list */ hsize_t userblock_size; /* Size of userblock, in bytes */ hsize_t superblock_size; /* Size of superblock, in bytes */ @@ -431,11 +813,13 @@ H5F__super_init(H5F_t *f, hid_t dxpl_id) if(H5F__set_base_addr(f, sblock->base_addr) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "failed to set base address for file driver") - /* Save a local copy of the superblock version number */ + /* Save a local copy of the superblock version number, size of addresses & offsets */ sblock->super_vers = super_vers; + sblock->sizeof_addr = f->shared->sizeof_addr; + sblock->sizeof_size = f->shared->sizeof_size; /* Compute the size of the superblock */ - superblock_size = (hsize_t)H5F_SUPERBLOCK_SIZE(super_vers, f); + superblock_size = (hsize_t)H5F_SUPERBLOCK_SIZE(sblock); /* Compute the size of the driver information block */ H5_CHECKED_ASSIGN(driver_size, size_t, H5FD_sb_size(f->shared->lf), hsize_t); @@ -450,10 +834,10 @@ H5F__super_init(H5F_t *f, hid_t dxpl_id) } /* end if */ /* - * Allocate space for the userblock, superblock & driver info blocks. - * We do it with one allocation request because the userblock and - * superblock need to be at the beginning of the file and only the first - * allocation request is required to return memory at format address zero. + * Allocate space for the superblock & driver info block. + * We do it with one allocation request because the superblock needs to be + * at the beginning of the file and only the first allocation request is + * required to return memory at format address zero. */ if(super_vers < HDF5_SUPERBLOCK_VERSION_2) superblock_size += driver_size; @@ -470,6 +854,9 @@ H5F__super_init(H5F_t *f, hid_t dxpl_id) /* Keep a copy of the superblock info */ f->shared->sblock = sblock; + /* set the drvinfo filed to NULL -- will overwrite this later if needed */ + f->shared->drvinfo = NULL; + /* * Determine if we will need a superblock extension */ @@ -543,20 +930,20 @@ H5F__super_init(H5F_t *f, hid_t dxpl_id) /* Check for driver info to store */ if(driver_size > 0) { - H5O_drvinfo_t drvinfo; /* Driver info */ + H5O_drvinfo_t t_drvinfo; /* Driver info */ uint8_t dbuf[H5F_MAX_DRVINFOBLOCK_SIZE]; /* Driver info block encoding buffer */ /* Sanity check */ HDassert(driver_size <= H5F_MAX_DRVINFOBLOCK_SIZE); /* Encode driver-specific data */ - if(H5FD_sb_encode(f->shared->lf, drvinfo.name, dbuf) < 0) + if(H5FD_sb_encode(f->shared->lf, t_drvinfo.name, dbuf) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode driver information") /* Write driver info information to the superblock extension */ - drvinfo.len = driver_size; - drvinfo.buf = dbuf; - if(H5O_msg_create(&ext_loc, H5O_DRVINFO_ID, H5O_MSG_FLAG_DONTSHARE, H5O_UPDATE_TIME, &drvinfo, dxpl_id) < 0) + t_drvinfo.len = driver_size; + t_drvinfo.buf = dbuf; + if(H5O_msg_create(&ext_loc, H5O_DRVINFO_ID, H5O_MSG_FLAG_DONTSHARE, H5O_UPDATE_TIME, &t_drvinfo, dxpl_id) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to update driver info header message") } /* end if */ @@ -576,6 +963,33 @@ H5F__super_init(H5F_t *f, hid_t dxpl_id) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to update free-space info header message") } /* end if */ } /* end if */ + else { + /* Check for creating an "old-style" driver info block */ + if(driver_size > 0) { + /* Sanity check */ + HDassert(H5F_addr_defined(sblock->driver_addr)); + + /* Allocate space for the driver info */ + if(NULL == (drvinfo = (H5O_drvinfo_t *)H5MM_calloc(sizeof(H5O_drvinfo_t)))) + HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "memory allocation failed for driver info message") + + /* Set up driver info message */ + /* (NOTE: All the actual information (name & driver information) is + * actually based on the VFD info in the file handle and + * will be encoded by the VFD's 'encode' callback, so it + * doesn't need to be set here. -QAK, 7/20/2013 + */ + H5_CHECKED_ASSIGN(drvinfo->len, size_t, H5FD_sb_size(f->shared->lf), hsize_t); + + /* Insert driver info block into cache */ + if(H5AC_insert_entry(f, dxpl_id, H5AC_DRVRINFO, sblock->driver_addr, drvinfo, H5AC__PIN_ENTRY_FLAG | H5AC__FLUSH_LAST_FLAG | H5AC__FLUSH_COLLECTIVELY_FLAG) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINS, FAIL, "can't add driver info block to cache") + drvinfo_in_cache = TRUE; + f->shared->drvinfo = drvinfo; + } /* end if */ + else + HDassert(!H5F_addr_defined(sblock->driver_addr)); + } /* end if */ done: /* Close superblock extension, if it was created */ @@ -584,6 +998,23 @@ done: /* Cleanup on failure */ if(ret_value < 0) { + /* Check if the driver info block has been allocated yet */ + if(drvinfo) { + /* Check if we've cached it already */ + if(drvinfo_in_cache) { + /* Unpin drvinfo in cache */ + if(H5AC_unpin_entry(drvinfo) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTUNPIN, FAIL, "unable to unpin driver info") + + /* Evict the driver info block from the cache */ + if(H5AC_expunge_entry(f, dxpl_id, H5AC_DRVRINFO, sblock->driver_addr, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTEXPUNGE, FAIL, "unable to expunge driver info block") + } /* end if */ + else + /* Free driver info block */ + H5MM_xfree(drvinfo); + } /* end if */ + /* Check if the superblock has been allocated yet */ if(sblock) { /* Check if we've cached it already */ @@ -639,6 +1070,14 @@ H5F_super_dirty(H5F_t *f) if(H5AC_mark_entry_dirty(f->shared->sblock) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty") + /* if the driver information block exists, mark it dirty as well + * so that the change in eoa will be reflected there as well if + * appropriate. + */ + if ( f->shared->drvinfo ) + if(H5AC_mark_entry_dirty(f->shared->drvinfo) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark drvinfo as dirty") + done: FUNC_LEAVE_NOAPI(ret_value) } /* H5F_super_dirty() */ @@ -702,7 +1141,7 @@ H5F__super_size(H5F_t *f, hid_t dxpl_id, hsize_t *super_size, hsize_t *super_ext /* Set the superblock size */ if(super_size) - *super_size = (hsize_t)H5F_SUPERBLOCK_SIZE(f->shared->sblock->super_vers, f); + *super_size = (hsize_t)H5F_SUPERBLOCK_SIZE(f->shared->sblock); /* Set the superblock extension size */ if(super_ext_size) { diff --git a/src/H5Fsuper_cache.c b/src/H5Fsuper_cache.c index ad0bdae..525597b 100644 --- a/src/H5Fsuper_cache.c +++ b/src/H5Fsuper_cache.c @@ -51,9 +51,6 @@ /* Local Macros */ /****************/ -/* Maximum size of super-block buffers */ -#define H5F_MAX_SUPERBLOCK_SIZE 134 - /******************/ /* Local Typedefs */ @@ -70,28 +67,77 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static H5F_super_t *H5F_sblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5F_sblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5F_super_t *sblock); -static herr_t H5F_sblock_dest(H5F_t *f, H5F_super_t * sblock); -static herr_t H5F_sblock_clear(H5F_t *f, H5F_super_t *sblock, hbool_t destroy); -static herr_t H5F_sblock_size(const H5F_t *f, const H5F_super_t *sblock, size_t *size_ptr); +static herr_t H5F__cache_superblock_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5F__cache_superblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5F__cache_superblock_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5F__cache_superblock_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5F__cache_superblock_pre_serialize(const H5F_t *f, + hid_t dxpl_id, void *thing, haddr_t addr, size_t len, + size_t compressed_len, haddr_t *new_addr, size_t *new_len, + size_t *new_compressed_len, unsigned *flags); +static herr_t H5F__cache_superblock_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5F__cache_superblock_free_icr(void *thing); + +static herr_t H5F__cache_drvrinfo_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static void *H5F__cache_drvrinfo_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5F__cache_drvrinfo_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5F__cache_drvrinfo_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5F__cache_drvrinfo_free_icr(void *thing); /*********************/ /* Package Variables */ /*********************/ -/* H5F inherits cache-like properties from H5AC */ +/* H5F superblock inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_SUPERBLOCK[1] = {{ - H5AC_SUPERBLOCK_ID, - (H5AC_load_func_t)H5F_sblock_load, - (H5AC_flush_func_t)H5F_sblock_flush, - (H5AC_dest_func_t)H5F_sblock_dest, - (H5AC_clear_func_t)H5F_sblock_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5F_sblock_size, + H5AC_SUPERBLOCK_ID, /* Metadata client ID */ + "Superblock", /* Metadata client name (for debugging) */ + H5FD_MEM_SUPER, /* File space memory type for client */ + H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ + H5F__cache_superblock_get_load_size,/* 'get_load_size' callback */ + H5F__cache_superblock_verify_chksum, /* 'verify_chksum' callback */ + H5F__cache_superblock_deserialize, /* 'deserialize' callback */ + H5F__cache_superblock_image_len, /* 'image_len' callback */ + H5F__cache_superblock_pre_serialize,/* 'pre_serialize' callback */ + H5F__cache_superblock_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5F__cache_superblock_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ +}}; + +/* H5F driver info block inherits cache-like properties from H5AC */ +const H5AC_class_t H5AC_DRVRINFO[1] = {{ + H5AC_DRVRINFO_ID, /* Metadata client ID */ + "Driver info block", /* Metadata client name (for debugging) */ + H5FD_MEM_SUPER, /* File space memory type for client */ + H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ + H5F__cache_drvrinfo_get_load_size, /* 'get_load_size' callback */ + NULL, /* 'verify_chksum' callback */ + H5F__cache_drvrinfo_deserialize, /* 'deserialize' callback */ + H5F__cache_drvrinfo_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5F__cache_drvrinfo_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5F__cache_drvrinfo_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; + /*****************************/ /* Library Private Variables */ /*****************************/ @@ -107,583 +153,565 @@ H5FL_EXTERN(H5F_super_t); /*------------------------------------------------------------------------- - * Function: H5F_sblock_load + * Function: H5F__cache_superblock_get_load_size * - * Purpose: Loads the superblock from the file, and deserializes - * its information into the H5F_super_t structure. + * Purpose: Compute the size of the data structure on disk. * - * Return: Success: SUCCEED - * Failure: NULL + * Return: Non-negative on success/Negative on failure * - * Programmer: Mike McGreevy - * mamcgree@hdfgroup.org - * April 8, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 17, 2013 * *------------------------------------------------------------------------- */ -static H5F_super_t * -H5F_sblock_load(H5F_t *f, hid_t dxpl_id, haddr_t H5_ATTR_UNUSED addr, void *_udata) +static herr_t +H5F__cache_superblock_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5F_super_t *sblock = NULL; /* File's superblock */ - haddr_t base_addr = HADDR_UNDEF; /* Base address of file */ - uint8_t sbuf[H5F_MAX_SUPERBLOCK_SIZE]; /* Buffer for superblock */ - H5P_genplist_t *dxpl; /* DXPL object */ - H5P_genplist_t *c_plist; /* File creation property list */ - H5F_file_t *shared; /* shared part of `file' */ - H5FD_t *lf; /* file driver part of `shared' */ - haddr_t stored_eof; /* stored end-of-file address in file */ - haddr_t eof; /* end of file address */ - uint8_t sizeof_addr; /* Size of offsets in the file (in bytes) */ - uint8_t sizeof_size; /* Size of lengths in the file (in bytes) */ - const size_t fixed_size = H5F_SUPERBLOCK_FIXED_SIZE; /*fixed sizeof superblock */ - size_t variable_size; /*variable sizeof superblock */ - uint8_t *p; /* Temporary pointer into encoding buffer */ - unsigned super_vers; /* Superblock version */ - H5F_super_ud_t *udata = (H5F_super_ud_t *)_udata; - unsigned tries, max_tries; /* The # of read attempts to try */ - unsigned retries; /* The # of retries */ - uint32_t computed_chksum; /* Computed checksum */ - uint32_t stored_chksum; /* Checksum read from file */ - H5F_super_t *ret_value; /* Return value */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5F_superblock_cache_ud_t *udata = (H5F_superblock_cache_ud_t *)_udata; /* User data */ + unsigned super_vers; /* Superblock version */ + uint8_t sizeof_addr; /* Size of offsets in the file (in bytes) */ + uint8_t sizeof_size; /* Size of lengths in the file (in bytes) */ + size_t variable_size; /* Variable size of superblock */ + htri_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_eq(addr, 0)); + HDassert(image_len); + + if(image == NULL) { + HDassert(actual_len == NULL); + + /* Set the initial image length size */ + *image_len = H5F_SUPERBLOCK_FIXED_SIZE + /* Fixed size of superblock */ + H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE; + } else { /* compute actual_len */ + HDassert(udata); + HDassert(udata->f); + HDassert(actual_len); + HDassert(*actual_len == *image_len); + + image += H5F_SIGNATURE_LEN; + + /* Superblock version */ + super_vers = *image++; + if(super_vers > HDF5_SUPERBLOCK_VERSION_LATEST) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad superblock version number") + + /* Save the version to be used in verify_chksum callback */ + udata->super_vers = super_vers; + + /* Sanity check */ + HDassert(((size_t)(image - (const uint8_t *)_image)) == H5F_SUPERBLOCK_FIXED_SIZE); + HDassert(*image_len >= H5F_SUPERBLOCK_FIXED_SIZE + 6); + + /* Determine the size of addresses & size of offsets, for computing the + * variable-sized portion of the superblock. + */ + if(super_vers < HDF5_SUPERBLOCK_VERSION_2) { + sizeof_addr = image[4]; + sizeof_size = image[5]; + } /* end if */ + else { + sizeof_addr = image[0]; + sizeof_size = image[1]; + } /* end else */ + if(sizeof_addr != 2 && sizeof_addr != 4 && + sizeof_addr != 8 && sizeof_addr != 16 && sizeof_addr != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad byte number in an address") + if(sizeof_size != 2 && sizeof_size != 4 && + sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad byte number for object size") + + /* Determine the size of the variable-length part of the superblock */ + variable_size = (size_t)H5F_SUPERBLOCK_VARLEN_SIZE(super_vers, sizeof_addr, sizeof_size); + HDassert(variable_size > 0); + + /* Handle metadata cache retry for variable-sized portion of the superblock */ + if(*image_len != (H5F_SUPERBLOCK_FIXED_SIZE + variable_size)) { + + /* Sanity check */ + HDassert(*image_len == (H5F_SUPERBLOCK_FIXED_SIZE + H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE)); + + /* Make certain we can read the variabled-sized portion of the superblock */ + if(H5F__set_eoa(udata->f, H5FD_MEM_SUPER, (haddr_t)(H5F_SUPERBLOCK_FIXED_SIZE + variable_size)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "set end of space allocation request failed") + + *actual_len = H5F_SUPERBLOCK_FIXED_SIZE + variable_size; + + } /* end if */ + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F__cache_superblock_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__cache_superblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5F__cache_superblock_verify_chksum(const void *_image, size_t len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5F_superblock_cache_ud_t *udata = (H5F_superblock_cache_ud_t *)_udata; /* User data */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); HDassert(udata); - /* Short cuts */ - shared = f->shared; - lf = shared->lf; + /* No checksum for version 0 & 1 */ + if(udata->super_vers >= HDF5_SUPERBLOCK_VERSION_2) { - /* Get the shared file creation property list */ - if(NULL == (c_plist = (H5P_genplist_t *)H5I_object(shared->fcpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "can't get property list") + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); - /* Get the base address for the file in the VFD */ - if(HADDR_UNDEF == (base_addr = H5FD_get_base_addr(lf))) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "failed to get base address for file driver") + if(stored_chksum != computed_chksum) + ret_value = FALSE; + } - /* Allocate space for the superblock */ - if(NULL == (sblock = H5FL_CALLOC(H5F_super_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F__cache_superblock_verify_chksum() */ - /* The superblock must be flushed last (and collectively in parallel) */ - sblock->cache_info.flush_me_last = TRUE; -#ifdef H5_HAVE_PARALLEL - sblock->cache_info.flush_me_collectively = TRUE; -#endif + +/*------------------------------------------------------------------------- + * Function: H5F__cache_superblock_deserialize + * + * Purpose: Loads an object from the disk. + * + * Return: Success: Pointer to new object + * Failure: NULL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 18 2013 + * + *------------------------------------------------------------------------- + */ +static void * +H5F__cache_superblock_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) +{ + H5F_super_t *sblock = NULL; /* File's superblock */ + H5F_superblock_cache_ud_t *udata = (H5F_superblock_cache_ud_t *)_udata; /* User data */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + size_t variable_size; /* Variable size of superblock */ + unsigned super_vers; /* Superblock version */ + uint8_t sizeof_addr; /* Size of offsets in the file (in bytes) */ + uint8_t sizeof_size; /* Size of lengths in the file (in bytes) */ + H5F_super_t *ret_value; /* Return value */ - /* Get the DXPL plist object for DXPL ID */ - if(NULL == (dxpl = (H5P_genplist_t *)H5I_object(dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "can't get property list") + FUNC_ENTER_STATIC - H5_CHECK_OVERFLOW(fixed_size, size_t, haddr_t); + /* Check arguments */ + HDassert(image); + HDassert(udata); + HDassert(udata->f); - /* Get the # of read attempts */ - tries = max_tries = H5F_GET_READ_ATTEMPTS(f); - retries = 0; - do { - /* Read fixed-size portion of the superblock */ - p = sbuf; - if(H5FD_set_eoa(lf, H5FD_MEM_SUPER, (haddr_t)fixed_size) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "set end of space allocation request failed") - if(H5FD_read(lf, dxpl, H5FD_MEM_SUPER, (haddr_t)0, fixed_size, p) < 0) - HGOTO_ERROR(H5E_FILE, H5E_READERROR, NULL, "unable to read superblock") + /* Allocate space for the superblock */ + if(NULL == (sblock = H5FL_CALLOC(H5F_super_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - /* Skip over signature (already checked when locating the superblock) */ - p += H5F_SIGNATURE_LEN; + image += H5F_SIGNATURE_LEN; - /* Superblock version */ - super_vers = *p++; - if(super_vers > HDF5_SUPERBLOCK_VERSION_LATEST) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad superblock version number") - if(H5P_set(c_plist, H5F_CRT_SUPER_VERS_NAME, &super_vers) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "unable to set superblock version") + /* Superblock version */ + super_vers = *image++; + if(super_vers > HDF5_SUPERBLOCK_VERSION_LATEST) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad superblock version number") - /* Record the superblock version */ - sblock->super_vers = super_vers; + /* Record the superblock version */ + sblock->super_vers = super_vers; - /* Sanity check */ - HDassert(((size_t)(p - sbuf)) == fixed_size); + /* Sanity check */ + HDassert(((size_t)(image - (const uint8_t *)_image)) == H5F_SUPERBLOCK_FIXED_SIZE); + HDassert(len >= H5F_SUPERBLOCK_FIXED_SIZE + 6); - /* Determine the size of the variable-length part of the superblock */ - variable_size = (size_t)H5F_SUPERBLOCK_VARLEN_SIZE(super_vers, f); - HDassert(variable_size > 0); - HDassert(fixed_size + variable_size <= sizeof(sbuf)); - - /* Read in variable-sized portion of superblock */ - if(H5FD_set_eoa(lf, H5FD_MEM_SUPER, (haddr_t)(fixed_size + variable_size)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "set end of space allocation request failed") - if(H5FD_read(lf, dxpl, H5FD_MEM_SUPER, (haddr_t)fixed_size, variable_size, p) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to read superblock") - - /* No checksum for version 0 & 1 */ - if(super_vers < HDF5_SUPERBLOCK_VERSION_2) - break; - - /* Decode size of file addresses at this point to get the correct H5F_SIZEOF_ADDR(f) for checksum */ - sizeof_addr = *p++; - if(sizeof_addr == 2 || sizeof_addr == 4 || - sizeof_addr == 8 || sizeof_addr == 16 || sizeof_addr == 32) { - - if(H5P_set(c_plist, H5F_CRT_ADDR_BYTE_NUM_NAME, &sizeof_addr) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "unable to set byte number in an address") - shared->sizeof_addr = sizeof_addr; /* Keep a local copy also */ - - /* Retrieve stored and computed checksum */ - H5F_get_checksums(sbuf, fixed_size + H5F_SUPERBLOCK_VARLEN_SIZE(super_vers, f), &stored_chksum, &computed_chksum); - - /* Verify correct checksum */ - if(stored_chksum == computed_chksum) - break; - } /* end if */ - } while (--tries); + /* Determine the size of addresses & size of offsets, for computing the + * variable-sized portion of the superblock. + */ + if(super_vers < HDF5_SUPERBLOCK_VERSION_2) { + sizeof_addr = image[4]; + sizeof_size = image[5]; + } /* end if */ + else { + sizeof_addr = image[0]; + sizeof_size = image[1]; + } /* end else */ + if(sizeof_addr != 2 && sizeof_addr != 4 && + sizeof_addr != 8 && sizeof_addr != 16 && sizeof_addr != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number in an address") + if(sizeof_size != 2 && sizeof_size != 4 && + sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number for object size") + sblock->sizeof_addr = sizeof_addr; + sblock->sizeof_size = sizeof_size; - if(tries == 0) - /* After all tries (for SWMR access) or after 1 try (for non-SWMR) */ - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "bad checksum or bad byte value in superblock") + /* Determine the size of the variable-length part of the superblock */ + variable_size = (size_t)H5F_SUPERBLOCK_VARLEN_SIZE(super_vers, sizeof_addr, sizeof_size); + HDassert(variable_size > 0); - retries += (max_tries - tries); - if(retries) /* Does not track 0 retry */ - if(H5F_track_metadata_read_retries(f, H5AC_SUPERBLOCK_ID, retries) < 0) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "cannot track read retries = %u ", retries) + HDassert(len == (H5F_SUPERBLOCK_FIXED_SIZE + variable_size)); /* Check for older version of superblock format */ if(super_vers < HDF5_SUPERBLOCK_VERSION_2) { - uint32_t status_flags; /* File status flags */ - unsigned btree_k[H5B_NUM_BTREE_ID]; /* B-tree internal node 'K' values */ - unsigned sym_leaf_k; /* Symbol table leaf node's 'K' value */ - - /* Freespace version (hard-wired) */ - if(HDF5_FREESPACE_VERSION != *p++) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad free space version number") - - /* Root group version number (hard-wired) */ - if(HDF5_OBJECTDIR_VERSION != *p++) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad object directory version number") - - /* Skip over reserved byte */ - p++; - - /* Shared header version number (hard-wired) */ - if(HDF5_SHAREDHEADER_VERSION != *p++) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad shared-header format version number") - - /* Size of file addresses */ - sizeof_addr = *p++; - if(sizeof_addr != 2 && sizeof_addr != 4 && - sizeof_addr != 8 && sizeof_addr != 16 && sizeof_addr != 32) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number in an address") - if(H5P_set(c_plist, H5F_CRT_ADDR_BYTE_NUM_NAME, &sizeof_addr) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "unable to set byte number in an address") - shared->sizeof_addr = sizeof_addr; /* Keep a local copy also */ - - /* Size of file sizes */ - sizeof_size = *p++; - if(sizeof_size != 2 && sizeof_size != 4 && - sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number for object size") - if(H5P_set(c_plist, H5F_CRT_OBJ_BYTE_NUM_NAME, &sizeof_size) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "unable to set byte number for object size") - shared->sizeof_size = sizeof_size; /* Keep a local copy also */ - - /* Skip over reserved byte */ - p++; - - /* Various B-tree sizes */ - UINT16DECODE(p, sym_leaf_k); - if(sym_leaf_k == 0) - HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad symbol table leaf node 1/2 rank") - if(H5P_set(c_plist, H5F_CRT_SYM_LEAF_NAME, &sym_leaf_k) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "unable to set rank for symbol table leaf nodes") - sblock->sym_leaf_k = sym_leaf_k; /* Keep a local copy also */ + uint32_t status_flags; /* File status flags */ + unsigned sym_leaf_k; /* Symbol table leaf node's 'K' value */ + unsigned snode_btree_k; /* B-tree symbol table internal node 'K' value */ + unsigned chunk_btree_k; /* B-tree chunk internal node 'K' value */ + + /* Freespace version (hard-wired) */ + if(HDF5_FREESPACE_VERSION != *image++) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad free space version number") + + /* Root group version number (hard-wired) */ + if(HDF5_OBJECTDIR_VERSION != *image++) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad object directory version number") + + /* Skip over reserved byte */ + image++; + + /* Shared header version number (hard-wired) */ + if(HDF5_SHAREDHEADER_VERSION != *image++) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad shared-header format version number") + + /* Size of file addresses */ + sizeof_addr = *image++; + if(sizeof_addr != 2 && sizeof_addr != 4 && + sizeof_addr != 8 && sizeof_addr != 16 && sizeof_addr != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number in an address") + sblock->sizeof_addr = sizeof_addr; + udata->f->shared->sizeof_addr = sizeof_addr; /* Keep a local copy also */ + + /* Size of file sizes */ + sizeof_size = *image++; + if(sizeof_size != 2 && sizeof_size != 4 && + sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number for object size") + sblock->sizeof_size = sizeof_size; + udata->f->shared->sizeof_size = sizeof_size; /* Keep a local copy also */ + + /* Skip over reserved byte */ + image++; + + /* Various B-tree sizes */ + UINT16DECODE(image, sym_leaf_k); + if(sym_leaf_k == 0) + HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad symbol table leaf node 1/2 rank") + udata->sym_leaf_k = sym_leaf_k; /* Keep a local copy also */ /* Need 'get' call to set other array values */ - if(H5P_get(c_plist, H5F_CRT_BTREE_RANK_NAME, btree_k) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "unable to get rank for btree internal nodes") - UINT16DECODE(p, btree_k[H5B_SNODE_ID]); - if(btree_k[H5B_SNODE_ID] == 0) - HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad 1/2 rank for btree internal nodes") - /* + UINT16DECODE(image, snode_btree_k); + if(snode_btree_k == 0) + HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad 1/2 rank for btree internal nodes") + udata->btree_k[H5B_SNODE_ID] = snode_btree_k; + + /* * Delay setting the value in the property list until we've checked * for the indexed storage B-tree internal 'K' value later. */ /* File status flags (not really used yet) */ - UINT32DECODE(p, status_flags); + UINT32DECODE(image, status_flags); HDassert(status_flags <= 255); sblock->status_flags = (uint8_t)status_flags; if(sblock->status_flags & ~H5F_SUPER_ALL_FLAGS) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock") + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock") - /* + /* * If the superblock version # is greater than 0, read in the indexed * storage B-tree internal 'K' value */ if(super_vers > HDF5_SUPERBLOCK_VERSION_DEF) { - UINT16DECODE(p, btree_k[H5B_CHUNK_ID]); - /* Reserved bytes are present only in version 1 */ - if(super_vers == HDF5_SUPERBLOCK_VERSION_1) - p += 2; /* reserved */ - } /* end if */ - else - btree_k[H5B_CHUNK_ID] = HDF5_BTREE_CHUNK_IK_DEF; + UINT16DECODE(image, chunk_btree_k); - /* Set the B-tree internal node values, etc */ - if(H5P_set(c_plist, H5F_CRT_BTREE_RANK_NAME, btree_k) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "unable to set rank for btree internal nodes") - HDmemcpy(sblock->btree_k, btree_k, sizeof(unsigned) * (size_t)H5B_NUM_BTREE_ID); /* Keep a local copy also */ + /* Reserved bytes are present only in version 1 */ + if(super_vers == HDF5_SUPERBLOCK_VERSION_1) + image += 2; /* reserved */ + } /* end if */ + else + chunk_btree_k = HDF5_BTREE_CHUNK_IK_DEF; + udata->btree_k[H5B_CHUNK_ID] = chunk_btree_k; - /* Remainder of "variable-sized" portion of superblock */ - H5F_addr_decode(f, (const uint8_t **)&p, &sblock->base_addr/*out*/); - H5F_addr_decode(f, (const uint8_t **)&p, &sblock->ext_addr/*out*/); - H5F_addr_decode(f, (const uint8_t **)&p, &stored_eof/*out*/); - H5F_addr_decode(f, (const uint8_t **)&p, &sblock->driver_addr/*out*/); + /* Remainder of "variable-sized" portion of superblock */ + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->base_addr/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->ext_addr/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &udata->stored_eof/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->driver_addr/*out*/); - /* Allocate space for the root group symbol table entry */ - HDassert(!sblock->root_ent); - if(NULL == (sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t)))) - HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "can't allocate space for root group symbol table entry") + /* Allocate space for the root group symbol table entry */ + HDassert(!sblock->root_ent); + if(NULL == (sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t)))) + HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "can't allocate space for root group symbol table entry") - /* decode the root group symbol table entry */ - if(H5G_ent_decode(f, (const uint8_t **)&p, sblock->root_ent) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode root group symbol table entry") + /* decode the root group symbol table entry */ + if(H5G_ent_decode(udata->f, (const uint8_t **)&image, sblock->root_ent) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode root group symbol table entry") - /* Set the root group address to the correct value */ - sblock->root_addr = sblock->root_ent->header; + /* Set the root group address to the correct value */ + sblock->root_addr = sblock->root_ent->header; - /* - * Check if superblock address is different from base address and - * adjust base address and "end of address" address if so. - */ - if(!H5F_addr_eq(base_addr, sblock->base_addr)) { - /* Check if the superblock moved earlier in the file */ - if(H5F_addr_lt(base_addr, sblock->base_addr)) - stored_eof -= (sblock->base_addr - base_addr); - else - /* The superblock moved later in the file */ - stored_eof += (base_addr - sblock->base_addr); - - /* Adjust base address for offsets of the HDF5 data in the file */ - sblock->base_addr = base_addr; - - /* Set the base address for the file in the VFD now */ - if(H5FD_set_base_addr(lf, sblock->base_addr) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "failed to set base address for file driver") - - /* Indicate that the superblock should be marked dirty */ - udata->dirtied = TRUE; - } /* end if */ - - /* This step is for h5repart tool only. If user wants to change file driver + /* This step is for h5repart tool only. If user wants to change file driver * from family to sec2 while using h5repart, set the driver address to * undefined to let the library ignore the family driver information saved * in the superblock. */ - if(H5F_HAS_FEATURE(f, H5FD_FEAT_IGNORE_DRVRINFO)) { - /* Eliminate the driver info */ - sblock->driver_addr = HADDR_UNDEF; + if(udata->ignore_drvrinfo && H5F_addr_defined(sblock->driver_addr)) { + /* Eliminate the driver info */ + sblock->driver_addr = HADDR_UNDEF; + udata->drvrinfo_removed = TRUE; + } /* end if */ - /* Indicate that the superblock should be marked dirty */ - udata->dirtied = TRUE; - } /* end if */ + /* NOTE: Driver info block is decoded separately, later */ - /* Decode the optional driver information block */ - if(H5F_addr_defined(sblock->driver_addr)) { - uint8_t dbuf[H5F_MAX_DRVINFOBLOCK_SIZE]; /* Buffer for driver info block */ - char drv_name[9]; /* Name of driver */ - unsigned drv_vers; /* Version of driver info block */ - size_t drv_variable_size; /* Size of variable-length portion of driver info block, in bytes */ - - /* Read in fixed-sized portion of driver info block */ - p = dbuf; - if(H5FD_set_eoa(lf, H5FD_MEM_SUPER, sblock->driver_addr + H5F_DRVINFOBLOCK_HDR_SIZE) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "set end of space allocation request failed") - if(H5FD_read(lf, dxpl, H5FD_MEM_SUPER, sblock->driver_addr, (size_t)H5F_DRVINFOBLOCK_HDR_SIZE, p) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to read driver information block") - - /* Version number */ - drv_vers = *p++; - if(drv_vers != HDF5_DRIVERINFO_VERSION_0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "bad driver information block version number") - - p += 3; /* reserved bytes */ - - /* Driver info size */ - UINT32DECODE(p, drv_variable_size); - - /* Sanity check */ - HDassert(H5F_DRVINFOBLOCK_HDR_SIZE + drv_variable_size <= sizeof(dbuf)); - - /* Driver name and/or version */ - HDstrncpy(drv_name, (const char *)p, (size_t)8); - drv_name[8] = '\0'; - p += 8; /* advance past name/version */ - - /* Read in variable-sized portion of driver info block */ - if(H5FD_set_eoa(lf, H5FD_MEM_SUPER, sblock->driver_addr + H5F_DRVINFOBLOCK_HDR_SIZE + drv_variable_size) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "set end of space allocation request failed") - if(H5FD_read(lf, dxpl, H5FD_MEM_SUPER, sblock->driver_addr + H5F_DRVINFOBLOCK_HDR_SIZE, drv_variable_size, p) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to read file driver information") - - /* Decode driver information */ - if(H5FD_sb_load(lf, drv_name, p) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to decode driver information") - } /* end if */ } /* end if */ else { + uint32_t read_chksum; /* Checksum read from file */ + + /* Size of file addresses */ + sizeof_addr = *image++; + if(sizeof_addr != 2 && sizeof_addr != 4 && + sizeof_addr != 8 && sizeof_addr != 16 && sizeof_addr != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number in an address") + sblock->sizeof_addr = sizeof_addr; + udata->f->shared->sizeof_addr = sizeof_addr; /* Keep a local copy also */ + + /* Size of file sizes */ + sizeof_size = *image++; + if(sizeof_size != 2 && sizeof_size != 4 && + sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number for object size") + sblock->sizeof_size = sizeof_size; + udata->f->shared->sizeof_size = sizeof_size; /* Keep a local copy also */ + + /* File status flags (not really used yet) */ + sblock->status_flags = *image++; + if(sblock->status_flags & ~H5F_SUPER_ALL_FLAGS) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock") + + /* Base, superblock extension, end of file & root group object header addresses */ + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->base_addr/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->ext_addr/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &udata->stored_eof/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->root_addr/*out*/); + + /* checksum verification already done in verify_chksum cb */ + + /* Decode checksum */ + UINT32DECODE(image, read_chksum); + + /* The Driver Information Block may not appear with the version + * 2 super block. Thus we set the driver_addr field of the in + * core representation of the super block HADDR_UNDEF to prevent + * any attempt to load the Driver Information Block. + */ + sblock->driver_addr = HADDR_UNDEF; + } /* end else */ - /* Already decoded sizeof_addr (and set property) when validating checksum earlier */ + /* Sanity check */ + HDassert((size_t)(image - (const uint8_t *)_image) <= len); - /* Size of file sizes */ - sizeof_size = *p++; - if(sizeof_size != 2 && sizeof_size != 4 && - sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number for object size") - if(H5P_set(c_plist, H5F_CRT_OBJ_BYTE_NUM_NAME, &sizeof_size) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "unable to set byte number for object size") - shared->sizeof_size = sizeof_size; /* Keep a local copy also */ + /* Set return value */ + ret_value = sblock; - /* File status flags (not really used yet) */ - sblock->status_flags = *p++; - if(sblock->status_flags & ~H5F_SUPER_ALL_FLAGS) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock") +done: + /* Release the [possibly partially initialized] superblock on error */ + if(!ret_value && sblock) + if(H5F__super_free(sblock) < 0) + HDONE_ERROR(H5E_FILE, H5E_CANTFREE, NULL, "unable to destroy superblock data") - /* Base, superblock extension, end of file & root group object header addresses */ - H5F_addr_decode(f, (const uint8_t **)&p, &sblock->base_addr/*out*/); - H5F_addr_decode(f, (const uint8_t **)&p, &sblock->ext_addr/*out*/); - H5F_addr_decode(f, (const uint8_t **)&p, &stored_eof/*out*/); - H5F_addr_decode(f, (const uint8_t **)&p, &sblock->root_addr/*out*/); + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F__cache_superblock_deserialize() */ - /* Already decoded and compared stored checksum earlier, when reading */ + +/*------------------------------------------------------------------------- + * Function: H5F__cache_superblock_image_len + * + * Purpose: Compute the size of the data structure on disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 19, 2013 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__cache_superblock_image_len(const void *_thing, size_t *image_len, hbool_t *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const H5F_super_t *sblock = (const H5F_super_t *)_thing; /* Pointer to the object */ - /* - * Check if superblock address is different from base address and - * adjust base address and "end of address" address if so. - */ - if(!H5F_addr_eq(base_addr, sblock->base_addr)) { - /* Check if the superblock moved earlier in the file */ - if(H5F_addr_lt(base_addr, sblock->base_addr)) - stored_eof -= (sblock->base_addr - base_addr); - else - /* The superblock moved later in the file */ - stored_eof += (base_addr - sblock->base_addr); - - /* Adjust base address for offsets of the HDF5 data in the file */ - sblock->base_addr = base_addr; - - /* Set the base address for the file in the VFD now */ - if(H5FD_set_base_addr(lf, sblock->base_addr) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "failed to set base address for file driver") - - /* Indicate that the superblock should be marked dirty */ - udata->dirtied = TRUE; - } /* end if */ + FUNC_ENTER_STATIC_NOERR - /* Get the B-tree internal node values, etc */ - if(H5P_get(c_plist, H5F_CRT_BTREE_RANK_NAME, sblock->btree_k) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "unable to get rank for btree internal nodes") - if(H5P_get(c_plist, H5F_CRT_SYM_LEAF_NAME, &sblock->sym_leaf_k) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "unable to get rank for btree internal nodes") - } /* end else */ + /* Check arguments */ + HDassert(sblock); + HDassert(sblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(sblock->cache_info.type == H5AC_SUPERBLOCK); + HDassert(image_len); + HDassert(compressed_ptr); - /* - * The user-defined data is the area of the file before the base - * address. - */ - if(H5P_set(c_plist, H5F_CRT_USER_BLOCK_NAME, &sblock->base_addr) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "unable to set userblock size") + /* Set the image length size */ + *image_len = (size_t)H5F_SUPERBLOCK_SIZE(sblock); - /* - * Make sure that the data is not truncated. One case where this is - * possible is if the first file of a family of files was opened - * individually. - */ - /* (This check can be skipped when the file is opened for SWMR read, - * as the file can appear truncated if only part of it has been - * been flushed to disk by the single writer process.) - */ - /* Can skip this test when it is not the initial file open-- - * H5F_super_read() call from H5F_evict_tagged_metadata() for - * refreshing object. - * When flushing file buffers and fractal heap is involved, - * the library will allocate actual space for tmp addresses - * via the file layer. The aggregator allocates a block, - * thus the eoa might be greater than eof. - * Note: the aggregator is changed again after being reset - * earlier before H5AC_flush due to allocation of tmp addresses. - */ - if (!(H5F_INTENT(f) & H5F_ACC_SWMR_READ) && udata->initial_read) { - if(HADDR_UNDEF == (eof = H5FD_get_eof(lf, H5FD_MEM_DEFAULT))) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to determine file size") + /* Set *compressed_ptr to FALSE unconditionally */ + *compressed_ptr; - /* (Account for the stored EOA being absolute offset -QAK) */ - if((eof + sblock->base_addr) < stored_eof) - HGOTO_ERROR(H5E_FILE, H5E_TRUNCATED, NULL, "truncated file: eof = %llu, sblock->base_addr = %llu, stored_eof = %llu", (unsigned long long)eof, (unsigned long long)sblock->base_addr, (unsigned long long)stored_eof) - } /* end if */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5F__cache_superblock_image_len() */ - /* - * Tell the file driver how much address space has already been - * allocated so that it knows how to allocate additional memory. - */ - /* (Account for the stored EOA being absolute offset -NAF) */ - if(H5FD_set_eoa(lf, H5FD_MEM_SUPER, stored_eof - sblock->base_addr) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to set end-of-address marker for file") - - /* Read the file's superblock extension, if there is one. */ - if(H5F_addr_defined(sblock->ext_addr)) { - H5O_loc_t ext_loc; /* "Object location" for superblock extension */ - H5O_btreek_t btreek; /* v1 B-tree 'K' value message from superblock extension */ - H5O_drvinfo_t drvinfo; /* Driver info message from superblock extension */ - size_t u; /* Local index variable */ - htri_t status; /* Status for message existing */ - - /* Sanity check - superblock extension should only be defined for - * superblock version >= 2. - */ - HDassert(super_vers >= HDF5_SUPERBLOCK_VERSION_2); + +/*------------------------------------------------------------------------- + * Function: H5FS__cache_hdf_pre_serialize + * + * Purpose: The current use of this function is a cludge to repair an + * oversight in the conversion of the superblock code to use the + * version 3 cache. + * + * In the V2 metadata cache callbacks, the superblock dirver info + * message was updated in the flush routine. Note that this + * operation only applies to version 2 or later superblocks. + * + * Somehow, this functionality was lost in the conversion to use + * the V3 cache, causing failures with the multi file driver + * (and possibly the family file driver as well). + * + * Performing this operation is impossible in the current + * serialize routine, as the dxpl_id is not available. While + * I am pretty sure that this is not the correct place for this + * functionality, as I can see it causing problems with both + * journaling and possibly parallel HDF5 as well, I am placing + * code for the necessary update in the pre_serialize call for + * now for testing purposes. We will almost certainly want to + * change this. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 10/82/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__cache_superblock_pre_serialize(const H5F_t *f, hid_t dxpl_id, + void *_thing, haddr_t H5_ATTR_UNUSED addr, size_t H5_ATTR_UNUSED len, + size_t H5_ATTR_UNUSED compressed_len, haddr_t H5_ATTR_UNUSED *new_addr, + size_t H5_ATTR_UNUSED *new_len, size_t H5_ATTR_UNUSED *new_compressed_len, + unsigned H5_ATTR_UNUSED *flags) +{ + H5F_super_t *sblock = (H5F_super_t *)_thing; /* Pointer to the super block */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT - /* Check for superblock extension being located "outside" the stored - * 'eoa' value, which can occur with the split/multi VFD. + /* Sanity check */ + HDassert(f); + HDassert(sblock); + HDassert(sblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(sblock->cache_info.type == H5AC_SUPERBLOCK); + HDassert(flags); + + if(sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2) { + /* WARNING: This code almost certainly doesn't belong here. Must + * discuss with Quincey where to put it. Note issues + * for journaling and possibly parallel. + * + * -- JRM */ - if(H5F_addr_gt(sblock->ext_addr, stored_eof)) { - /* Set the 'eoa' for the object header memory type large enough - * to give some room for a reasonably sized superblock extension. - * (This is _rather_ a kludge -QAK) - */ - if(H5FD_set_eoa(lf, H5FD_MEM_OHDR, (haddr_t)(sblock->ext_addr + 1024)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to set end-of-address marker for file") - } /* end if */ + /* Update the driver information message in the superblock extension + * if appropriate. + */ + if(H5F_addr_defined(sblock->ext_addr)) { + size_t driver_size; /* Size of driver info block (bytes)*/ + H5O_loc_t ext_loc; /* "Object location" for superblock extension */ - /* Open the superblock extension */ - if(H5F_super_ext_open(f, sblock->ext_addr, &ext_loc) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENOBJ, NULL, "unable to open file's superblock extension") + HDassert(sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2); + + /* Open the superblock extension's object header */ + if(H5F_super_ext_open((H5F_t *)f, sblock->ext_addr, &ext_loc) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENOBJ, FAIL, "unable to open file's superblock extension") - /* Check for the extension having a 'driver info' message */ - if((status = H5O_msg_exists(&ext_loc, H5O_DRVINFO_ID, dxpl_id)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "unable to read object header") - if(status) { /* Check for ignoring the driver info for this file */ - if(H5F_HAS_FEATURE(f, H5FD_FEAT_IGNORE_DRVRINFO)) { - /* Indicate that the superblock should be marked dirty */ - udata->dirtied = TRUE; - } /* end if */ - else { - /* Retrieve the 'driver info' structure */ - if(NULL == H5O_msg_read(&ext_loc, H5O_DRVINFO_ID, &drvinfo, dxpl_id)) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "driver info message not present") - - /* Decode driver information */ - if(H5FD_sb_load(lf, drvinfo.name, drvinfo.buf) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to decode driver information") - - /* Reset driver info message */ - H5O_msg_reset(H5O_DRVINFO_ID, &drvinfo); - } /* end else */ - } /* end if */ + if(!H5F_HAS_FEATURE(f, H5FD_FEAT_IGNORE_DRVRINFO)) { + /* Check for driver info message */ + H5_CHECKED_ASSIGN(driver_size, size_t, H5FD_sb_size(f->shared->lf), hsize_t); + if(driver_size > 0) { + H5O_drvinfo_t drvinfo; /* Driver info */ + uint8_t dbuf[H5F_MAX_DRVINFOBLOCK_SIZE]; /* Driver info block encoding buffer */ - /* Read in the shared OH message information if there is any */ - if(H5SM_get_info(&ext_loc, c_plist, dxpl_id) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to read SOHM table information") - - /* Check for the extension having a 'v1 B-tree "K"' message */ - if((status = H5O_msg_exists(&ext_loc, H5O_BTREEK_ID, dxpl_id)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "unable to read object header") - if(status) { - /* Retrieve the 'v1 B-tree "K"' structure */ - if(NULL == H5O_msg_read(&ext_loc, H5O_BTREEK_ID, &btreek, dxpl_id)) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "v1 B-tree 'K' info message not present") - - /* Set non-default v1 B-tree 'K' value info from file */ - sblock->btree_k[H5B_CHUNK_ID] = btreek.btree_k[H5B_CHUNK_ID]; - sblock->btree_k[H5B_SNODE_ID] = btreek.btree_k[H5B_SNODE_ID]; - sblock->sym_leaf_k = btreek.sym_leaf_k; - - /* Set non-default v1 B-tree 'K' values in the property list */ - if(H5P_set(c_plist, H5F_CRT_BTREE_RANK_NAME, btreek.btree_k) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "unable to set rank for btree internal nodes") - if(H5P_set(c_plist, H5F_CRT_SYM_LEAF_NAME, &btreek.sym_leaf_k) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "unable to set rank for symbol table leaf nodes") - } /* end if */ + /* Sanity check */ + HDassert(driver_size <= H5F_MAX_DRVINFOBLOCK_SIZE); - /* Check for the extension having a 'free-space manager info' message */ - if((status = H5O_msg_exists(&ext_loc, H5O_FSINFO_ID, dxpl_id)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "unable to check object header") - if(status) { - H5O_fsinfo_t fsinfo; /* Free-space manager info message from superblock extension */ - - /* Retrieve the 'free-space manager info' structure */ - if(NULL == H5O_msg_read(&ext_loc, H5O_FSINFO_ID, &fsinfo, dxpl_id)) - HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get free-space manager info message") - - if(shared->fs_strategy != fsinfo.strategy) { - shared->fs_strategy = fsinfo.strategy; - - /* Set non-default strategy in the property list */ - if(H5P_set(c_plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, &fsinfo.strategy) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "unable to set file space strategy") - } /* end if */ - if(shared->fs_threshold != fsinfo.threshold) { - shared->fs_threshold = fsinfo.threshold; - - /* Set non-default threshold in the property list */ - if(H5P_set(c_plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, &fsinfo.threshold) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "unable to set file space strategy") - } /* end if */ - - /* set free-space manager addresses */ - shared->fs_addr[0] = HADDR_UNDEF; - for(u = 1; u < NELMTS(f->shared->fs_addr); u++) - shared->fs_addr[u] = fsinfo.fs_addr[u-1]; - } /* end if */ + /* Encode driver-specific data */ + if(H5FD_sb_encode(f->shared->lf, drvinfo.name, dbuf) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode driver information") - /* Close superblock extension */ - if(H5F_super_ext_close(f, &ext_loc, dxpl_id, FALSE) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, NULL, "unable to close file's superblock extension") - } /* end if */ + /* Write driver info information to the superblock extension */ + drvinfo.len = driver_size; + drvinfo.buf = dbuf; + if(H5O_msg_write(&ext_loc, H5O_DRVINFO_ID, H5O_MSG_FLAG_DONTSHARE, H5O_UPDATE_TIME, &drvinfo, dxpl_id) < 0) + HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "unable to update driver info header message") + } /* end if */ + } /* end if */ - /* Set return value */ - ret_value = sblock; + /* Close the superblock extension object header */ + if(H5F_super_ext_close((H5F_t *)f, &ext_loc, dxpl_id, FALSE) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close file's superblock extension") + } /* end if */ + } /* end if */ done: - /* Release the [possibly partially initialized] superblock on errors */ - if(!ret_value && sblock) - if(H5F__super_free(sblock) < 0) - HDONE_ERROR(H5E_FILE, H5E_CANTFREE, NULL, "unable to destroy superblock data") - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5F_sblock_load() */ +} /* end H5FS_cache_superblock_pre_serialize() */ /*------------------------------------------------------------------------- - * Function: H5F_sblock_flush + * Function: H5F__cache_superblock_serialize * - * Purpose: Flushes the superblock. + * Purpose: Flushes a dirty object to disk. * - * Return: Success: SUCCEED - * Failure: NULL + * Return: Non-negative on success/Negative on failure * - * Programmer: Mike McGreevy - * mamcgree@hdfgroup.org - * April 8, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 19 2013 * *------------------------------------------------------------------------- */ static herr_t -H5F_sblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t H5_ATTR_UNUSED addr, - H5F_super_t *sblock) +H5F__cache_superblock_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, + void *_thing) { - herr_t ret_value = SUCCEED; + H5F_super_t *sblock = (H5F_super_t *)_thing; /* Pointer to the object */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + haddr_t rel_eof; /* Relative EOF for file */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* check arguments */ + /* Sanity check */ HDassert(f); - HDassert(H5F_addr_eq(addr, 0)); + HDassert(image); HDassert(sblock); - + /* Assert that the superblock is marked as being flushed last (and collectively in parallel) */ /* (We'll rely on the cache to make sure it actually *is* flushed @@ -693,301 +721,434 @@ H5F_sblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t H5_ATTR_UNUSE HDassert(sblock->cache_info.flush_me_collectively); #endif - if(sblock->cache_info.is_dirty) { - H5P_genplist_t *dxpl; /* DXPL object */ - uint8_t buf[H5F_MAX_SUPERBLOCK_SIZE + H5F_MAX_DRVINFOBLOCK_SIZE]; /* Superblock & driver info blockencoding buffer */ - uint8_t *p; /* Ptr into encoding buffer */ - haddr_t rel_eof; /* Relative EOF for file */ - size_t superblock_size; /* Size of superblock, in bytes */ - size_t driver_size; /* Size of driver info block (bytes)*/ - - /* Encode the common portion of the file superblock for all versions */ - p = buf; - HDmemcpy(p, H5F_SIGNATURE, (size_t)H5F_SIGNATURE_LEN); - p += H5F_SIGNATURE_LEN; - *p++ = (uint8_t)sblock->super_vers; - - /* Check for older version of superblock format */ - if(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) { - *p++ = (uint8_t)HDF5_FREESPACE_VERSION; /* (hard-wired) */ - *p++ = (uint8_t)HDF5_OBJECTDIR_VERSION; /* (hard-wired) */ - *p++ = 0; /* reserved*/ - - *p++ = (uint8_t)HDF5_SHAREDHEADER_VERSION; /* (hard-wired) */ - *p++ = (uint8_t)H5F_SIZEOF_ADDR(f); - *p++ = (uint8_t)H5F_SIZEOF_SIZE(f); - *p++ = 0; /* reserved */ - - UINT16ENCODE(p, sblock->sym_leaf_k); - UINT16ENCODE(p, sblock->btree_k[H5B_SNODE_ID]); - UINT32ENCODE(p, (uint32_t)sblock->status_flags); - - /* - * Versions of the superblock >0 have the indexed storage B-tree - * internal 'K' value stored - */ - if(sblock->super_vers > HDF5_SUPERBLOCK_VERSION_DEF) { - UINT16ENCODE(p, sblock->btree_k[H5B_CHUNK_ID]); - *p++ = 0; /*reserved */ - *p++ = 0; /*reserved */ - } /* end if */ - - /* Encode the base address */ - H5F_addr_encode(f, &p, sblock->base_addr); - - /* Encode the address of global free-space index */ - H5F_addr_encode(f, &p, sblock->ext_addr); - - /* Encode the end-of-file address. Note that at this point in time, - * the EOF value itself may not be reflective of the file's size, as - * we will eventually truncate the file to match the EOA value. As - * such, use the EOA value in its place, knowing that the current EOF - * value will ultimately match it. */ - if ((rel_eof = H5FD_get_eoa(f->shared->lf, H5FD_MEM_SUPER)) == HADDR_UNDEF) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed") - H5F_addr_encode(f, &p, (rel_eof + sblock->base_addr)); - - /* Encode the driver informaton block address */ - H5F_addr_encode(f, &p, sblock->driver_addr); - - /* Encode the root group object entry, including the cached stab info */ - if(H5G_ent_encode(f, &p, sblock->root_ent) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTENCODE, FAIL, "can't encode root group symbol table entry") - - /* Encode the driver information block. */ - H5_CHECKED_ASSIGN(driver_size, size_t, H5FD_sb_size(f->shared->lf), hsize_t); - - /* Checking whether driver block address is defined here is to handle backward - * compatibility. If the file was created with v1.6 library or earlier and no - * driver info block was written in the superblock, we don't write it either even - * though there's some driver info. Otherwise, the driver block extended will - * overwrite the (meta)data right after the superblock. This situation happens to - * the family driver particularly. SLU - 2009/3/24 - */ - if(driver_size > 0 && H5F_addr_defined(sblock->driver_addr)) { - char driver_name[9]; /* Name of driver, for driver info block */ - uint8_t *dbuf = p; /* Pointer to beginning of driver info */ - - /* Encode the driver information block */ - *p++ = HDF5_DRIVERINFO_VERSION_0; /* Version */ - *p++ = 0; /* reserved */ - *p++ = 0; /* reserved */ - *p++ = 0; /* reserved */ - - /* Driver info size, excluding header */ - UINT32ENCODE(p, driver_size); - - /* Encode driver-specific data */ - if(H5FD_sb_encode(f->shared->lf, driver_name, dbuf + H5F_DRVINFOBLOCK_HDR_SIZE) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode driver information") - - /* Store driver name (set in 'H5FD_sb_encode' call above) */ - HDmemcpy(p, driver_name, (size_t)8); - - /* Advance buffer pointer past name & variable-sized portion of driver info */ - /* (for later use in computing the superblock size) */ - p += 8 + driver_size; - } /* end if */ - } /* end if */ - else { - uint32_t chksum; /* Checksum temporary variable */ - H5O_loc_t *root_oloc; /* Pointer to root group's object location */ - - /* Size of file addresses & offsets, and status flags */ - *p++ = (uint8_t)H5F_SIZEOF_ADDR(f); - *p++ = (uint8_t)H5F_SIZEOF_SIZE(f); - *p++ = sblock->status_flags; + /* Encode the common portion of the file superblock for all versions */ + HDmemcpy(image, H5F_SIGNATURE, (size_t)H5F_SIGNATURE_LEN); + image += H5F_SIGNATURE_LEN; + *image++ = (uint8_t)sblock->super_vers; - /* Encode the base address */ - H5F_addr_encode(f, &p, sblock->base_addr); - - /* Encode the address of the superblock extension */ - H5F_addr_encode(f, &p, sblock->ext_addr); - - /* At this point in time, the EOF value itself may - * not be reflective of the file's size, since we'll eventually - * truncate it to match the EOA value. As such, use the EOA value - * in its place, knowing that the current EOF value will - * ultimately match it. */ - if ((rel_eof = H5FD_get_eoa(f->shared->lf, H5FD_MEM_SUPER)) == HADDR_UNDEF) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed") - H5F_addr_encode(f, &p, (rel_eof + sblock->base_addr)); + /* Check for older version of superblock format */ + if(sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) { + *image++ = (uint8_t)HDF5_FREESPACE_VERSION; /* (hard-wired) */ + *image++ = (uint8_t)HDF5_OBJECTDIR_VERSION; /* (hard-wired) */ + *image++ = 0; /* reserved*/ - /* Retrieve information for root group */ - if(NULL == (root_oloc = H5G_oloc(f->shared->root_grp))) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to retrieve root group information") + *image++ = (uint8_t)HDF5_SHAREDHEADER_VERSION; /* (hard-wired) */ + *image++ = sblock->sizeof_addr; + *image++ = sblock->sizeof_size; + *image++ = 0; /* reserved */ - /* Encode address of root group's object header */ - H5F_addr_encode(f, &p, root_oloc->addr); + UINT16ENCODE(image, sblock->sym_leaf_k); + UINT16ENCODE(image, sblock->btree_k[H5B_SNODE_ID]); + UINT32ENCODE(image, (uint32_t)sblock->status_flags); - /* Compute superblock checksum */ - chksum = H5_checksum_metadata(buf, ((size_t)H5F_SUPERBLOCK_SIZE(sblock->super_vers, f) - H5F_SIZEOF_CHKSUM), 0); + /* + * Versions of the superblock >0 have the indexed storage B-tree + * internal 'K' value stored + */ + if(sblock->super_vers > HDF5_SUPERBLOCK_VERSION_DEF) { + UINT16ENCODE(image, sblock->btree_k[H5B_CHUNK_ID]); + *image++ = 0; /*reserved */ + *image++ = 0; /*reserved */ + } /* end if */ - /* Superblock checksum */ - UINT32ENCODE(p, chksum); + /* Encode the base address */ + H5F_addr_encode(f, &image, sblock->base_addr); - /* Sanity check */ - HDassert((size_t)(p - buf) == (size_t)H5F_SUPERBLOCK_SIZE(sblock->super_vers, f)); - } /* end else */ + /* Encode the address of global free-space index */ + H5F_addr_encode(f, &image, sblock->ext_addr); - /* Retrieve the total size of the superblock info */ - H5_CHECKED_ASSIGN(superblock_size, size_t, (p - buf), ptrdiff_t); + /* Encode the end-of-file address. Note that at this point in time, + * the EOF value itself may not be reflective of the file's size, as + * we will eventually truncate the file to match the EOA value. As + * such, use the EOA value in its place, knowing that the current EOF + * value will ultimately match it. */ + if ((rel_eof = H5FD_get_eoa(f->shared->lf, H5FD_MEM_SUPER)) == HADDR_UNDEF) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed") + H5F_addr_encode(f, &image, (rel_eof + sblock->base_addr)); - /* Double check we didn't overrun the block (unlikely) */ - HDassert(superblock_size <= sizeof(buf)); + /* Encode the driver informaton block address */ + H5F_addr_encode(f, &image, sblock->driver_addr); - /* Get the DXPL plist object for DXPL ID */ - if(NULL == (dxpl = (H5P_genplist_t *)H5I_object(dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get property list") + /* Encode the root group object entry, including the cached stab info */ + if(H5G_ent_encode(f, &image, sblock->root_ent) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTENCODE, FAIL, "can't encode root group symbol table entry") - /* Write superblock */ - /* (always at relative address 0) */ - if(H5FD_write(f->shared->lf, dxpl, H5FD_MEM_SUPER, (haddr_t)0, superblock_size, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write superblock") + /* NOTE: Driver info block is handled separately */ - /* Check for newer version of superblock format & superblock extension */ - if(sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2 && H5F_addr_defined(sblock->ext_addr)) { - H5O_loc_t ext_loc; /* "Object location" for superblock extension */ + } /* end if */ + else { /* sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2 */ + uint32_t chksum; /* Checksum temporary variable */ + H5O_loc_t *root_oloc; /* Pointer to root group's object location */ - /* Open the superblock extension's object header */ - if(H5F_super_ext_open(f, sblock->ext_addr, &ext_loc) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENOBJ, FAIL, "unable to open file's superblock extension") + /* Size of file addresses & offsets, and status flags */ + *image++ = sblock->sizeof_addr; + *image++ = sblock->sizeof_size; + *image++ = sblock->status_flags; - /* Check for ignoring the driver info for this file */ - if(!H5F_HAS_FEATURE(f, H5FD_FEAT_IGNORE_DRVRINFO)) { - /* Check for driver info message */ - H5_CHECKED_ASSIGN(driver_size, size_t, H5FD_sb_size(f->shared->lf), hsize_t); - if(driver_size > 0) { - H5O_drvinfo_t drvinfo; /* Driver info */ - uint8_t dbuf[H5F_MAX_DRVINFOBLOCK_SIZE]; /* Driver info block encoding buffer */ + /* Encode the base address */ + H5F_addr_encode(f, &image, sblock->base_addr); - /* Sanity check */ - HDassert(driver_size <= H5F_MAX_DRVINFOBLOCK_SIZE); + /* Encode the address of the superblock extension */ + H5F_addr_encode(f, &image, sblock->ext_addr); - /* Encode driver-specific data */ - if(H5FD_sb_encode(f->shared->lf, drvinfo.name, dbuf) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode driver information") + /* At this point in time, the EOF value itself may + * not be reflective of the file's size, since we'll eventually + * truncate it to match the EOA value. As such, use the EOA value + * in its place, knowing that the current EOF value will + * ultimately match it. */ + if ((rel_eof = H5FD_get_eoa(f->shared->lf, H5FD_MEM_SUPER)) == HADDR_UNDEF) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed") + H5F_addr_encode(f, &image, (rel_eof + sblock->base_addr)); - /* Write driver info information to the superblock extension */ - drvinfo.len = driver_size; - drvinfo.buf = dbuf; - if(H5O_msg_write(&ext_loc, H5O_DRVINFO_ID, H5O_MSG_FLAG_DONTSHARE, H5O_UPDATE_TIME, &drvinfo, dxpl_id) < 0) - HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "unable to update driver info header message") + /* Retrieve information for root group */ + if(NULL == (root_oloc = H5G_oloc(f->shared->root_grp))) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to retrieve root group information") - } /* end if */ + /* Encode address of root group's object header */ + H5F_addr_encode(f, &image, root_oloc->addr); - } /* end if */ + /* Compute superblock checksum */ + chksum = H5_checksum_metadata(_image, ((size_t)H5F_SUPERBLOCK_SIZE(sblock) - H5F_SIZEOF_CHKSUM), 0); - /* Close the superblock extension object header */ - if(H5F_super_ext_close(f, &ext_loc, dxpl_id, FALSE) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close file's superblock extension") - } /* end if */ + /* Superblock checksum */ + UINT32ENCODE(image, chksum); - /* Reset the dirty flag. */ - sblock->cache_info.is_dirty = FALSE; - } /* end if */ + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) == (size_t)H5F_SUPERBLOCK_SIZE(sblock)); + } /* end else */ - if(destroy) - if(H5F_sblock_dest(f, sblock) < 0) - HGOTO_ERROR(H5E_FSPACE, H5E_CLOSEERROR, FAIL, "can't close superblock") + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= len); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5F_sblock_flush() */ +} /* H5F__cache_superblock_serialize() */ /*------------------------------------------------------------------------- - * Function: H5F_sblock_dest + * Function: H5F__cache_superblock_free_icr * - * Purpose: Frees memory used by the superblock. + * Purpose: Destroy/release an "in core representation" of a data + * structure * - * Return: Non-negative on success/Negative on failure + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). + * + * Return: Non-negative on success/Negative on failure * - * Programmer: Mike McGreevy - * April 8, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 20, 2013 * *------------------------------------------------------------------------- */ static herr_t -H5F_sblock_dest(H5F_t H5_ATTR_UNUSED *f, H5F_super_t* sblock) +H5F__cache_superblock_free_icr(void *_thing) { + H5F_super_t *sblock = (H5F_super_t *)_thing; /* Pointer to the object */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Sanity check */ HDassert(sblock); + HDassert(sblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(sblock->cache_info.type == H5AC_SUPERBLOCK); - /* Free superblock */ + /* Destroy superblock */ if(H5F__super_free(sblock) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "unable to destroy superblock") + HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free superblock") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5F_sblock_dest() */ +} /* H5F__cache_superblock_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5F_sblock_clear + * Function: H5F__cache_drvrinfo_get_load_size * - * Purpose: Mark the superblock as no longer being dirty. + * Purpose: Compute the size of the data structure on disk. * * Return: Non-negative on success/Negative on failure * - * Programmer: Mike McGreevy - * April 8, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 20, 2013 * *------------------------------------------------------------------------- */ static herr_t -H5F_sblock_clear(H5F_t *f, H5F_super_t *sblock, hbool_t destroy) +H5F__cache_drvrinfo_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5F_drvrinfo_cache_ud_t *udata = (H5F_drvrinfo_cache_ud_t *)_udata; /* User data */ + unsigned drv_vers; /* Version of driver info block */ + size_t drvinfo_len; /* Length of encoded buffer */ + htri_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ - HDassert(sblock); + /* Check arguments */ + HDassert(image_len); + + if(image == NULL) { + HDassert(actual_len == NULL); + + /* Set the initial image length size */ + *image_len = H5F_DRVINFOBLOCK_HDR_SIZE; /* Fixed size portion of driver info block */ + + } else { /* compute actual_len */ + + HDassert(udata); + HDassert(udata->f); + HDassert(actual_len); + HDassert(*actual_len == *image_len); + + /* Version number */ + drv_vers = *image++; + if(drv_vers != HDF5_DRIVERINFO_VERSION_0) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad driver information block version number") + + image += 3; /* reserved bytes */ - /* Reset the dirty flag. */ - sblock->cache_info.is_dirty = FALSE; + /* Driver info size */ + UINT32DECODE(image, drvinfo_len); - if(destroy) - if(H5F_sblock_dest(f, sblock) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "unable to delete superblock") + /* Handle metadata cache retry for variable-sized portion of the driver info block */ + if(*image_len != (H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo_len)) { + /* Sanity check */ + HDassert(*image_len == H5F_DRVINFOBLOCK_HDR_SIZE); + + /* extend the eoa if required so that we can read the complete driver info block */ + { + haddr_t eoa; + haddr_t min_eoa; + + /* get current eoa... */ + if ((eoa = H5FD_get_eoa(udata->f->shared->lf, H5FD_MEM_SUPER)) == HADDR_UNDEF) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed") + + /* ... if it is too small, extend it. */ + min_eoa = udata->driver_addr + H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo_len; + + if ( H5F_addr_gt(min_eoa, eoa) ) + if(H5FD_set_eoa(udata->f->shared->lf, H5FD_MEM_SUPER, min_eoa) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, \ + "set end of space allocation request failed") + } + *actual_len = H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo_len; + } + } /* compute actual_len */ done: + FUNC_LEAVE_NOAPI(ret_value) -} /* end H5F_sblock_clear() */ +} /* end H5F__cache_drvrinfo_get_load_size() */ /*------------------------------------------------------------------------- - * Function: H5F_sblock_size + * Function: H5F__cache_drvrinfo_deserialize * - * Purpose: Returns the size of the superblock encoded on disk. + * Purpose: Loads an object from the disk. + * + * Return: Success: Pointer to a new B-tree. + * Failure: NULL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 20 2013 + * + *------------------------------------------------------------------------- + */ +static void * +H5F__cache_drvrinfo_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) +{ + H5O_drvinfo_t *drvinfo = NULL; /* Driver info */ + H5F_drvrinfo_cache_ud_t *udata = (H5F_drvrinfo_cache_ud_t *)_udata; /* User data */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + char drv_name[9]; /* Name of driver */ + unsigned drv_vers; /* Version of driver info block */ + H5O_drvinfo_t *ret_value; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(image); + HDassert(len >= H5F_DRVINFOBLOCK_HDR_SIZE); + HDassert(udata); + HDassert(udata->f); + + /* Allocate space for the driver info */ + if(NULL == (drvinfo = (H5O_drvinfo_t *)H5MM_calloc(sizeof(H5O_drvinfo_t)))) + HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "memory allocation failed for driver info message") + + /* Version number */ + drv_vers = *image++; + if(drv_vers != HDF5_DRIVERINFO_VERSION_0) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad driver information block version number") + + image += 3; /* reserved bytes */ + + /* Driver info size */ + UINT32DECODE(image, drvinfo->len); + + /* Driver name and/or version */ + HDstrncpy(drv_name, (const char *)image, (size_t)8); + drv_name[8] = '\0'; + image += 8; /* advance past name/version */ + + HDassert(len == (H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo->len)); + + /* Validate and decode driver information */ + if(H5FD_sb_load(udata->f->shared->lf, drv_name, image) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "unable to decode driver information") + + /* Sanity check */ + HDassert((size_t)(image - (const uint8_t *)_image) <= len); + + /* Set return value */ + ret_value = drvinfo; + +done: + /* Release the [possibly partially initialized] driver info message on error */ + if(!ret_value && drvinfo) + H5MM_xfree(drvinfo); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F__cache_drvrinfo_deserialize() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__cache_drvrinfo_image_len + * + * Purpose: Compute the size of the data structure on disk. * * Return: Non-negative on success/Negative on failure * - * Programmer: Mike McGreevy - * April 8, 2009 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 20, 2013 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__cache_drvrinfo_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const H5O_drvinfo_t *drvinfo = (const H5O_drvinfo_t *)_thing; /* Pointer to the object */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(drvinfo); + HDassert(drvinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(drvinfo->cache_info.type == H5AC_DRVRINFO); + HDassert(image_len); + HDassert(compressed_ptr); + + /* Set the image length size */ + *image_len = (size_t)(H5F_DRVINFOBLOCK_HDR_SIZE + /* Fixed-size portion of driver info block */ + drvinfo->len); /* Variable-size portion of driver info block */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5F__cache_drvrinfo_image_len() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__cache_drvrinfo_serialize + * + * Purpose: Flushes a dirty object to disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 20 2013 * *------------------------------------------------------------------------- */ static herr_t -H5F_sblock_size(const H5F_t *f, const H5F_super_t *sblock, size_t *size_ptr) +H5F__cache_drvrinfo_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + H5O_drvinfo_t *drvinfo = (H5O_drvinfo_t *)_thing; /* Pointer to the object */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint8_t *dbuf; /* Pointer to beginning of driver info */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC /* check arguments */ HDassert(f); - HDassert(sblock); - HDassert(size_ptr); + HDassert(image); + HDassert(drvinfo); + HDassert(drvinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(drvinfo->cache_info.type == H5AC_DRVRINFO); + HDassert(len == (size_t)(H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo->len)); + + /* Save pointer to beginning of driver info */ + dbuf = image; + + /* Encode the driver information block */ + *image++ = HDF5_DRIVERINFO_VERSION_0; /* Version */ + *image++ = 0; /* reserved */ + *image++ = 0; /* reserved */ + *image++ = 0; /* reserved */ + + /* Driver info size, excluding header */ + UINT32ENCODE(image, drvinfo->len); + + /* Encode driver-specific data */ + if(H5FD_sb_encode(f->shared->lf, (char *)image, dbuf + H5F_DRVINFOBLOCK_HDR_SIZE) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode driver information") + + /* Advance buffer pointer past name & variable-sized portion of driver info */ + image += 8 + drvinfo->len; + + /* Sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= len); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5F__cache_drvrinfo_serialize() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__cache_drvrinfo_free_icr + * + * Purpose: Destroy/release an "in core representation" of a data + * structure + * + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 20, 2013 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__cache_drvrinfo_free_icr(void *_thing) +{ + H5O_drvinfo_t *drvinfo = (H5O_drvinfo_t *)_thing; /* Pointer to the object */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(drvinfo); + HDassert(drvinfo->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(drvinfo->cache_info.type == H5AC_DRVRINFO); - /* Set size value */ - *size_ptr = (size_t)H5F_SUPERBLOCK_SIZE(sblock->super_vers, f); + /* Destroy driver info message */ + H5MM_xfree(drvinfo); FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5F_sblock_size() */ +} /* H5F__cache_drvrinfo_free_icr() */ diff --git a/src/H5Gcache.c b/src/H5Gcache.c index bedceb6..4ab5217 100644 --- a/src/H5Gcache.c +++ b/src/H5Gcache.c @@ -46,7 +46,6 @@ /****************/ #define H5G_NODE_VERS 1 /* Symbol table node version number */ -#define H5G_NODE_BUF_SIZE 512 /* Size of stack buffer for serialized nodes */ /******************/ @@ -64,12 +63,16 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static H5G_node_t *H5G_node_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5G_node_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5G_node_t *sym, unsigned *flags_ptr); -static herr_t H5G_node_dest(H5F_t *f, H5G_node_t *sym); -static herr_t H5G_node_clear(H5F_t *f, H5G_node_t *sym, hbool_t destroy); -static herr_t H5G_node_size(const H5F_t *f, const H5G_node_t *sym, size_t *size_ptr); +static herr_t H5G__cache_node_get_load_size(const void *image, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static void *H5G__cache_node_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5G__cache_node_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5G__cache_node_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5G__cache_node_free_icr(void *thing); /*********************/ @@ -88,13 +91,20 @@ static herr_t H5G_node_size(const H5F_t *f, const H5G_node_t *sym, size_t *size_ /* Symbol table nodes inherit cache-like properties from H5AC */ const H5AC_class_t H5AC_SNODE[1] = {{ - H5AC_SNODE_ID, - (H5AC_load_func_t)H5G_node_load, - (H5AC_flush_func_t)H5G_node_flush, - (H5AC_dest_func_t)H5G_node_dest, - (H5AC_clear_func_t)H5G_node_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5G_node_size, + H5AC_SNODE_ID, /* Metadata client ID */ + "Symbol table node", /* Metadata client name (for debugging) */ + H5FD_MEM_BTREE, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5G__cache_node_get_load_size, /* 'get_load_size' callback */ + NULL, /* 'verify_chksum' callback */ + H5G__cache_node_deserialize, /* 'deserialize' callback */ + H5G__cache_node_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5G__cache_node_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5G__cache_node_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -106,42 +116,89 @@ H5FL_SEQ_EXTERN(H5G_entry_t); /*------------------------------------------------------------------------- - * Function: H5G_node_load + * Function: H5G__cache_node_get_load_size() * - * Purpose: Loads a symbol table node from the file. + * Purpose: Determine the size of the on disk image of the node, and + * return this value in *image_len. * - * Return: Success: Ptr to the new table. + * Note that this computation requires access to the file pointer, + * which is not provided in the parameter list for this callback. + * Finesse this issue by passing in the file pointer twice to the + * H5AC_protect() call -- once as the file pointer proper, and + * again as the user data. + * + * Return: Success: SUCCEED + * Failure: FAIL * - * Failure: NULL - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Jun 23 1997 + * Programmer: John Mainzer + * 7/21/14 * *------------------------------------------------------------------------- */ -static H5G_node_t * -H5G_node_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata) +static herr_t +H5G__cache_node_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5G_node_t *sym = NULL; - H5WB_t *wb = NULL; /* Wrapped buffer for node data */ - uint8_t node_buf[H5G_NODE_BUF_SIZE]; /* Buffer for node */ - uint8_t *node; /* Pointer to node buffer */ - const uint8_t *p; - H5G_node_t *ret_value; /*for error handling */ - - FUNC_ENTER_NOAPI_NOINIT - - /* - * Check arguments. - */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer to image to deserialize */ + H5F_t *f = (H5F_t *)_udata; /* User data for callback */ + + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata); + HDassert(image_len); + + if(image == NULL) { + /* report image length */ + *image_len = (size_t)(H5G_NODE_SIZE(f)); + } else { + HDassert(actual_len); + HDassert(*image_len == *actual_len); + } - /* - * Initialize variables. - */ + /* Nothing to do for non-NULL image : no need to compute actual_len */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5G__cache_node_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5G__cache_node_deserialize + * + * Purpose: Given a buffer containing the on disk image of a symbol table + * node, allocate an instance of H5G_node_t, load the contence of the + * image into it, and return a pointer to the instance. + * + * Note that deserializing the image requires access to the file + * pointer, which is not included in the parameter list for this + * callback. Finesse this issue by passing in the file pointer + * twice to the H5AC_protect() call -- once as the file pointer + * proper, and again as the user data + * + * Return: Success: Pointer to in core representation + * Failure: NULL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static void * +H5G__cache_node_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) +{ + H5F_t *f = (H5F_t *)_udata; /* User data for callback */ + H5G_node_t *sym = NULL; /* Symbol table node created */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer to image to deserialize */ + void * ret_value; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(image); + HDassert(len > 0); + HDassert(f); + HDassert(dirty); /* Allocate symbol table data structures */ if(NULL == (sym = H5FL_CALLOC(H5G_node_t))) @@ -150,262 +207,175 @@ H5G_node_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata) if(NULL == (sym->entry = H5FL_SEQ_CALLOC(H5G_entry_t, (size_t)(2 * H5F_SYM_LEAF_K(f))))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - /* Wrap the local buffer for serialized node info */ - if(NULL == (wb = H5WB_wrap(node_buf, sizeof(node_buf)))) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, NULL, "can't wrap buffer") - - /* Get a pointer to a buffer that's large enough for node */ - if(NULL == (node = (uint8_t *)H5WB_actual(wb, sym->node_size))) - HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, NULL, "can't get actual buffer") - - /* Read the serialized symbol table node. */ - if(H5F_block_read(f, H5FD_MEM_BTREE, addr, sym->node_size, dxpl_id, node) < 0) - HGOTO_ERROR(H5E_SYM, H5E_READERROR, NULL, "unable to read symbol table node") - - /* Get temporary pointer to serialized node */ - p = node; - /* magic */ - if(HDmemcmp(p, H5G_NODE_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, NULL, "bad symbol table node signature") - p += H5_SIZEOF_MAGIC; + if(HDmemcmp(image, H5G_NODE_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, NULL, "bad symbol table node signature") + image += H5_SIZEOF_MAGIC; /* version */ - if(H5G_NODE_VERS != *p++) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, NULL, "bad symbol table node version") + if(H5G_NODE_VERS != *image++) + HGOTO_ERROR(H5E_SYM, H5E_VERSION, NULL, "bad symbol table node version") /* reserved */ - p++; + image++; /* number of symbols */ - UINT16DECODE(p, sym->nsyms); + UINT16DECODE(image, sym->nsyms); /* entries */ - if(H5G__ent_decode_vec(f, &p, sym->entry, sym->nsyms) < 0) + if(H5G__ent_decode_vec(f, &image, sym->entry, sym->nsyms) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, NULL, "unable to decode symbol table entries") /* Set return value */ ret_value = sym; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, NULL, "can't close wrapped buffer") if(!ret_value) if(sym && H5G__node_free(sym) < 0) HDONE_ERROR(H5E_SYM, H5E_CANTFREE, NULL, "unable to destroy symbol table node") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5G_node_load() */ +} /* end H5G__cache_node_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5G_node_flush + * Function: H5G__cache_node_image_len * - * Purpose: Flush a symbol table node to disk. + * Purpose: Compute the size of the data structure on disk and return + * it in *image_len. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Jun 23 1997 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ static herr_t -H5G_node_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5G_node_t *sym, unsigned H5_ATTR_UNUSED * flags_ptr) +H5G__cache_node_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5WB_t *wb = NULL; /* Wrapped buffer for node data */ - uint8_t node_buf[H5G_NODE_BUF_SIZE]; /* Buffer for node */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5G_node_t *sym = (const H5G_node_t *)_thing; /* Pointer to object */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* - * Check arguments. - */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ HDassert(sym); + HDassert(sym->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(sym->cache_info.type == H5AC_SNODE); + HDassert(image_len); - /* - * Write the symbol node to disk. - */ - if(sym->cache_info.is_dirty) { - uint8_t *node; /* Pointer to node buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - - /* Wrap the local buffer for serialized node info */ - if(NULL == (wb = H5WB_wrap(node_buf, sizeof(node_buf)))) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't wrap buffer") - - /* Get a pointer to a buffer that's large enough for node */ - if(NULL == (node = (uint8_t *)H5WB_actual(wb, sym->node_size))) - HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "can't get actual buffer") - - /* Get temporary pointer to serialized symbol table node */ - p = node; - - /* magic number */ - HDmemcpy(p, H5G_NODE_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* version number */ - *p++ = H5G_NODE_VERS; - - /* reserved */ - *p++ = 0; - - /* number of symbols */ - UINT16ENCODE(p, sym->nsyms); - - /* entries */ - if(H5G__ent_encode_vec(f, &p, sym->entry, sym->nsyms) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTENCODE, FAIL, "can't serialize") - HDmemset(p, 0, sym->node_size - (size_t)(p - node)); - - /* Write the serialized symbol table node. */ - if(H5F_block_write(f, H5FD_MEM_BTREE, addr, sym->node_size, dxpl_id, node) < 0) - HGOTO_ERROR(H5E_SYM, H5E_WRITEERROR, FAIL, "unable to write symbol table node to the file") + *image_len = sym->node_size; - /* Reset the node's dirty flag */ - sym->cache_info.is_dirty = FALSE; - } /* end if */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5G__cache_node_image_len() */ - /* - * Destroy the symbol node? This might happen if the node is being - * preempted from the cache. - */ - if(destroy) - if(H5G_node_dest(f, sym) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to destroy symbol table node") -done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5G_node_flush() */ +/*************************************/ +/* no H5G__cache_node_pre_serialize() */ +/*************************************/ /*------------------------------------------------------------------------- - * Function: H5G_node_dest + * Function: H5G__cache_node_serialize * - * Purpose: Destroy a symbol table node in memory. + * Purpose: Given a correctly sized buffer and an instace of H5G_node_t, + * serialize the contents of the instance of H5G_node_t, and write + * this data into the supplied buffer. This buffer will be written + * to disk. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Jan 15 2003 + * Programmer: John Mainzer + * 7/21/14 * *------------------------------------------------------------------------- */ static herr_t -H5G_node_dest(H5F_t *f, H5G_node_t *sym) +H5G__cache_node_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5G_node_t *sym = (H5G_node_t *)_thing; /* Pointer to object */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ HDassert(f); + HDassert(image); HDassert(sym); + HDassert(sym->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(sym->cache_info.type == H5AC_SNODE); + HDassert(len == sym->node_size); - /* Verify that node is clean */ - HDassert(sym->cache_info.is_dirty == FALSE); + /* magic number */ + HDmemcpy(image, H5G_NODE_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!sym->cache_info.free_file_space_on_destroy || H5F_addr_defined(sym->cache_info.addr)); + /* version number */ + *image++ = H5G_NODE_VERS; - /* Check for freeing file space for symbol table node */ - if(sym->cache_info.free_file_space_on_destroy) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_BTREE, H5AC_dxpl_id, sym->cache_info.addr, (hsize_t)sym->node_size) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to free symbol table node") - } /* end if */ + /* reserved */ + *image++ = 0; - /* Destroy symbol table node */ - if(H5G__node_free(sym) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to destroy symbol table node") + /* number of symbols */ + UINT16ENCODE(image, sym->nsyms); + + /* entries */ + if(H5G__ent_encode_vec(f, &image, sym->entry, sym->nsyms) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTENCODE, FAIL, "can't serialize") + + /* Clear rest of symbol table node */ + HDmemset(image, 0, sym->node_size - (size_t)(image - (uint8_t *)_image)); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5G_node_dest() */ +} /* end H5G__cache_node_serialize() */ + + +/***************************************/ +/* no H5G__cache_node_notify() function */ +/***************************************/ /*------------------------------------------------------------------------- - * Function: H5G_node_clear + * Function: H5G__cache_node_free_icr * - * Purpose: Mark a symbol table node in memory as non-dirty. + * Purpose: Destroys a symbol table node in memory. * - * Return: Non-negative on success/Negative on failure + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 20 2003 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ static herr_t -H5G_node_clear(H5F_t *f, H5G_node_t *sym, hbool_t destroy) +H5G__cache_node_free_icr(void *_thing) { - herr_t ret_value = SUCCEED; + H5G_node_t *sym = (H5G_node_t *)_thing; /* Pointer to the object */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ HDassert(sym); + HDassert(sym->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(sym->cache_info.type == H5AC_SNODE); - /* Reset the node's dirty flag */ - sym->cache_info.is_dirty = FALSE; - - /* - * Destroy the symbol node? This might happen if the node is being - * preempted from the cache. - */ - if(destroy) - if(H5G_node_dest(f, sym) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to destroy symbol table node") + /* Destroy symbol table node */ + if(H5G__node_free(sym) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to destroy symbol table node") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5G_node_clear() */ - - -/*------------------------------------------------------------------------- - * Function: H5G_node_size - * - * Purpose: Compute the size in bytes of the specified instance of - * H5G_node_t on disk, and return it in *size_ptr. On failure - * the value of size_ptr is undefined. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: John Mainzer - * 5/13/04 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5G_node_size(const H5F_t H5_ATTR_UNUSED *f, const H5G_node_t *sym, size_t *size_ptr) -{ - FUNC_ENTER_NOAPI_NOINIT_NOERR - - /* - * Check arguments. - */ - HDassert(f); - HDassert(size_ptr); - - *size_ptr = sym->node_size; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5G_node_size() */ +} /* end H5G__cache_node_free_icr() */ diff --git a/src/H5Gent.c b/src/H5Gent.c index 86af500..2959a53 100644 --- a/src/H5Gent.c +++ b/src/H5Gent.c @@ -460,7 +460,7 @@ H5G__ent_convert(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, const char *name, targ_oloc.addr = lnk->u.hard.addr; /* Get the object header */ - if(NULL == (oh = H5O_protect(&targ_oloc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(&targ_oloc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect target object header") /* Check if a symbol table message exists */ diff --git a/src/H5Gnode.c b/src/H5Gnode.c index dc954ca..9c4c962 100644 --- a/src/H5Gnode.c +++ b/src/H5Gnode.c @@ -541,7 +541,7 @@ H5G_node_found(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void H5_ATTR_UNUSED /* * Load the symbol table node for exclusive access. */ - if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC_READ))) + if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, "unable to protect symbol table node") /* Get base address of heap */ @@ -647,7 +647,7 @@ H5G_node_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr, /* * Load the symbol node. */ - if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC_WRITE))) + if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5B_INS_ERROR, "unable to protect symbol table node") /* Get base address of heap */ @@ -691,7 +691,7 @@ H5G_node_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr, if(H5G_node_create(f, dxpl_id, H5B_INS_FIRST, NULL, NULL, NULL, new_node_p/*out*/) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5B_INS_ERROR, "unable to split symbol table node") - if(NULL == (snrt = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, *new_node_p, f, H5AC_WRITE))) + if(NULL == (snrt = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, *new_node_p, f, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5B_INS_ERROR, "unable to split symbol table node") HDmemcpy(snrt->entry, sn->entry + H5F_SYM_LEAF_K(f), @@ -808,7 +808,7 @@ H5G_node_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key/*in,out*/, HDassert(udata && udata->common.heap); /* Load the symbol table */ - if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC_WRITE))) + if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5B_INS_ERROR, "unable to protect symbol table node") /* "Normal" removal of a single entry from the symbol table node */ @@ -1001,7 +1001,7 @@ H5G__node_iterate(H5F_t *f, hid_t dxpl_id, const void H5_ATTR_UNUSED *_lt_key, h HDassert(udata && udata->heap); /* Protect the symbol table node & local heap while we iterate over entries */ - if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC_READ))) + if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node") /* @@ -1078,7 +1078,7 @@ H5G__node_sumup(H5F_t *f, hid_t dxpl_id, const void H5_ATTR_UNUSED *_lt_key, had HDassert(num_objs); /* Find the object node and add the number of symbol entries. */ - if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC_READ))) + if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node") *num_objs += sn->nsyms; @@ -1123,7 +1123,7 @@ H5G__node_by_idx(H5F_t *f, hid_t dxpl_id, const void H5_ATTR_UNUSED *_lt_key, ha HDassert(udata); /* Get a pointer to the symbol table node */ - if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC_READ))) + if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node"); /* Find the node, locate the object symbol table entry and retrieve the name */ @@ -1261,11 +1261,11 @@ H5G__node_copy(H5F_t *f, hid_t dxpl_id, const void H5_ATTR_UNUSED *_lt_key, hadd HDassert(udata); /* load the symbol table into memory from the source file */ - if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC_READ))) + if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node") /* get the base address of the heap */ - if(NULL == (heap = H5HL_protect(f, dxpl_id, udata->src_heap_addr, H5AC_READ))) + if(NULL == (heap = H5HL_protect(f, dxpl_id, udata->src_heap_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5_ITER_ERROR, "unable to protect symbol name") /* copy object in this node one by one */ @@ -1420,7 +1420,7 @@ H5G__node_build_table(H5F_t *f, hid_t dxpl_id, const void H5_ATTR_UNUSED *_lt_ke * Save information about the symbol table node since we can't lock it * because we're about to call an application function. */ - if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC_READ))) + if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node") /* Check if the link table needs to be extended */ @@ -1527,14 +1527,14 @@ H5G_node_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent, /* Pin the heap down in memory */ if(heap_addr > 0 && H5F_addr_defined(heap_addr)) - if(NULL == (heap = H5HL_protect(f, dxpl_id, heap_addr, H5AC_READ))) + if(NULL == (heap = H5HL_protect(f, dxpl_id, heap_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, "unable to protect symbol table heap") /* * If we couldn't load the symbol table node, then try loading the * B-tree node. */ - if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC_READ))) { + if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) { H5G_bt_common_t udata; /*data to pass through B-tree */ H5E_clear_stack(NULL); /* discard that error */ diff --git a/src/H5Gstab.c b/src/H5Gstab.c index 6c7e828..a5c5d3e 100644 --- a/src/H5Gstab.c +++ b/src/H5Gstab.c @@ -160,7 +160,7 @@ H5G__stab_create_components(H5F_t *f, H5O_stab_t *stab, size_t size_hint, hid_t HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create heap") /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(f, dxpl_id, stab->heap_addr, H5AC_WRITE))) + if(NULL == (heap = H5HL_protect(f, dxpl_id, stab->heap_addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap") /* Insert name into the heap */ @@ -276,7 +276,7 @@ H5G__stab_insert_real(H5F_t *f, const H5O_stab_t *stab, const char *name, HDassert(obj_lnk); /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(f, dxpl_id, stab->heap_addr, H5AC_WRITE))) + if(NULL == (heap = H5HL_protect(f, dxpl_id, stab->heap_addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap") /* Initialize data to pass through B-tree */ @@ -373,7 +373,7 @@ H5G__stab_remove(const H5O_loc_t *loc, hid_t dxpl_id, H5RS_str_t *grp_full_path_ HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table") /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(loc->file, dxpl_id, stab.heap_addr, H5AC_WRITE))) + if(NULL == (heap = H5HL_protect(loc->file, dxpl_id, stab.heap_addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap") /* Initialize data to pass through B-tree */ @@ -431,7 +431,7 @@ H5G__stab_remove_by_idx(const H5O_loc_t *grp_oloc, hid_t dxpl_id, H5RS_str_t *gr HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table") /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC_WRITE))) + if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap") /* Initialize data to pass through B-tree */ @@ -485,7 +485,7 @@ H5G__stab_delete(H5F_t *f, hid_t dxpl_id, const H5O_stab_t *stab) HDassert(H5F_addr_defined(stab->heap_addr)); /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(f, dxpl_id, stab->heap_addr, H5AC_WRITE))) + if(NULL == (heap = H5HL_protect(f, dxpl_id, stab->heap_addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap") /* Set up user data for B-tree deletion */ @@ -546,7 +546,7 @@ H5G__stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, H5_iter_order_t order, HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address") /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(oloc->file, dxpl_id, stab.heap_addr, H5AC_READ))) + if(NULL == (heap = H5HL_protect(oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap") /* Check on iteration order */ @@ -766,7 +766,7 @@ H5G__stab_get_name_by_idx(const H5O_loc_t *oloc, H5_iter_order_t order, hsize_t HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address") /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(oloc->file, dxpl_id, stab.heap_addr, H5AC_READ))) + if(NULL == (heap = H5HL_protect(oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap") /* Remap index for decreasing iteration order */ @@ -888,7 +888,7 @@ H5G__stab_lookup(const H5O_loc_t *grp_oloc, const char *name, H5O_link_t *lnk, HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't read message") /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC_READ))) + if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap") /* Set up user data to pass to 'find' operation callback */ @@ -989,7 +989,7 @@ H5G__stab_lookup_by_idx(const H5O_loc_t *grp_oloc, H5_iter_order_t order, hsize_ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address") /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC_READ))) + if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap") /* Remap index for decreasing iteration order */ @@ -1081,10 +1081,10 @@ H5G__stab_valid(H5O_loc_t *grp_oloc, hid_t dxpl_id, H5O_stab_t *alt_stab) } /* end if */ /* Check if the symbol table message's heap address is valid */ - if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC_READ))) { + if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG))) { /* Address is invalid, try the heap address in the alternate symbol * table message */ - if(!alt_stab || NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, alt_stab->heap_addr, H5AC_READ))) + if(!alt_stab || NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, alt_stab->heap_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "unable to locate heap") else { /* The alternate symbol table's heap address is valid. Adjust the diff --git a/src/H5Gtest.c b/src/H5Gtest.c index 981946d..412389b 100644 --- a/src/H5Gtest.c +++ b/src/H5Gtest.c @@ -637,7 +637,7 @@ H5G__verify_cached_stab_test(H5O_loc_t *grp_oloc, H5G_entry_t *ent) HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "b-tree address is invalid") /* Verify that the heap address is valid */ - if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC_READ))) + if(NULL == (heap = H5HL_protect(grp_oloc->file, dxpl_id, stab.heap_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "heap address is invalid") done: @@ -686,7 +686,7 @@ H5G_verify_cached_stabs_test_cb(H5F_t *f, hid_t dxpl_id, HDassert(H5F_addr_defined(addr)); /* Load the node */ - if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC_READ))) + if(NULL == (sn = (H5G_node_t *)H5AC_protect(f, dxpl_id, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node") /* Check each target object to see if its stab message (if present) matches @@ -701,7 +701,7 @@ H5G_verify_cached_stabs_test_cb(H5F_t *f, hid_t dxpl_id, targ_oloc.addr = sn->entry[i].header; /* Load target object header */ - if(NULL == (targ_oh = H5O_protect(&targ_oloc, dxpl_id, H5AC_READ))) + if(NULL == (targ_oh = H5O_protect(&targ_oloc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to protect target object header") /* Check if a symbol table message exists */ @@ -172,7 +172,7 @@ H5HF_create(H5F_t *f, hid_t dxpl_id, const H5HF_create_t *cparam) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed for fractal heap info") /* Lock the heap header into memory */ - if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC_WRITE))) + if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header") /* Point fractal heap wrapper at header and bump it's ref count */ @@ -231,7 +231,7 @@ H5HF_open(H5F_t *f, hid_t dxpl_id, haddr_t fh_addr) HDassert(H5F_addr_defined(fh_addr)); /* Load the heap header into memory */ - if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC_READ))) + if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header") /* Check for pending heap deletion */ @@ -821,7 +821,7 @@ H5HF_close(H5HF_t *fh, hid_t dxpl_id) H5HF_hdr_t *hdr; /* Another pointer to fractal heap header */ /* Lock the heap header into memory */ - if(NULL == (hdr = H5HF_hdr_protect(fh->f, dxpl_id, heap_addr, H5AC_WRITE))) + if(NULL == (hdr = H5HF_hdr_protect(fh->f, dxpl_id, heap_addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header") /* Delete heap, starting with header (unprotects header) */ @@ -865,7 +865,7 @@ H5HF_delete(H5F_t *f, hid_t dxpl_id, haddr_t fh_addr) HDassert(H5F_addr_defined(fh_addr)); /* Lock the heap header into memory */ - if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC_WRITE))) + if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header") /* Check for files using shared heap header */ diff --git a/src/H5HFcache.c b/src/H5HFcache.c index 4b02e06..7171da9 100644 --- a/src/H5HFcache.c +++ b/src/H5HFcache.c @@ -1,4 +1,4 @@ -/* / * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * @@ -53,20 +53,6 @@ #define H5HF_DBLOCK_VERSION 0 /* Direct block */ #define H5HF_IBLOCK_VERSION 0 /* Indirect block */ -/* Size of stack buffer for serialized headers */ -#define H5HF_HDR_BUF_SIZE 512 - -/* Size of stack buffer for serialized indirect blocks */ -#define H5HF_IBLOCK_BUF_SIZE 4096 - -/* Size of minimum header to decode for determining the full header size */ -#define H5HF_MIN_HEADER_SIZE ( \ - H5_SIZEOF_MAGIC + /* Signature */ \ - 1 + /* Version */ \ - 2 + /* Heap ID len */ \ - 2 /* I/O filters' encoded len */ \ - ) - /******************/ /* Local Typedefs */ @@ -87,24 +73,57 @@ static herr_t H5HF__dtable_encode(H5F_t *f, uint8_t **pp, const H5HF_dtable_t *d static herr_t H5HF__dtable_decode(H5F_t *f, const uint8_t **pp, H5HF_dtable_t *dtable); /* Metadata cache (H5AC) callbacks */ -static H5HF_hdr_t *H5HF_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5HF_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_hdr_t *hdr, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5HF_cache_hdr_dest(H5F_t *f, H5HF_hdr_t *hdr); -static herr_t H5HF_cache_hdr_clear(H5F_t *f, H5HF_hdr_t *hdr, hbool_t destroy); -static herr_t H5HF_cache_hdr_size(const H5F_t *f, const H5HF_hdr_t *hdr, size_t *size_ptr); -static H5HF_indirect_t *H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5HF_cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_indirect_t *iblock, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5HF_cache_iblock_dest(H5F_t *f, H5HF_indirect_t *iblock); -static herr_t H5HF_cache_iblock_clear(H5F_t *f, H5HF_indirect_t *iblock, hbool_t destroy); -static herr_t H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock); -static herr_t H5HF_cache_iblock_size(const H5F_t *f, const H5HF_indirect_t *iblock, size_t *size_ptr); -static H5HF_direct_t *H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5HF_cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_direct_t *dblock, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5HF_cache_dblock_dest(H5F_t *f, H5HF_direct_t *dblock); -static herr_t H5HF_cache_dblock_clear(H5F_t *f, H5HF_direct_t *dblock, hbool_t destroy); -static herr_t H5HF_cache_dblock_notify(H5C_notify_action_t action, H5HF_direct_t *dblock); -static herr_t H5HF_cache_dblock_size(const H5F_t *f, const H5HF_direct_t *dblock, size_t *size_ptr); - +static herr_t H5HF__cache_hdr_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5HF__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5HF__cache_hdr_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5HF__cache_hdr_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5HF__cache_hdr_pre_serialize(const H5F_t *f, hid_t dxpl_id, + void *thing, haddr_t addr, size_t len, size_t compressed_len, + haddr_t *new_addr, size_t *new_len, size_t *new_compressed_len, + unsigned *flags); +static herr_t H5HF__cache_hdr_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5HF__cache_hdr_free_icr(void *thing); + +static herr_t H5HF__cache_iblock_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5HF__cache_iblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5HF__cache_iblock_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5HF__cache_iblock_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5HF__cache_iblock_pre_serialize(const H5F_t *f, hid_t dxpl_id, + void *thing, haddr_t addr, size_t len, size_t compressed_len, + haddr_t *new_addr, size_t *new_len, size_t *new_compressed_len, + unsigned *flags); +static herr_t H5HF__cache_iblock_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5HF__cache_iblock_notify(H5C_notify_action_t action, void *thing); +static herr_t H5HF__cache_iblock_free_icr(void *thing); + +static herr_t H5HF__cache_dblock_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5HF__cache_dblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5HF__cache_dblock_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5HF__cache_dblock_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5HF__cache_dblock_pre_serialize(const H5F_t *f, hid_t dxpl_id, + void *thing, haddr_t addr, size_t len, size_t compressed_len, + haddr_t *new_addr, size_t *new_len, size_t *new_compressed_len, + unsigned *flags); +static herr_t H5HF__cache_dblock_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5HF__cache_dblock_notify(H5C_notify_action_t action, void *thing); +static herr_t H5HF__cache_dblock_free_icr(void *thing); /* Debugging Function Prototypes */ #ifndef NDEBUG @@ -125,35 +144,56 @@ static herr_t H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f, hid_t dxpl_i /* H5HF header inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FHEAP_HDR[1] = {{ - H5AC_FHEAP_HDR_ID, - (H5AC_load_func_t)H5HF_cache_hdr_load, - (H5AC_flush_func_t)H5HF_cache_hdr_flush, - (H5AC_dest_func_t)H5HF_cache_hdr_dest, - (H5AC_clear_func_t)H5HF_cache_hdr_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5HF_cache_hdr_size, + H5AC_FHEAP_HDR_ID, /* Metadata client ID */ + "fractal heap header", /* Metadata client name (for debugging) */ + H5FD_MEM_FHEAP_HDR, /* File space memory type for client */ + H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ + H5HF__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5HF__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ + H5HF__cache_hdr_deserialize, /* 'deserialize' callback */ + H5HF__cache_hdr_image_len, /* 'image_len' callback */ + H5HF__cache_hdr_pre_serialize, /* 'pre_serialize' callback */ + H5HF__cache_hdr_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5HF__cache_hdr_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* H5HF indirect block inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FHEAP_IBLOCK[1] = {{ - H5AC_FHEAP_IBLOCK_ID, - (H5AC_load_func_t)H5HF_cache_iblock_load, - (H5AC_flush_func_t)H5HF_cache_iblock_flush, - (H5AC_dest_func_t)H5HF_cache_iblock_dest, - (H5AC_clear_func_t)H5HF_cache_iblock_clear, - (H5AC_notify_func_t)H5HF_cache_iblock_notify, - (H5AC_size_func_t)H5HF_cache_iblock_size, + H5AC_FHEAP_IBLOCK_ID, /* Metadata client ID */ + "fractal heap indirect block", /* Metadata client name (for debugging) */ + H5FD_MEM_FHEAP_IBLOCK, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5HF__cache_iblock_get_load_size, /* 'get_load_size' callback */ + H5HF__cache_iblock_verify_chksum, /* 'verify_chksum' callback */ + H5HF__cache_iblock_deserialize, /* 'deserialize' callback */ + H5HF__cache_iblock_image_len, /* 'image_len' callback */ + H5HF__cache_iblock_pre_serialize, /* 'pre_serialize' callback */ + H5HF__cache_iblock_serialize, /* 'serialize' callback */ + H5HF__cache_iblock_notify, /* 'notify' callback */ + H5HF__cache_iblock_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* H5HF direct block inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FHEAP_DBLOCK[1] = {{ - H5AC_FHEAP_DBLOCK_ID, - (H5AC_load_func_t)H5HF_cache_dblock_load, - (H5AC_flush_func_t)H5HF_cache_dblock_flush, - (H5AC_dest_func_t)H5HF_cache_dblock_dest, - (H5AC_clear_func_t)H5HF_cache_dblock_clear, - (H5AC_notify_func_t)H5HF_cache_dblock_notify, - (H5AC_size_func_t)H5HF_cache_dblock_size, + H5AC_FHEAP_DBLOCK_ID, /* Metadata client ID */ + "fractal heap direct block", /* Metadata client name (for debugging) */ + H5FD_MEM_FHEAP_DBLOCK, /* File space memory type for client */ + H5C__CLASS_COMPRESSED_FLAG, /* Client class behavior flags */ + H5HF__cache_dblock_get_load_size, /* 'get_load_size' callback */ + H5HF__cache_dblock_verify_chksum, /* 'verify_chksum' callback */ + H5HF__cache_dblock_deserialize, /* 'deserialize' callback */ + H5HF__cache_dblock_image_len, /* 'image_len' callback */ + H5HF__cache_dblock_pre_serialize, /* 'pre_serialize' callback */ + H5HF__cache_dblock_serialize, /* 'serialize' callback */ + H5HF__cache_dblock_notify, /* 'notify' callback */ + H5HF__cache_dblock_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -272,174 +312,294 @@ H5HF__dtable_encode(H5F_t *f, uint8_t **pp, const H5HF_dtable_t *dtable) /*------------------------------------------------------------------------- - * Function: H5HF_cache_hdr_load + * Function: H5HF__cache_hdr_get_load_size() * - * Purpose: Loads a fractal heap header from the disk. + * Purpose: Determine the size of the fractal heap header on disk, + * and set *image_len to this value. * - * Return: Success: Pointer to a new fractal heap + * This code is based on the old H5HF_cache_hdr_load() routine + * that was used with the version 2 metadata cache. Note the + * use of a dummy header to compute the on disk size of the header. + * + * Note also that the value returned by this function presumes that + * there is no I/O filtering data in the header. If there is, the + * size reported will be too small, and H5C_load_entry() + * will have to make two tries to load the fractal heap header. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_hdr_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; /* pointer to user data */ + H5HF_hdr_t dummy_hdr; /* dummy header -- to compute size */ + unsigned id_len; /* Size of heap IDs (in bytes) */ + unsigned filter_len; /* Size of I/O filter information (in bytes) */ + size_t filter_info_size; /* Size of filter information */ + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(udata); + HDassert(image_len); + + if(image == NULL) { + /* Set the internal parameters for the heap */ + dummy_hdr.f = udata->f; + dummy_hdr.sizeof_size = H5F_SIZEOF_SIZE(udata->f); + dummy_hdr.sizeof_addr = H5F_SIZEOF_ADDR(udata->f); + + /* Compute the 'base' size of the fractal heap header on disk */ + *image_len = (size_t)H5HF_HEADER_SIZE(&dummy_hdr); + + } else { /* compute actual_len */ + + HDassert(actual_len); + HDassert(*actual_len == *image_len); + + /* Magic number */ + if(HDmemcmp(image, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_DONE(FAIL) + image += H5_SIZEOF_MAGIC; + + /* Version */ + if(*image++ != H5HF_HDR_VERSION) + HGOTO_DONE(FAIL) + + /* General heap information */ + UINT16DECODE(image, id_len); /* Heap ID length */ + UINT16DECODE(image, filter_len); /* I/O filters' encoded length */ + + if(filter_len > 0) { + + /* Compute the size of the extra filter information */ + filter_info_size = (size_t)(H5F_SIZEOF_SIZE(udata->f) /* Size of size for filtered root direct block */ + + (unsigned)4 /* Size of filter mask for filtered root direct block */ + + filter_len); /* Size of encoded I/O filter info */ + + /* Compute the heap header's size */ + *actual_len += filter_info_size; + } + + } /* compute actual_len */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_hdr_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_hdr_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_hdr_verify_chksum() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_hdr_deserialize + * + * Purpose: Given a buffer containing an on disk image of a fractal heap + * header block, allocate an instance of H5HF_hdr_t, load the contents + * of the buffer into into the new instance of H5HF_hdr_t, and then + * return a pointer to the new instance. + * + * Since H5HF__cache_hdr_get_load_size() reports header on disk size + * base on the assumption that the header contains no I/O filtering + * data, it is possible that the provided image will be too small. + * + * In this case, we DO NOT flag an error when this is discovered. + * Instead, we make note of the correct image size, and report + * success. + * + * Since H5HF__cache_hdr_image_len() callback is defined, + * H5C_load_entry() will call H5HF__cache_hdr_image_len() and + * obtain the correct image length. + * + * Since the H5AC__CLASS_SPECULATIVE_LOAD_FLAG is set, + * H5C_load_entry() will load an image of the correct size, and + * then call this function again to deserialize it. Before doing + * so, it will also call H5HF__cache_hdr_free_icr() to discard the + * result of the first deserialize call. + * + * Note that the v2 B-tree and free space manager associated + * with the fractal heap (roots stored in the huge_bt2 and fspace + * fields respectively) are not loaded at this time. As best I can + * tell from reviewing the code, they are loaded or created when + * they are accessed. + * + * Return: Success: Pointer to in core representation * Failure: NULL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static H5HF_hdr_t * -H5HF_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5HF__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { - H5HF_hdr_t *hdr = NULL; /* Fractal heap info */ - H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; - size_t min_size; /* Header size */ - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5HF_HDR_BUF_SIZE]; /* Buffer for header */ - uint8_t *buf; /* Pointer to header buffer */ - size_t buf_size; /* Current size of temporary buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5HF_hdr_t *hdr = NULL; /* Fractal heap info */ + H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; /* User data for callback */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into into supplied image */ + size_t size; /* Header size */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ - unsigned tries, max_tries; /* The # of read attempts */ - unsigned retries; /* The # of retries */ uint8_t heap_flags; /* Status flags for heap */ - H5HF_hdr_t *ret_value; /* Return value */ + void * ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ + HDassert(image); + HDassert(len > 0); HDassert(udata); + HDassert(dirty); /* Allocate space for the fractal heap data structure */ if(NULL == (hdr = H5HF_hdr_alloc(udata->f))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't wrap buffer") - - /* Compute the minimum size of the fractal heap header to determine filter info */ - min_size = (size_t)H5HF_MIN_HEADER_SIZE; - - /* Get a pointer to a buffer that's large enough for serialized header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, min_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "can't get actual buffer") - buf_size = min_size; - - /* Get the # of read attempts */ - tries = max_tries = H5F_GET_READ_ATTEMPTS(udata->f); - retries = 0; - do { - /* Read minimum header from disk */ - if(H5F_block_read(udata->f, H5FD_MEM_FHEAP_HDR, addr, min_size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "can't read fractal heap header") - - /* Get temporary pointer to serialized header */ - p = buf; - - /* Magic number */ - if(HDmemcmp(p, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - continue; /* Transfer control to while() and count this as a bad read, not an error */ - p += H5_SIZEOF_MAGIC; - - /* Version */ - if(*p++ != H5HF_HDR_VERSION) - continue; /* Transfer control to while() and count this as a bad read, not an error */ - - /* General heap information */ - UINT16DECODE(p, hdr->id_len); /* Heap ID length */ - UINT16DECODE(p, hdr->filter_len); /* I/O filters' encoded length */ - - /* Fixed-size header length */ - hdr->heap_size = (size_t)H5HF_HEADER_SIZE(hdr); - - /* Check for I/O filter information to decode */ - if(hdr->filter_len > 0) - /* Add the variable-len I/O filter information */ - hdr->heap_size += (size_t)(hdr->sizeof_size /* Size of size for filtered root direct block */ - + (unsigned)4 /* Size of filter mask for filtered root direct block */ - + hdr->filter_len); /* Size of encoded I/O filter info */ - - /* Check if we need to resize the buffer */ - if(hdr->heap_size > buf_size) { - /* Re-size current buffer */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, hdr->heap_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "can't get actual buffer") - buf_size = hdr->heap_size; - } /* end if */ - - /* Read the whole header, possibly with filter info */ - /* (Can't use H5F_read_check_metadata() since the length from the - * minimum-sized header info might be incorrect. -QAK) - */ - if(H5F_block_read(udata->f, H5FD_MEM_FHEAP_HDR, addr, hdr->heap_size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "can't read remainder of fractal heap header") - - /* Retrieve stored and computed checksums */ - H5F_get_checksums(buf, hdr->heap_size, &stored_chksum, &computed_chksum); + /* Compute the 'base' size of the fractal heap header on disk */ + size = (size_t)H5HF_HEADER_SIZE(hdr); - /* Verify checksum */ - if(stored_chksum == computed_chksum) - break; - } while (--tries); + /* the size we have just calculated presumes that there is no I/O + * filter information in the header. If there is no filter information, + * the deserialize operation should succeed. + * + * If there is filter information, the first attempt to deserialize + * the header will reveal this. In this case, we will be unable to + * deserialize the header as the supplied image will be too small. + * However, we will make note of the correct size and report success + * anyway. + * + * When H5C_load_entry() calls H5HF__cache_hdr_image_len(), we will report + * the correct size. Since the H5C__CLASS_SPECULATIVE_LOAD_FLAG is set, + * this will prompt H5C_load_entry() to load the correct size image, + * discard the result of the first attempt at deserialization, and + * call this routine a second time to deserialize the correct size + * buffer. + */ + HDassert(size <= len); - if(tries == 0) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "incorrect metadata checksum after all tries (%u) for fractal heap header", max_tries) + /* Magic number */ + if(HDmemcmp(image, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "wrong fractal heap header signature") + image += H5_SIZEOF_MAGIC; - /* Calculate and track the # of retry */ - retries += (max_tries - tries); - if(retries) /* Does not track 0 retry */ - if(H5F_track_metadata_read_retries(udata->f, H5AC_FHEAP_HDR_ID, retries) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "cannot track read tries = %u ", retries) + /* Version */ + if(*image++ != H5HF_HDR_VERSION) + HGOTO_ERROR(H5E_HEAP, H5E_VERSION, NULL, "wrong fractal heap header version") - /* Reset pointer into [possibly] re-sized buffer */ - /* (Skip over information decoded earlier) */ - p = buf + min_size; + /* General heap information */ + UINT16DECODE(image, hdr->id_len); /* Heap ID length */ + UINT16DECODE(image, hdr->filter_len); /* I/O filters' encoded length */ /* Heap status flags */ /* (bit 0: "huge" object IDs have wrapped) */ /* (bit 1: checksum direct blocks) */ - heap_flags = *p++; + heap_flags = *image++; hdr->huge_ids_wrapped = heap_flags & H5HF_HDR_FLAGS_HUGE_ID_WRAPPED; hdr->checksum_dblocks = heap_flags & H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS; /* "Huge" object information */ - UINT32DECODE(p, hdr->max_man_size); /* Max. size of "managed" objects */ - H5F_DECODE_LENGTH(udata->f, p, hdr->huge_next_id); /* Next ID to use for "huge" object */ - H5F_addr_decode(udata->f, &p, &hdr->huge_bt2_addr); /* Address of "huge" object tracker B-tree */ + UINT32DECODE(image, hdr->max_man_size); /* Max. size of "managed" objects */ + H5F_DECODE_LENGTH(udata->f, image, hdr->huge_next_id); /* Next ID to use for "huge" object */ + H5F_addr_decode(udata->f, &image, &hdr->huge_bt2_addr); /* Address of "huge" object tracker B-tree */ /* "Managed" object free space information */ - H5F_DECODE_LENGTH(udata->f, p, hdr->total_man_free); /* Internal free space in managed direct blocks */ - H5F_addr_decode(udata->f, &p, &hdr->fs_addr); /* Address of free section header */ + H5F_DECODE_LENGTH(udata->f, image, hdr->total_man_free); /* Internal free space in managed direct blocks */ + H5F_addr_decode(udata->f, &image, &hdr->fs_addr); /* Address of free section header */ /* Heap statistics */ - H5F_DECODE_LENGTH(udata->f, p, hdr->man_size); - H5F_DECODE_LENGTH(udata->f, p, hdr->man_alloc_size); - H5F_DECODE_LENGTH(udata->f, p, hdr->man_iter_off); - H5F_DECODE_LENGTH(udata->f, p, hdr->man_nobjs); - H5F_DECODE_LENGTH(udata->f, p, hdr->huge_size); - H5F_DECODE_LENGTH(udata->f, p, hdr->huge_nobjs); - H5F_DECODE_LENGTH(udata->f, p, hdr->tiny_size); - H5F_DECODE_LENGTH(udata->f, p, hdr->tiny_nobjs); + H5F_DECODE_LENGTH(udata->f, image, hdr->man_size); + H5F_DECODE_LENGTH(udata->f, image, hdr->man_alloc_size); + H5F_DECODE_LENGTH(udata->f, image, hdr->man_iter_off); + H5F_DECODE_LENGTH(udata->f, image, hdr->man_nobjs); + H5F_DECODE_LENGTH(udata->f, image, hdr->huge_size); + H5F_DECODE_LENGTH(udata->f, image, hdr->huge_nobjs); + H5F_DECODE_LENGTH(udata->f, image, hdr->tiny_size); + H5F_DECODE_LENGTH(udata->f, image, hdr->tiny_nobjs); /* Managed objects' doubling-table info */ - if(H5HF__dtable_decode(udata->f, &p, &(hdr->man_dtable)) < 0) + if(H5HF__dtable_decode(hdr->f, &image, &(hdr->man_dtable)) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, NULL, "unable to encode managed obj. doubling table info") + /* Sanity check */ + /* (allow for checksum not decoded yet) */ + HDassert((size_t)(image - (const uint8_t *)_image) == (size - H5HF_SIZEOF_CHKSUM)); + /* Check for I/O filter information to decode */ if(hdr->filter_len > 0) { + size_t filter_info_size; /* Size of filter information */ H5O_pline_t *pline; /* Pipeline information from the header on disk */ + /* Compute the size of the extra filter information */ + filter_info_size = (size_t)(hdr->sizeof_size /* Size of size for filtered root direct block */ + + (unsigned)4 /* Size of filter mask for filtered root direct block */ + + hdr->filter_len); /* Size of encoded I/O filter info */ + + /* Compute the heap header's size */ + hdr->heap_size = size + filter_info_size; + + if(size == len) + /* we were supplied with too small a buffer -- goto done + * and let H5C_load_entry() retry with a larger buffer + */ + HGOTO_DONE((void *)hdr) + + else + if((size + filter_info_size) != len) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "bad image len") + /* Decode the size of a filtered root direct block */ - H5F_DECODE_LENGTH(udata->f, p, hdr->pline_root_direct_size); + H5F_DECODE_LENGTH(udata->f, image, hdr->pline_root_direct_size); /* Decode the filter mask for a filtered root direct block */ - UINT32DECODE(p, hdr->pline_root_direct_filter_mask); + UINT32DECODE(image, hdr->pline_root_direct_filter_mask); /* Decode I/O filter information */ - if(NULL == (pline = (H5O_pline_t *)H5O_msg_decode(udata->f, udata->dxpl_id, NULL, H5O_PLINE_ID, p))) + if(NULL == (pline = (H5O_pline_t *)H5O_msg_decode(hdr->f, udata->dxpl_id, NULL, H5O_PLINE_ID, image))) HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, NULL, "can't decode I/O pipeline filters") - p += hdr->filter_len; + + image += hdr->filter_len; /* Copy the information into the header's I/O pipeline structure */ if(NULL == H5O_msg_copy(H5O_PLINE_ID, pline, &(hdr->pline))) @@ -448,354 +608,441 @@ H5HF_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) /* Release the space allocated for the I/O pipeline filters */ H5O_msg_free(H5O_PLINE_ID, pline); } /* end if */ + else + /* Set the heap header's size */ + hdr->heap_size = size; + + /* checksum verification already done in verify_chksum cb */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - (const uint8_t *)buf) == (hdr->heap_size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == hdr->heap_size); /* Finish initialization of heap header */ if(H5HF_hdr_finish_init(hdr) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "can't finish initializing shared fractal heap header") /* Set return value */ - ret_value = hdr; + ret_value = (void *)hdr; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, NULL, "can't close wrapped buffer") if(!ret_value && hdr) if(H5HF_hdr_free(hdr) < 0) HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "unable to release fractal heap header") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_hdr_load() */ /*lint !e818 Can't make udata a pointer to const */ +} /* end H5HF__cache_hdr_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_hdr_flush + * Function: H5HF__cache_hdr_image_len * - * Purpose: Flushes a dirty fractal heap header to disk. + * Purpose: Return the actual size of the fractal heap header on + * disk image. * - * Return: Non-negative on success/Negative on failure + * If the header contains filter information, this size will be + * larger than the value returned by H5HF__cache_hdr_get_load_size(). * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_hdr_t *hdr, unsigned H5_ATTR_UNUSED * flags_ptr) +static herr_t +H5HF__cache_hdr_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5HF_HDR_BUF_SIZE]; /* Buffer for header */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5HF_hdr_t *hdr = (const H5HF_hdr_t *)_thing; /* Fractal heap info */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + HDassert(image_len); - if(hdr->cache_info.is_dirty) { - uint8_t *buf; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t size; /* Header size on disk */ - uint8_t heap_flags; /* Status flags for heap */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - -#ifndef NDEBUG -{ - /* Verify that flush dependencies are working correctly. Do this - * by verifying that either: - * - * 1) the header has a root iblock, and that the root iblock and all - * of its children are clean, or - * - * 2) The header has a root dblock, which is clean, or - * - * 3) The heap is empty, and thus the header has neither a root - * iblock no a root dblock. In this case, the flush ordering - * constraint is met by default. - * - * Do this with a call to H5HF__cache_verify_hdr_descendants_clean(). - */ - hbool_t descendants_clean = TRUE; + *image_len = hdr->heap_size; - if(H5HF__cache_verify_hdr_descendants_clean(f, dxpl_id, hdr, &descendants_clean) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify hdr descendants clean.") - HDassert(descendants_clean); -} -#endif /* NDEBUG */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HF__cache_hdr_image_len() */ - /* Set the shared heap header's file context for this operation */ - hdr->f = f; - - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't wrap buffer") - - /* Compute the size of the heap header on disk */ - size = hdr->heap_size; - - /* Get a pointer to a buffer that's large enough for serialized header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "can't get actual buffer") - - /* Get temporary pointer to serialized header */ - p = buf; - - /* Magic number */ - HDmemcpy(p, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5HF_HDR_VERSION; - - /* General heap information */ - UINT16ENCODE(p, hdr->id_len); /* Heap ID length */ - UINT16ENCODE(p, hdr->filter_len); /* I/O filters' encoded length */ - - /* Heap status flags */ - /* (bit 0: "huge" object IDs have wrapped) */ - /* (bit 1: checksum direct blocks) */ - heap_flags = 0; - heap_flags = (uint8_t)(heap_flags | (hdr->huge_ids_wrapped ? H5HF_HDR_FLAGS_HUGE_ID_WRAPPED : 0)); - heap_flags = (uint8_t)(heap_flags | (hdr->checksum_dblocks ? H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS : 0)); - *p++ = heap_flags; - - /* "Huge" object information */ - UINT32ENCODE(p, hdr->max_man_size); /* Max. size of "managed" objects */ - H5F_ENCODE_LENGTH(f, p, hdr->huge_next_id); /* Next ID to use for "huge" object */ - H5F_addr_encode(f, &p, hdr->huge_bt2_addr); /* Address of "huge" object tracker B-tree */ - - /* "Managed" object free space information */ - H5F_ENCODE_LENGTH(f, p, hdr->total_man_free); /* Internal free space in managed direct blocks */ - H5F_addr_encode(f, &p, hdr->fs_addr); /* Address of free section header */ - - /* Heap statistics */ - H5F_ENCODE_LENGTH(f, p, hdr->man_size); - H5F_ENCODE_LENGTH(f, p, hdr->man_alloc_size); - H5F_ENCODE_LENGTH(f, p, hdr->man_iter_off); - H5F_ENCODE_LENGTH(f, p, hdr->man_nobjs); - H5F_ENCODE_LENGTH(f, p, hdr->huge_size); - H5F_ENCODE_LENGTH(f, p, hdr->huge_nobjs); - H5F_ENCODE_LENGTH(f, p, hdr->tiny_size); - H5F_ENCODE_LENGTH(f, p, hdr->tiny_nobjs); - - /* Managed objects' doubling-table info */ - if(H5HF__dtable_encode(hdr->f, &p, &(hdr->man_dtable)) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, FAIL, "unable to encode managed obj. doubling table info") - - /* Check for I/O filter information to encode */ - if(hdr->filter_len > 0) { - /* Encode the size of a filtered root direct block */ - H5F_ENCODE_LENGTH(f, p, hdr->pline_root_direct_size); + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_hdr_pre_serialize + * + * Purpose: As best I can tell, fractal heap header blocks are always + * allocated in real file space. Thus this routine simply verifies + * this, verifies that the len parameter contains the expected + * value, and returns an error if either of these checks fail. + * + * When compiled in debug mode, the function also verifies that all + * indirect and direct blocks that are children of the header are + * either clean, or not in the metadata cache. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_hdr_pre_serialize(const H5F_t *f, hid_t dxpl_id, void *_thing, + haddr_t addr, size_t len, size_t H5_ATTR_UNUSED compressed_len, + haddr_t H5_ATTR_UNUSED *new_addr, size_t H5_ATTR_UNUSED *new_len, + size_t H5_ATTR_UNUSED *new_compressed_len, unsigned *flags) +{ + H5HF_hdr_t *hdr = (H5HF_hdr_t *)_thing; /* Fractal heap info */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Encode the filter mask for a filtered root direct block */ - UINT32ENCODE(p, hdr->pline_root_direct_filter_mask); + FUNC_ENTER_STATIC - /* Encode I/O filter information */ - if(H5O_msg_encode(hdr->f, H5O_PLINE_ID, FALSE, p, &(hdr->pline)) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, FAIL, "can't encode I/O pipeline fiters") - p += hdr->filter_len; - } /* end if */ + /* Sanity checks */ + HDassert(f); + HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + HDassert(H5F_addr_defined(addr)); + HDassert(addr == hdr->heap_addr); + HDassert(new_addr); + HDassert(new_len); + HDassert(flags); - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); +#ifndef NDEBUG +{ + hbool_t descendants_clean = TRUE; - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); + /* Verify that flush dependencies are working correctly. Do this + * by verifying that either: + * + * 1) the header has a root iblock, and that the root iblock and all + * of its children are clean, or + * + * 2) The header has a root dblock, which is clean, or + * + * 3) The heap is empty, and thus the header has neither a root + * iblock no a root dblock. In this case, the flush ordering + * constraint is met by default. + * + * Do this with a call to H5HF__cache_verify_hdr_descendants_clean(). + */ + if(H5HF__cache_verify_hdr_descendants_clean((H5F_t *)f, dxpl_id, hdr, &descendants_clean) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify hdr descendants clean.") + HDassert(descendants_clean); +} +#endif /* NDEBUG */ - /* Write the heap header. */ - HDassert((size_t)(p - buf) == size); - if(H5F_block_write(f, H5FD_MEM_FHEAP_HDR, addr, size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFLUSH, FAIL, "unable to save fractal heap header to disk") + if(H5F_IS_TMP_ADDR(f, addr)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "addr in temporary space?!?."); - hdr->cache_info.is_dirty = FALSE; - } /* end if */ + if(len != hdr->heap_size) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "unexpected image len."); - if(destroy) - if(H5HF_cache_hdr_dest(f, hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap header") + *flags = 0; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") - FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_cache_hdr_flush() */ +} /* end H5HF__cache_hdr_pre_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_hdr_dest + * Function: H5HF__cache_hdr_serialize * - * Purpose: Destroys a fractal heap header in memory. + * Purpose: Construct the on disk image of the header, and place it in + * the buffer pointed to by image. Return SUCCEED on success, + * and FAIL on failure. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_hdr_dest(H5F_t *f, H5HF_hdr_t *hdr) +static herr_t +H5HF__cache_hdr_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) { + H5HF_hdr_t *hdr = (H5HF_hdr_t *)_thing; /* Fractal heap info */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint8_t heap_flags; /* Status flags for heap */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ + HDassert(f); + HDassert(image); HDassert(hdr); - HDassert(hdr->rc == 0); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + HDassert(len == hdr->heap_size); + + /* Set the shared heap header's file context for this operation */ + hdr->f = f; + + /* Magic number */ + HDmemcpy(image, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!hdr->cache_info.free_file_space_on_destroy || H5F_addr_defined(hdr->cache_info.addr)); + /* Version # */ + *image++ = H5HF_HDR_VERSION; - /* Check for freeing file space for heap header */ - if(hdr->cache_info.free_file_space_on_destroy) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_HDR, H5AC_dxpl_id, hdr->cache_info.addr, (hsize_t)hdr->heap_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap header") + /* General heap information */ + UINT16ENCODE(image, hdr->id_len); /* Heap ID length */ + UINT16ENCODE(image, hdr->filter_len); /* I/O filters' encoded length */ + + /* Heap status flags */ + /* (bit 0: "huge" object IDs have wrapped) */ + /* (bit 1: checksum direct blocks) */ + heap_flags = 0; + heap_flags = (uint8_t)(heap_flags | (hdr->huge_ids_wrapped ? H5HF_HDR_FLAGS_HUGE_ID_WRAPPED : 0)); + heap_flags = (uint8_t)(heap_flags | (hdr->checksum_dblocks ? H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS : 0)); + *image++ = heap_flags; + + /* "Huge" object information */ + UINT32ENCODE(image, hdr->max_man_size); /* Max. size of "managed" objects */ + H5F_ENCODE_LENGTH(f, image, hdr->huge_next_id); /* Next ID to use for "huge" object */ + H5F_addr_encode(f, &image, hdr->huge_bt2_addr); /* Address of "huge" object tracker B-tree */ + + /* "Managed" object free space information */ + H5F_ENCODE_LENGTH(f, image, hdr->total_man_free); /* Internal free space in managed direct blocks */ + H5F_addr_encode(f, &image, hdr->fs_addr); /* Address of free section header */ + + /* Heap statistics */ + H5F_ENCODE_LENGTH(f, image, hdr->man_size); + H5F_ENCODE_LENGTH(f, image, hdr->man_alloc_size); + H5F_ENCODE_LENGTH(f, image, hdr->man_iter_off); + H5F_ENCODE_LENGTH(f, image, hdr->man_nobjs); + H5F_ENCODE_LENGTH(f, image, hdr->huge_size); + H5F_ENCODE_LENGTH(f, image, hdr->huge_nobjs); + H5F_ENCODE_LENGTH(f, image, hdr->tiny_size); + H5F_ENCODE_LENGTH(f, image, hdr->tiny_nobjs); + + /* Managed objects' doubling-table info */ + if(H5HF__dtable_encode(hdr->f, &image, &(hdr->man_dtable)) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, FAIL, "unable to encode managed obj. doubling table info") + + /* Check for I/O filter information to encode */ + if(hdr->filter_len > 0) { + /* Encode the size of a filtered root direct block */ + H5F_ENCODE_LENGTH(f, image, hdr->pline_root_direct_size); + + /* Encode the filter mask for a filtered root direct block */ + UINT32ENCODE(image, hdr->pline_root_direct_filter_mask); + + /* Encode I/O filter information */ + if(H5O_msg_encode(hdr->f, H5O_PLINE_ID, FALSE, image, &(hdr->pline)) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, FAIL, "can't encode I/O pipeline fiters") + image += hdr->filter_len; } /* end if */ - /* Free the shared info itself */ - if(H5HF_hdr_free(hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "unable to release fractal heap header") + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); + + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + + /* sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) == len); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_hdr_dest() */ +} /* end H5HF__cache_hdr_serialize() */ + +/***************************************/ +/* no H5HF__cache_hdr_notify() function */ +/***************************************/ /*------------------------------------------------------------------------- - * Function: H5HF_cache_hdr_clear + * Function: H5HF__cache_hdr_free_icr * - * Purpose: Mark a fractal heap header in memory as non-dirty. + * Purpose: Free the in core representation of the fractal heap header. * - * Return: Non-negative on success/Negative on failure + * This routine frees just the header itself, not the + * associated version 2 B-Tree, the associated Free Space Manager, + * nor the indirect/direct block tree that is rooted in the header. * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * This routine also does not free the file space that may + * be allocated to the header. + * + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_hdr_clear(H5F_t *f, H5HF_hdr_t *hdr, hbool_t destroy) +static herr_t +H5HF__cache_hdr_free_icr(void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_hdr_t *hdr = (H5HF_hdr_t *)_thing; /* Fractal heap info */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + HDassert(hdr->rc == 0); - /* Reset the dirty flag. */ - hdr->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5HF_cache_hdr_dest(f, hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap header") + if(H5HF_hdr_free(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "unable to release fractal heap header") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_hdr_clear() */ +} /* end H5HF__cache_hdr_free_icr() */ + +/***********************************************************/ +/* metadata cache callback definitions for indirect blocks */ +/***********************************************************/ /*------------------------------------------------------------------------- - * Function: H5HF_cache_hdr_size + * Function: H5HF__cache_iblock_get_load_size() * - * Purpose: Compute the size in bytes of a fractal heap header - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Compute the size of the on disk image of the indirect + * block, and place this value in *image_len. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_hdr_size(const H5F_t H5_ATTR_UNUSED *f, const H5HF_hdr_t *hdr, size_t *size_ptr) +static herr_t +H5HF__cache_iblock_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5HF_iblock_cache_ud_t *udata = (H5HF_iblock_cache_ud_t *)_udata; /* User data for callback */ - /* Check arguments */ - HDassert(f); - HDassert(hdr); - HDassert(size_ptr); + FUNC_ENTER_STATIC_NOERR - /* Set size value */ - *size_ptr = hdr->heap_size; + /* Sanity checks */ + HDassert(udata); + HDassert(udata->par_info); + HDassert(udata->par_info->hdr); + HDassert(image_len); + + if(image == NULL) + *image_len = (size_t)H5HF_MAN_INDIRECT_SIZE(udata->par_info->hdr, *udata->nrows); + else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5HF_cache_hdr_size() */ +} /* end H5HF__cache_iblock_get_load_size() */ /***********************************************************/ /* metadata cache callback definitions for indirect blocks */ /***********************************************************/ + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_iblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF__cache_iblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_iblock_verify_chksum() */ + /*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_load + * Function: H5HF__cache_iblock_deserialize * - * Purpose: Loads a fractal heap indirect block from the disk. + * Purpose: Given a buffer containing the on disk image of the indirect + * block, allocate an instance of H5HF_indirect_t, load the data + * in the buffer into this new instance, and return a pointer to + * it. * - * Return: Success: Pointer to a new fractal heap indirect block + * As best I can tell, the size of the indirect block image is fully + * know before the image is loaded, so this function should succeed + * unless the image is corrupt or memory allocation fails. * + * Return: Success: Pointer to in core representation * Failure: NULL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 27 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static H5HF_indirect_t * -H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5HF__cache_iblock_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { H5HF_hdr_t *hdr; /* Shared fractal heap information */ - H5HF_iblock_cache_ud_t *udata = (H5HF_iblock_cache_ud_t *)_udata; /* user data for callback */ - H5HF_indirect_t *iblock = NULL; /* Indirect block info */ - H5WB_t *wb = NULL; /* Wrapped buffer for indirect block data */ - uint8_t iblock_buf[H5HF_IBLOCK_BUF_SIZE]; /* Buffer for indirect block */ - uint8_t *buf; /* Temporary buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5HF_iblock_cache_ud_t *udata = (H5HF_iblock_cache_ud_t *)_udata; /* User data for callback */ + H5HF_indirect_t *iblock = NULL; /* Indirect block info */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ haddr_t heap_addr; /* Address of heap header in the file */ + uint32_t stored_chksum; /* Stored metadata checksum value */ unsigned u; /* Local index variable */ - H5HF_indirect_t *ret_value; /* Return value */ + void * ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ + HDassert(image); HDassert(udata); - - /* Allocate space for the fractal heap indirect block */ - if(NULL == (iblock = H5FL_CALLOC(H5HF_indirect_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - /* Get the pointer to the shared heap header */ + HDassert(dirty); hdr = udata->par_info->hdr; + HDassert(hdr->f); /* Set the shared heap header's file context for this operation */ hdr->f = udata->f; + /* Allocate space for the fractal heap indirect block */ + if(NULL == (iblock = H5FL_CALLOC(H5HF_indirect_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + /* Share common heap information */ iblock->hdr = hdr; if(H5HF_hdr_incr(hdr) < 0) @@ -806,35 +1053,23 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) iblock->nrows = *udata->nrows; iblock->nchildren = 0; - /* Wrap the local buffer for serialized indirect block */ - if(NULL == (wb = H5WB_wrap(iblock_buf, sizeof(iblock_buf)))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't wrap buffer") - /* Compute size of indirect block */ iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock->nrows); - /* Get a pointer to a buffer that's large enough for serialized indirect block */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, iblock->size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "can't get actual buffer") - - /* Read and validate indirect block from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_FHEAP_IBLOCK, H5AC_FHEAP_IBLOCK_ID, addr, iblock->size, iblock->size, buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "incorrect metadata checksum for fractal heap indirect block") - - /* Get temporary pointer to serialized indirect block */ - p = buf; + /* sanity check */ + HDassert(iblock->size == len); /* Magic number */ - if(HDmemcmp(p, H5HF_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "wrong fractal heap indirect block signature") - p += H5_SIZEOF_MAGIC; + if(HDmemcmp(image, H5HF_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "wrong fractal heap indirect block signature") + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5HF_IBLOCK_VERSION) + if(*image++ != H5HF_IBLOCK_VERSION) HGOTO_ERROR(H5E_HEAP, H5E_VERSION, NULL, "wrong fractal heap direct block version") /* Address of heap that owns this block */ - H5F_addr_decode(udata->f, &p, &heap_addr); + H5F_addr_decode(udata->f, &image, &heap_addr); if(H5F_addr_ne(heap_addr, hdr->heap_addr)) HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "incorrect heap header address for direct block") @@ -859,7 +1094,7 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) } /* end else */ /* Offset of heap within the heap's address space */ - UINT64DECODE_VAR(p, iblock->block_off, hdr->heap_off_size); + UINT64DECODE_VAR(image, iblock->block_off, hdr->heap_off_size); /* Allocate & decode child block entry tables */ HDassert(iblock->nrows > 0); @@ -881,7 +1116,7 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) for(u = 0; u < (iblock->nrows * hdr->man_dtable.cparam.width); u++) { /* Decode child block address */ - H5F_addr_decode(udata->f, &p, &(iblock->ents[u].addr)); + H5F_addr_decode(udata->f, &image, &(iblock->ents[u].addr)); /* Check for heap with I/O filters */ if(hdr->filter_len > 0) { @@ -891,7 +1126,7 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) /* Decode extra information for direct blocks */ if(u < (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width)) { /* Size of filtered direct block */ - H5F_DECODE_LENGTH(udata->f, p, iblock->filt_ents[u].size); + H5F_DECODE_LENGTH(udata->f, image, iblock->filt_ents[u].size); /* Sanity check */ /* (either both the address & size are defined or both are @@ -901,7 +1136,7 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) || (!H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size == 0)); /* I/O filter mask for filtered direct block */ - UINT32DECODE(p, iblock->filt_ents[u].filter_mask); + UINT32DECODE(image, iblock->filt_ents[u].filter_mask); } /* end if */ } /* end if */ @@ -915,14 +1150,17 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) /* Sanity check */ HDassert(iblock->nchildren); /* indirect blocks w/no children should have been deleted */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done by verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - (const uint8_t *)buf) == (iblock->size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == iblock->size); /* Check if we have any indirect block children */ if(iblock->nrows > hdr->man_dtable.max_direct_rows) { - unsigned indir_rows; /* Number of indirect rows in this indirect block */ + unsigned indir_rows;/* Number of indirect rows in this indirect block */ /* Compute the number of indirect rows for this indirect block */ indir_rows = iblock->nrows - hdr->man_dtable.max_direct_rows; @@ -935,343 +1173,323 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) iblock->child_iblocks = NULL; /* Set return value */ - ret_value = iblock; + ret_value = (void *)iblock; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, NULL, "can't close wrapped buffer") if(!ret_value && iblock) if(H5HF_man_iblock_dest(iblock) < 0) HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy fractal heap indirect block") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_iblock_load() */ +} /* end H5HF__cache_iblock_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_flush + * Function: H5HF__cache_iblock_image_len * - * Purpose: Flushes a dirty fractal heap indirect block to disk. + * Purpose: Return the size of the on disk image of the iblock. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 6 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_indirect_t *iblock, unsigned H5_ATTR_UNUSED * flags_ptr) +static herr_t +H5HF__cache_iblock_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5WB_t *wb = NULL; /* Wrapped buffer for indirect block data */ - uint8_t iblock_buf[H5HF_IBLOCK_BUF_SIZE]; /* Buffer for indirect block */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5HF_indirect_t *iblock = (const H5HF_indirect_t *)_thing; /* Indirect block info */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ HDassert(iblock); + HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK); + HDassert(image_len); - if(iblock->cache_info.is_dirty) { - H5HF_hdr_t *hdr; /* Shared fractal heap information */ - uint8_t *buf; /* Temporary buffer */ - uint8_t *p; /* Pointer into raw data buffer */ -#ifndef NDEBUG - unsigned nchildren = 0; /* Track # of children */ - unsigned max_child = 0; /* Track max. child entry used */ -#endif /* NDEBUG */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - size_t u; /* Local index variable */ - -#ifndef NDEBUG -{ - /* Verify that flush dependencies are working correctly. Do this - * by verifying that all children of this iblock are clean. - */ - hbool_t descendants_clean = TRUE; - unsigned iblock_status; - - if(H5AC_get_entry_status(f, iblock->addr, &iblock_status) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get iblock status") - - /* since the current iblock is the guest of honor in a flush, we know - * that it is locked into the cache for the duration of the call. Hence - * there is no need to check to see if it is pinned or protected, or to - * protect it if it is not. - */ - if(H5HF__cache_verify_iblock_descendants_clean(f, dxpl_id, iblock, &iblock_status, &descendants_clean) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify descendants clean.") - - HDassert(descendants_clean); -} -#endif /* NDEBUG */ - - /* Get the pointer to the shared heap header */ - hdr = iblock->hdr; - - /* Set the shared heap header's file context for this operation */ - hdr->f = f; - - /* Wrap the local buffer for serialized indirect block */ - if(NULL == (wb = H5WB_wrap(iblock_buf, sizeof(iblock_buf)))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't wrap buffer") - - /* Get a pointer to a buffer that's large enough for serialized indirect block */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, iblock->size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "can't get actual buffer") - - /* Get temporary pointer to buffer for serialized indirect block */ - p = buf; - - /* Magic number */ - HDmemcpy(p, H5HF_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5HF_IBLOCK_VERSION; - - /* Address of heap header for heap which owns this block */ - H5F_addr_encode(f, &p, hdr->heap_addr); - - /* Offset of block in heap */ - UINT64ENCODE_VAR(p, iblock->block_off, hdr->heap_off_size); - - /* Encode indirect block-specific fields */ - for(u = 0; u < (iblock->nrows * hdr->man_dtable.cparam.width); u++) { - /* Encode child block address */ - H5F_addr_encode(f, &p, iblock->ents[u].addr); + *image_len = iblock->size; - /* Check for heap with I/O filters */ - if(hdr->filter_len > 0) { - /* Sanity check */ - HDassert(iblock->filt_ents); + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HF__cache_iblock_image_len() */ - /* Encode extra information for direct blocks */ - if(u < (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width)) { - /* Sanity check */ - /* (either both the address & size are defined or both are - * not defined) - */ - HDassert((H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size) - || (!H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size == 0)); + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_iblock_pre_serialize + * + * Purpose: The primary objective of this function is to determine if the + * indirect block is currently allocated in temporary file space, + * and if so, to move it to real file space before the entry is + * serialized. + * + * In debug compiles, this function also verifies that all children + * of this indirect block are either clean or are not in cache. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_iblock_pre_serialize(const H5F_t *f, hid_t dxpl_id, void *_thing, + haddr_t addr, size_t H5_ATTR_UNUSED len, size_t H5_ATTR_UNUSED compressed_len, + haddr_t *new_addr, size_t H5_ATTR_UNUSED *new_len, + size_t H5_ATTR_UNUSED *new_compressed_len, unsigned *flags) +{ + H5HF_hdr_t *hdr; /* Shared fractal heap information */ + H5HF_indirect_t *iblock = (H5HF_indirect_t *)_thing; /* Indirect block info */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Size of filtered direct block */ - H5F_ENCODE_LENGTH(f, p, iblock->filt_ents[u].size); + FUNC_ENTER_STATIC - /* I/O filter mask for filtered direct block */ - UINT32ENCODE(p, iblock->filt_ents[u].filter_mask); - } /* end if */ - } /* end if */ + /* Sanity checks */ + HDassert(f); + HDassert(iblock); + HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK); + HDassert(iblock->cache_info.size == iblock->size); + HDassert(H5F_addr_defined(addr)); + HDassert(H5F_addr_eq(iblock->addr, addr)); + HDassert(new_addr); + HDassert(new_len); + HDassert(flags); + hdr = iblock->hdr; + HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); #ifndef NDEBUG - /* Count child blocks */ - if(H5F_addr_defined(iblock->ents[u].addr)) { - nchildren++; - if(u > max_child) - max_child = u; - } /* end if */ -#endif /* NDEBUG */ - } /* end for */ - - /* Compute checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); +{ + hbool_t descendants_clean = TRUE; + unsigned iblock_status = 0; - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); + /* verify that flush dependencies are working correctly. Do this + * by verifying that all children of this iblock are clean. + */ + if(H5AC_get_entry_status(f, iblock->addr, &iblock_status) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get iblock status") - /* Sanity check */ - HDassert((size_t)(p - buf) == iblock->size); -#ifndef NDEBUG - HDassert(nchildren == iblock->nchildren); - HDassert(max_child == iblock->max_child); + /* since the current iblock is the guest of honor in a flush, we know + * that it is locked into the cache for the duration of the call. Hence + * there is no need to check to see if it is pinned or protected, or to + * protect it if it is not. + */ + if(H5HF__cache_verify_iblock_descendants_clean((H5F_t *)f, dxpl_id, iblock, &iblock_status, &descendants_clean) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify descendants clean.") + HDassert(descendants_clean); +} #endif /* NDEBUG */ - /* Check for needing to re-allocate indirect block from 'temp.' to 'normal' file space */ - if(H5F_IS_TMP_ADDR(f, addr)) { - /* Sanity check */ - HDassert(H5F_addr_eq(iblock->addr, addr)); + /* Check to see if we must re-allocate the iblock from temporary to + * normal (AKA real) file space. + */ + if(H5F_IS_TMP_ADDR(f, addr)) { + haddr_t iblock_addr; - /* Allocate 'normal' space for the new indirect block on disk */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, (hsize_t)iblock->size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block") + /* Allocate 'normal' space for the new indirect block on disk */ + if(HADDR_UNDEF == (iblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, (hsize_t)iblock->size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block") - /* Sanity check */ - HDassert(!H5F_addr_eq(iblock->addr, addr)); + /* Sanity check */ + HDassert(!H5F_addr_eq(iblock->addr, iblock_addr)); - /* Let the metadata cache know the block moved */ - if(H5AC_move_entry(f, H5AC_FHEAP_IBLOCK, iblock->addr, addr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move indirect block") + /* Let the metadata cache know the block moved */ + if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_IBLOCK, iblock->addr, iblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move indirect block") - /* Update the internal address for the block */ - iblock->addr = addr; + /* Update the internal address for the block */ + iblock->addr = iblock_addr; - /* Check for root indirect block */ - if(NULL == iblock->parent) { - /* Update information about indirect block's location */ - hdr->man_dtable.table_addr = addr; + /* Check for root indirect block */ + if(NULL == iblock->parent) { + /* Update information about indirect block's location */ + hdr->man_dtable.table_addr = iblock_addr; - /* Mark that heap header was modified */ - if(H5HF_hdr_dirty(hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end if */ - else { - H5HF_indirect_t *par_iblock; /* Parent indirect block */ - unsigned par_entry; /* Entry in parent indirect block */ + /* Mark that heap header was modified */ + if(H5HF_hdr_dirty(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") + } /* end if */ + else { + H5HF_indirect_t *par_iblock; /* Parent indirect block */ + unsigned par_entry; /* Entry in parent indirect block */ - /* Get parent information */ - par_iblock = iblock->parent; - par_entry = iblock->par_entry; + /* Get parent information */ + par_iblock = iblock->parent; + par_entry = iblock->par_entry; - /* Update information about indirect block's location */ - par_iblock->ents[par_entry].addr = addr; + /* Update information about indirect block's location */ + par_iblock->ents[par_entry].addr = iblock_addr; - /* Mark that parent was modified */ - if(H5HF_iblock_dirty(par_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end if */ + /* Mark that parent was modified */ + if(H5HF_iblock_dirty(par_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") } /* end if */ - /* Indirect block must be in 'normal' file space now */ - HDassert(!H5F_IS_TMP_ADDR(f, addr)); - - /* Write the indirect block */ - if(H5F_block_write(f, H5FD_MEM_FHEAP_IBLOCK, addr, iblock->size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFLUSH, FAIL, "unable to save fractal heap indirect block to disk") - - /* Reset dirty flags */ - iblock->cache_info.is_dirty = FALSE; + *new_addr = iblock_addr; + *flags = H5C__SERIALIZE_MOVED_FLAG; } /* end if */ - - if(destroy) - if(H5HF_cache_iblock_dest(f, iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block") + else + *flags = 0; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") - FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_cache_iblock_flush() */ +} /* end H5HF__cache_iblock_pre_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_dest + * Function: H5HF__cache_iblock_serialize * - * Purpose: Destroys a fractal heap indirect block in memory. + * Purpose: Given a pointer to an iblock, and a pointer to a buffer of + * the appropriate size, write the contents of the iblock to the + * buffer in format appropriate for writing to disk. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 6 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_iblock_dest(H5F_t *f, H5HF_indirect_t *iblock) +static herr_t +H5HF__cache_iblock_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_hdr_t *hdr; /* Shared fractal heap information */ + H5HF_indirect_t *iblock = (H5HF_indirect_t *)_thing; /* Indirect block info */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ +#ifndef NDEBUG + unsigned nchildren = 0; /* Track # of children */ + size_t max_child = 0; /* Track max. child entry used */ +#endif /* NDEBUG */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + size_t u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* - * Check arguments. - */ + /* Sanity checks */ + HDassert(f); + HDassert(image); HDassert(iblock); - HDassert(iblock->rc == 0); - HDassert(iblock->hdr); + HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK); + HDassert(iblock->cache_info.size == iblock->size); + HDassert(len == iblock->size); - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!iblock->cache_info.free_file_space_on_destroy || H5F_addr_defined(iblock->cache_info.addr)); - - /* Check for freeing file space for indirect block */ - if(iblock->cache_info.free_file_space_on_destroy) { - /* Check if the indirect block is NOT currently allocated in temp. file space */ - /* (temp. file space does not need to be freed) */ - if(!H5F_IS_TMP_ADDR(f, iblock->cache_info.addr)) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_IBLOCK, H5AC_dxpl_id, iblock->cache_info.addr, (hsize_t)iblock->size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block") - } /* end if */ - } /* end if */ + /* Indirect block must be in 'normal' file space */ + HDassert(!H5F_IS_TMP_ADDR(f, iblock->addr)); + HDassert(H5F_addr_eq(iblock->addr, iblock->cache_info.addr)); - /* Destroy fractal heap indirect block */ - if(H5HF_man_iblock_dest(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block") + /* Get the pointer to the shared heap header */ + hdr = iblock->hdr; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_iblock_dest() */ + /* Set the shared heap header's file context for this operation */ + hdr->f = f; - -/*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_clear - * - * Purpose: Mark a fractal heap indirect block in memory as non-dirty. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 6 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5HF_cache_iblock_clear(H5F_t *f, H5HF_indirect_t *iblock, hbool_t destroy) -{ - herr_t ret_value = SUCCEED; /* Return value */ + /* Magic number */ + HDmemcpy(image, H5HF_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - FUNC_ENTER_NOAPI_NOINIT + /* Version # */ + *image++ = H5HF_IBLOCK_VERSION; - /* - * Check arguments. - */ - HDassert(iblock); + /* Address of heap header for heap which owns this block */ + H5F_addr_encode(f, &image, hdr->heap_addr); - /* Reset the dirty flag. */ - iblock->cache_info.is_dirty = FALSE; + /* Offset of block in heap */ + UINT64ENCODE_VAR(image, iblock->block_off, hdr->heap_off_size); - if(destroy) - if(H5HF_cache_iblock_dest(f, iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block") + /* Encode indirect block-specific fields */ + for(u = 0; u < (iblock->nrows * hdr->man_dtable.cparam.width); u++) { + /* Encode child block address */ + H5F_addr_encode(f, &image, iblock->ents[u].addr); + + /* Check for heap with I/O filters */ + if(hdr->filter_len > 0) { + /* Sanity check */ + HDassert(iblock->filt_ents); + + /* Encode extra information for direct blocks */ + if(u < (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width)) { + /* Sanity check */ + /* (either both the address & size are defined or both are + * not defined) + */ + HDassert((H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size) + || (!H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size == 0)); + + /* Size of filtered direct block */ + H5F_ENCODE_LENGTH(f, image, iblock->filt_ents[u].size); + + /* I/O filter mask for filtered direct block */ + UINT32ENCODE(image, iblock->filt_ents[u].filter_mask); + } /* end if */ + } /* end if */ + +#ifndef NDEBUG + /* Count child blocks */ + if(H5F_addr_defined(iblock->ents[u].addr)) { + nchildren++; + if(u > max_child) + max_child = u; + } /* end if */ +#endif /* NDEBUG */ + } /* end for */ + + /* Compute checksum */ + metadata_chksum = H5_checksum_metadata((uint8_t *)_image, (size_t)(image - (uint8_t *)_image), 0); + + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + + /* Sanity checks */ + HDassert((size_t)(image - (uint8_t *)_image) == iblock->size); +#ifndef NDEBUG + HDassert(nchildren == iblock->nchildren); + HDassert(max_child == iblock->max_child); +#endif /* NDEBUG */ -done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_iblock_clear() */ +} /* end H5HF__cache_iblock_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_notify + * Function: H5HF__cache_iblock_notify * - * Purpose: Setup / takedown flush dependencies as indirect blocks + * Purpose: This function is used to create and destroy flush dependency + * relationships between iblocks and their parents as indirect blocks * are loaded / inserted and evicted from the metadata cache. * - * Return: Non-negative on success/Negative on failure + * In general, the parent will be another iblock, but it may be the + * header if the iblock in question is the root iblock. + * + * Return: Success: SUCCEED + * Failure: FAIL * * Programmer: John Mainzer - * 5/17/14 + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock) +static herr_t +H5HF__cache_iblock_notify(H5C_notify_action_t action, void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_indirect_t *iblock = (H5HF_indirect_t *)_thing; /* Indirect block info */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ HDassert(iblock); HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK); HDassert(iblock->hdr); if(action == H5AC_NOTIFY_ACTION_BEFORE_EVICT) @@ -1316,6 +1534,7 @@ H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock) switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: if(iblock->parent) { /* this is a child iblock */ /* create flush dependency with parent iblock */ if(H5AC_create_flush_dependency(iblock->parent, iblock) < 0) @@ -1328,6 +1547,10 @@ H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock) } /* end else */ break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: if(iblock->fd_parent) { /* this is a child iblock */ /* destroy flush dependency with parent iblock */ @@ -1348,95 +1571,324 @@ H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_iblock_notify() */ +} /* end H5HF__cache_iblock_notify() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_size + * Function: H5HF__cache_iblock_free_icr * - * Purpose: Compute the size in bytes of a fractal heap indirect block - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Unlink the supplied instance of H5HF_indirect_t from the + * fractal heap and free its memory. * - * Return: Non-negative on success/Negative on failure + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 6 2006 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_iblock_size(const H5F_t H5_ATTR_UNUSED *f, const H5HF_indirect_t *iblock, size_t *size_ptr) +static herr_t +H5HF__cache_iblock_free_icr(void *thing) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + H5HF_indirect_t *iblock = (H5HF_indirect_t *)thing; /* Fractal heap indirect block to free */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Check arguments */ + FUNC_ENTER_STATIC + + /* Sanity checks */ HDassert(iblock); - HDassert(size_ptr); + HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK); + HDassert(iblock->rc == 0); + HDassert(iblock->hdr); - /* Set size value */ - *size_ptr = iblock->size; + /* Destroy fractal heap indirect block */ + if(H5HF_man_iblock_dest(iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_iblock_free_icr() */ +/*********************************************************/ +/* metadata cache callback definitions for direct blocks */ +/*********************************************************/ + + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_dblock_get_load_size() + * + * Purpose: Determine the size of the direct block on disk image, and + * return it in *image_len. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_dblock_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + const H5HF_dblock_cache_ud_t *udata = (const H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */ + const H5HF_parent_t *par_info; /* Pointer to parent information */ + const H5HF_hdr_t *hdr; /* Shared fractal heap information */ + size_t compressed_size=0; + hbool_t compressed; + + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(udata); + HDassert(image_len); + par_info = (const H5HF_parent_t *)(&(udata->par_info)); + HDassert(par_info); + hdr = par_info->hdr; + HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + + if(hdr->filter_len > 0) { + + /* Check for root direct block */ + if(par_info->iblock == NULL) { + /* filtered direct block */ + compressed_size = hdr->pline_root_direct_size; + } /* end if */ + else { + /* filtered direct block */ + compressed_size = par_info->iblock->filt_ents[par_info->entry].size; + } /* end else */ + } + + if(image == NULL) { + + /* depend on I/O filters on this heap */ + *image_len = (hdr->filter_len > 0) ? compressed_size:udata->dblock_size; + + } else { + + HDassert(actual_len); + HDassert(*actual_len == *image_len); + HDassert(compressed_ptr); + HDassert(compressed_image_len_ptr); + + if(hdr->filter_len > 0) { + HDassert(*image_len == compressed_size); + compressed = TRUE; + } else { + HDassert(*image_len == udata->dblock_size); + compressed = FALSE; + compressed_size = 0; + } + + /* decompressed size */ + *actual_len = udata->dblock_size; + *compressed_ptr = compressed; + *compressed_image_len_ptr = compressed_size; + } + FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5HF_cache_iblock_size() */ +} /* end H5HF__cache_dblock_get_load_size() */ /*********************************************************/ /* metadata cache callback definitions for direct blocks */ /*********************************************************/ +/*------------------------------------------------------------------------- + * Function: H5HF__cache_dblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF__cache_dblock_verify_chksum(const void *_image, size_t len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5HF_dblock_cache_ud_t *udata = (H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */ + void *read_buf = NULL; /* Pointer to buffer to read in */ + size_t read_size; /* Size of filtered direct block to read */ + H5HF_hdr_t *hdr; /* Shared fractal heap information */ + H5HF_parent_t *par_info; /* Pointer to parent information */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t t_chksum; /* Computed metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + size_t chk_size; /* The size for validating checksum */ + uint8_t *chk_p; /* Pointer to the area for validating checksum */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(image); + HDassert(udata); + par_info = (H5HF_parent_t *)(&(udata->par_info)); + HDassert(par_info); + hdr = par_info->hdr; + HDassert(hdr); + + /* len is the decompressed size of the direct block */ + + udata->decompressed = FALSE; + udata->dblk = NULL; + + /* Get out if data block is not checksummed */ + if(!(hdr->checksum_dblocks)) + HGOTO_DONE(TRUE); + + /* Determine the size on disk */ + if(hdr->filter_len > 0) { + + /* Check for root direct block */ + if(par_info->iblock == NULL) { + /* Set up parameters to read filtered direct block */ + read_size = hdr->pline_root_direct_size; + } /* end if */ + else { + /* Set up parameters to read filtered direct block */ + read_size = par_info->iblock->filt_ents[par_info->entry].size; + } /* end else */ + } else + read_size = len; + + /* Allocate buffer to perform I/O filtering on and copy image into + * it. Must do this as H5Z_pipeline() may re-sized the buffer + * provided to it. + */ + if(NULL == (read_buf = H5MM_malloc(read_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer") + + if(hdr->filter_len > 0) { + size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */ + unsigned filter_mask; /* Excluded filters for direct block */ + H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ + + /* Push direct block data through I/O filter pipeline */ + nbytes = read_size; + filter_mask = udata->filter_mask; + HDmemcpy(read_buf, image, read_size); + + if(H5Z_pipeline(&(hdr->pline), H5Z_FLAG_REVERSE, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &read_size, &read_buf) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFILTER, FAIL, "output pipeline failed") + + /* Sanity check */ + HDassert(nbytes == len); + udata->decompressed = TRUE; + + } else + HDmemcpy(read_buf, image, read_size); + + /* Decode checksum */ + chk_size = (size_t)(H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr) - H5HF_SIZEOF_CHKSUM); + chk_p = (uint8_t *)read_buf + chk_size; + + /* Metadata checksum */ + UINT32DECODE(chk_p, stored_chksum); + + chk_p -= H5HF_SIZEOF_CHKSUM; + + /* Reset checksum field, for computing the checksum */ + /* (Casting away const OK - QAK) */ + HDmemset(chk_p, 0, (size_t)H5HF_SIZEOF_CHKSUM); + + /* Compute checksum on entire direct block */ + computed_chksum = H5_checksum_metadata(read_buf, len, 0); + + /* Restore the checksum */ + UINT32ENCODE(chk_p, stored_chksum) + + /* Verify checksum */ + if(stored_chksum != computed_chksum) + HGOTO_DONE(FALSE); + + /* Save the decompressed data to be used later in deserialize callback */ + if(hdr->filter_len > 0) { + + HDassert(udata->decompressed); + HDassert(len == udata->dblock_size); + /* Allocate block buffer */ + if(NULL == (udata->dblk = H5FL_BLK_MALLOC(direct_block, (size_t)len))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Copy un-filtered data into block's buffer */ + HDmemcpy(udata->dblk, read_buf, len); + } + +done: + /* Release the read buffer */ + if(read_buf) + H5MM_xfree(read_buf); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_dblock_verify_chksum() */ + /*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_load + * Function: H5HF__cache_dblock_deserialize * - * Purpose: Loads a fractal heap direct block from the disk. + * Purpose: Given a buffer containing the on disk image of a direct + * block, allocate an instance of H5HF_direct_t, load the data + * in the buffer into this new instance, and return a pointer to + * it. * - * Return: Success: Pointer to a new fractal heap direct block + * As best I can tell, the size of the direct block image is fully + * know before the image is loaded, so this function should succeed + * unless the image is corrupt or memory allocation fails. * + * Return: Success: Pointer to in core representation * Failure: NULL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 27 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static H5HF_direct_t * -H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5HF__cache_dblock_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { H5HF_hdr_t *hdr; /* Shared fractal heap information */ H5HF_dblock_cache_ud_t *udata = (H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */ H5HF_parent_t *par_info; /* Pointer to parent information */ - H5HF_direct_t *dblock = NULL; /* Direct block info */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5HF_direct_t *dblock = NULL; /* Direct block info */ + const uint8_t *image; /* Pointer into raw data buffer */ haddr_t heap_addr; /* Address of heap header in the file */ - uint32_t computed_chksum; /* Computed metadata checksum value */ - uint32_t stored_chksum; /* Metadata checksum value */ - unsigned tries, max_tries; /* The # of read attempts */ - unsigned retries; /* The # of retries */ - size_t chk_size; /* The size for validating checksum */ - uint8_t *chk_p; /* Pointer to the area for validating checksum */ - size_t read_size; /* Size of filtered direct block to read */ - H5HF_direct_t *ret_value; /* Return value */ + void * ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata != NULL); - HDassert(udata->f != NULL); - HDassert(udata->dblock_size > 0); + /* Sanity checks */ + HDassert(_image); + HDassert(udata); + par_info = (H5HF_parent_t *)(&(udata->par_info)); + HDassert(par_info); + hdr = par_info->hdr; + HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + HDassert(dirty); /* Allocate space for the fractal heap direct block */ if(NULL == (dblock = H5FL_MALLOC(H5HF_direct_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") HDmemset(&dblock->cache_info, 0, sizeof(H5AC_info_t)); - /* Get the pointer to the shared heap header */ - par_info = (H5HF_parent_t *)(&(udata->par_info)); - hdr = par_info->hdr; - /* Set the shared heap header's file context for this operation */ hdr->f = udata->f; @@ -1449,46 +1901,54 @@ H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) dblock->size = udata->dblock_size; dblock->file_size = 0; - /* Allocate block buffer */ -/* XXX: Change to using free-list factories */ - if(NULL == (dblock->blk = H5FL_BLK_MALLOC(direct_block, (size_t)dblock->size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - /* Determine read_size for filter buffer */ + /* initialize fields used in serialization */ + dblock->write_buf = NULL; + dblock->write_size = 0; + + if(udata->dblk && udata->decompressed) { + /* direct block is already decompressed in verify_chksum callback */ + HDassert(hdr->filter_len > 0); + HDassert(len == dblock->size); + dblock->blk = udata->dblk; + } else { + HDassert(udata->dblk == NULL); + HDassert(!udata->decompressed); + + /* Allocate block buffer */ + /* XXX: Change to using free-list factories */ + if(NULL == (dblock->blk = H5FL_BLK_MALLOC(direct_block, (size_t)dblock->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + } + + /* Check for I/O filters on this heap */ if(hdr->filter_len > 0) { - /* Check for root direct block */ - if(par_info->iblock == NULL) { - /* Sanity check */ - HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr)); - - /* Set up parameters to read filtered direct block */ - read_size = hdr->pline_root_direct_size; - } /* end if */ - else { - /* Sanity check */ - HDassert(H5F_addr_eq(par_info->iblock->ents[par_info->entry].addr, addr)); - - /* Set up parameters to read filtered direct block */ - read_size = par_info->iblock->filt_ents[par_info->entry].size; - } /* end else */ - } /* end if */ - - tries = max_tries = H5F_GET_READ_ATTEMPTS(f); - do { - /* Check for I/O filters on this heap */ - if(hdr->filter_len > 0) { - H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ - size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */ - void *read_buf; /* Pointer to buffer to read in */ - unsigned filter_mask; /* Excluded filters for direct block */ + H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ + size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */ + void *read_buf; /* Pointer to buffer to read in */ + size_t read_size; /* Size of filtered direct block to read */ + unsigned filter_mask; /* Excluded filters for direct block */ + + if(!udata->decompressed) { + HDassert(udata->dblk == NULL); + + /* Check for root direct block */ + if(par_info->iblock == NULL) { + /* Set up parameters to read filtered direct block */ + read_size = hdr->pline_root_direct_size; + } /* end if */ + else { + /* Set up parameters to read filtered direct block */ + read_size = par_info->iblock->filt_ents[par_info->entry].size; + } /* end else */ + HDassert(len == read_size); - /* Allocate buffer to perform I/O filtering on */ + /* Allocate buffer to perform I/O filtering on and copy image into + * it. Must do this as H5Z_pipeline() may re-sized the buffer + * provided to it. + */ if(NULL == (read_buf = H5MM_malloc(read_size))) HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "memory allocation failed for pipeline buffer") - - /* Read filtered direct block from disk */ - if(H5F_block_read(f, H5FD_MEM_FHEAP_DBLOCK, addr, read_size, dxpl_id, read_buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "can't read fractal heap direct block") + HDmemcpy(read_buf, _image, len); /* Push direct block data through I/O filter pipeline */ nbytes = read_size; @@ -1504,62 +1964,28 @@ H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) /* Release the read buffer */ H5MM_xfree(read_buf); - } /* end if */ - else { - /* Read direct block from disk */ - if(H5F_block_read(f, H5FD_MEM_FHEAP_DBLOCK, addr, dblock->size, dxpl_id, dblock->blk) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "can't read fractal heap direct block") - } /* end else */ - - /* Get out if data block is not checksummed */ - if(!(hdr->checksum_dblocks)) - break; - - /* Decode checksum on direct block, if requested */ - chk_size = (size_t)(H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr) - H5HF_SIZEOF_CHKSUM); - chk_p = dblock->blk + chk_size; - - /* Metadata checksum */ - UINT32DECODE(chk_p, stored_chksum); - - chk_p -= H5HF_SIZEOF_CHKSUM; - - /* Reset checksum field, for computing the checksum */ - /* (Casting away const OK - QAK) */ - HDmemset(chk_p, 0, (size_t)H5HF_SIZEOF_CHKSUM); - - /* Compute checksum on entire direct block */ - computed_chksum = H5_checksum_metadata(dblock->blk, dblock->size, 0); - - /* Verify checksum */ - if(stored_chksum == computed_chksum) - break; - - } while (--tries); - - if(tries == 0) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "incorrect metadata checksum after all tries (%u) for fractal heap direct block", max_tries) - - /* Calculate and track the # of retries */ - retries = max_tries - tries; - if(retries) /* Does not track 0 retry */ - if(H5F_track_metadata_read_retries(f, H5AC_FHEAP_DBLOCK_ID, retries) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "cannot track read retries = %u ", retries) + } + } /* end if */ + else { + /* copy image to dblock->blk */ + HDassert(dblock->size == len); + HDmemcpy(dblock->blk, _image, dblock->size); + } /* end else */ /* Start decoding direct block */ - p = dblock->blk; + image = dblock->blk; /* Magic number */ - if(HDmemcmp(p, H5HF_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "wrong fractal heap direct block signature") - p += H5_SIZEOF_MAGIC; + if(HDmemcmp(image, H5HF_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "wrong fractal heap direct block signature") + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5HF_DBLOCK_VERSION) + if(*image++ != H5HF_DBLOCK_VERSION) HGOTO_ERROR(H5E_HEAP, H5E_VERSION, NULL, "wrong fractal heap direct block version") /* Address of heap that owns this block (just for file integrity checks) */ - H5F_addr_decode(udata->f, &p, &heap_addr); + H5F_addr_decode(udata->f, &image, &heap_addr); if(H5F_addr_ne(heap_addr, hdr->heap_addr)) HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "incorrect heap header address for direct block") @@ -1574,17 +2000,24 @@ H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) } /* end if */ /* Offset of heap within the heap's address space */ - UINT64DECODE_VAR(p, dblock->block_off, hdr->heap_off_size); + UINT64DECODE_VAR(image, dblock->block_off, hdr->heap_off_size); + + /* Decode checksum on direct block, if requested */ + if(hdr->checksum_dblocks) { + uint32_t stored_chksum; /* Metadata checksum value */ - /* Advance past optional checksum on direct block, it was verified earlier */ - if(hdr->checksum_dblocks) - p += H5HF_SIZEOF_CHKSUM; + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); + + } /* end if */ /* Sanity check */ - HDassert((size_t)(p - dblock->blk) == (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)); + HDassert((size_t)(image - dblock->blk) == (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)); /* Set return value */ - ret_value = dblock; + ret_value = (void *)dblock; done: if(!ret_value && dblock) @@ -1592,402 +2025,646 @@ done: HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy fractal heap direct block") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_dblock_load() */ +} /* end H5HF__cache_dblock_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_flush + * Function: H5HF__cache_dblock_image_len * - * Purpose: Flushes a dirty fractal heap direct block to disk. + * Purpose: Report the actual size of the direct block image on disk. + * Note that this value will probably be incorrect if compression + * is enabled and the entry is dirty. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 27 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_direct_t *dblock, unsigned H5_ATTR_UNUSED * flags_ptr) +static herr_t +H5HF__cache_dblock_image_len(const void *_thing, size_t *image_len, hbool_t *compressed_ptr, size_t *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const H5HF_direct_t *dblock = (const H5HF_direct_t *)_thing; /* Direct block info */ + const H5HF_indirect_t *par_iblock; /* Parent iblock */ + const H5HF_hdr_t *hdr; /* Shared fractal heap information */ + hbool_t compressed; + size_t size; + size_t compressed_size; - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ HDassert(dblock); + HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK); + HDassert(image_len); + HDassert(compressed_ptr); + HDassert(compressed_image_len_ptr); - if(dblock->cache_info.is_dirty) { - H5HF_hdr_t *hdr; /* Shared fractal heap information */ - hbool_t at_tmp_addr = H5F_IS_TMP_ADDR(f, addr); /* Flag to indicate direct block is at temporary address */ - void *write_buf; /* Pointer to buffer to write out */ - size_t write_size; /* Size of buffer to write out */ - uint8_t *p; /* Pointer into raw data buffer */ + /* Set up convenience variables */ + hdr = dblock->hdr; + par_iblock = dblock->parent; - /* Get the pointer to the shared heap header */ - hdr = dblock->hdr; + /* Check for I/O filters on this heap */ + if(hdr->filter_len > 0) { - /* Set the shared heap header's file context for this operation */ - hdr->f = f; + /* Filters are enabled, so set compressed to TRUE, and set + * size equal to the uncompressed size of the direct block. + * If the data is available, set compressed_size to the compressed + * size of the direct block -- otherwise set it equal to the + * uncompressed size. + * + * We have three possible scenarios here. + * + * First, the block may never have been flushed. In this + * case, both dblock->file_size and the size stored in the + * parent (either the header or the parent iblock) will all + * be zero. In this case, return the uncompressed size + * stored in dblock->size as the compressed size. + * + * Second, the block may have just been serialized, in which + * case, dblock->file_size should be zero, and the correct + * on disk size should be stored in the parent (again, either + * the header or the parent iblock as case may be). + * + * Third, we may be in the process of discarding this + * dblock without writing it. In this case, dblock->file_size + * should be non-zero and have the correct size. Note that + * in this case, the direct block will have been detached, + * and thus looking up the parent will likely return incorrect + * data. + */ + size = dblock->size; + compressed = TRUE; + compressed_size = dblock->size; /* will overwrite if compressed + * size is available. + */ + + if(dblock->file_size != 0) + compressed_size = dblock->file_size; + else { + if(par_iblock) { + unsigned par_entry; /* Entry in parent indirect block */ - HDassert(dblock->blk); - p = dblock->blk; + par_entry = dblock->par_entry; + compressed_size = par_iblock->filt_ents[par_entry].size; - /* Magic number */ - HDmemcpy(p, H5HF_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; + } /* end if */ + else { + compressed_size = hdr->pline_root_direct_size; + } - /* Version # */ - *p++ = H5HF_DBLOCK_VERSION; + if(compressed_size == 0) + compressed_size = dblock->size; - /* Address of heap header for heap which owns this block */ - H5F_addr_encode(f, &p, hdr->heap_addr); + } /* end else */ + } /* end if */ + else { + size = dblock->size; + compressed = FALSE; + compressed_size = 0; /* a convenient, invalid value */ + } - /* Offset of block in heap */ - UINT64ENCODE_VAR(p, dblock->block_off, hdr->heap_off_size); + HDassert(size > 0); - /* Metadata checksum */ - if(hdr->checksum_dblocks) { - uint32_t metadata_chksum; /* Computed metadata checksum value */ + *image_len = size; + *compressed_ptr = compressed; + *compressed_image_len_ptr = compressed_size; - /* Clear the checksum field, to compute the checksum */ - HDmemset(p, 0, (size_t)H5HF_SIZEOF_CHKSUM); + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HF__cache_dblock_image_len() */ - /* Compute checksum on entire direct block */ - metadata_chksum = H5_checksum_metadata(dblock->blk, dblock->size, 0); + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_dblock_pre_serialize + * + * Purpose: In principle, the purpose of this function is to determine + * the size and location of the disk image of the target direct + * block. In this case, the uncompressed size of the block is + * fixed, but sined the H5C__CLASS_COMPRESSED_FLAG is set, + * we may need to compute and report the compressed size. + * + * This is a bit sticky in the case of a direct block when I/O + * filters are enabled, as the size of the compressed version + * of the on disk image is not known until the direct block has + * been run through the filters. Further, the location of the + * on disk image may change if the compressed size of the image + * changes as well. + * + * To complicate matters further, the direct block may have been + * initially allocated in temporary (AKA imaginary) file space. + * In this case, we must relocate the direct block's on disk + * image to real file space regardless of whether it has changed + * size. + * + * One simplifying factor is the direct block's "blk" field, + * which contains a pointer to a buffer which (with the exception + * of a small header) contains the on disk image in uncompressed + * form. + * + * To square this particular circle, this function does + * everything the serialize function usually does, with the + * exception of copying the image into the image buffer provided + * to the serialize function by the metadata cache. The data to + * copy is provided to the serialize function in a buffer pointed + * to by the write_buf field. + * + * If I/O filters are enabled, on exit, + * H5HF__cache_dblock_pre_serialize() sets the write_buf field to + * point to a buffer containing the filtered image of the direct + * block. The serialize function should free this block, and set + * the write_buf field to NULL after copying it into the image + * buffer provided by the metadata cache. + * + * If I/O filters are not enabled, this function prepares + * the buffer pointed to by the blk field for copying to the + * image buffer provided by the metadata cache, and sets the + * write_buf field equal to the blk field. In this case, the + * serialize function should simply set the write_buf field to + * NULL after copying the direct block image into the image + * buffer. + * + * In both of the above cases, the length of the buffer pointed + * to by write_buf is provided in the write_len field. This + * field must contain 0 on entry to this function, and should + * be set back to 0 at the end of the serialize function. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_dblock_pre_serialize(const H5F_t *f, hid_t dxpl_id, void *_thing, + haddr_t addr, size_t len, size_t compressed_len, haddr_t *new_addr, + size_t H5_ATTR_UNUSED *new_len, size_t *new_compressed_len, unsigned *flags) +{ + hbool_t at_tmp_addr; /* Flag to indicate direct block is */ + /* at temporary address */ + haddr_t dblock_addr; + H5HF_hdr_t *hdr; /* Shared fractal heap information */ + H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Direct block info */ + H5HF_indirect_t *par_iblock; /* Parent indirect block */ + unsigned par_entry; /* Entry in parent indirect block */ + void *write_buf; /* Pointer to buffer to write out */ + size_t write_size; /* Size of buffer to write out */ + uint8_t *image; /* Pointer into raw data buffer */ + unsigned dblock_flags = 0; + herr_t ret_value = SUCCEED; /* Return value */ - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); - } /* end if */ + FUNC_ENTER_STATIC - /* Sanity check */ - HDassert((size_t)(p - dblock->blk) == (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)); + /* Sanity checks */ + HDassert(f); + HDassert(dblock); + HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK); + HDassert(dblock->write_buf == NULL); + HDassert(dblock->write_size == 0); + HDassert(dblock->cache_info.size == len); + HDassert(H5F_addr_defined(addr)); + HDassert(len == dblock->size); + HDassert(new_addr); + HDassert(new_compressed_len); + HDassert(flags); - /* Check for I/O filters on this heap */ - if(hdr->filter_len > 0) { - H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ - size_t nbytes; /* Number of bytes used */ - unsigned filter_mask = 0; /* Filter mask for block */ + /* Set up local variables */ + hdr = dblock->hdr; + dblock_addr = addr; /* will update dblock_addr if we move the block */ - /* Allocate buffer to perform I/O filtering on */ - write_size = dblock->size; - if(NULL == (write_buf = H5MM_malloc(write_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer") - HDmemcpy(write_buf, dblock->blk, write_size); + /* dblock->size must match dblock->cache_info.size */ + HDassert(dblock->cache_info.size == dblock->size); - /* Push direct block data through I/O filter pipeline */ - nbytes = write_size; - if(H5Z_pipeline(&(hdr->pline), 0, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &write_size, &write_buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "output pipeline failed") + /* Set the shared heap header's file context for this operation */ + hdr->f = (H5F_t *)f; - /* Use the compressed number of bytes as the size to write */ - write_size = nbytes; + HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); - /* Check for root direct block */ - if(dblock->parent == NULL) { - hbool_t hdr_changed = FALSE; /* Whether the header information changed */ + if(dblock->parent) { + /* this is the common case, in which the direct block is the child + * of an indirect block. Set up the convenience variables we will + * need if the address and/or compressed size of the on disk image + * of the direct block changes, and do some sanity checking in + * passing. + */ + par_iblock = dblock->parent; + par_entry = dblock->par_entry; - /* Sanity check */ - HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr)); - HDassert(hdr->pline_root_direct_size > 0); + HDassert(par_iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(par_iblock->cache_info.type == H5AC_FHEAP_IBLOCK); + HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)); + } /* end if */ + else { + /* the direct block is a root direct block -- just set par_iblock + * to NULL, as the field will not be used. + */ + par_iblock = NULL; + } /* end else */ - /* Check if the filter mask changed */ - if(hdr->pline_root_direct_filter_mask != filter_mask) { - hdr->pline_root_direct_filter_mask = filter_mask; - hdr_changed = TRUE; - } /* end if */ + at_tmp_addr = H5F_IS_TMP_ADDR(f, addr); - /* Check if we need to re-size the block on disk */ - if(hdr->pline_root_direct_size != write_size || at_tmp_addr) { - /* Check if the direct block is NOT currently allocated in temp. file space */ - /* (temp. file space does not need to be freed) */ - if(!at_tmp_addr) { - /* Release direct block's current disk space */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, addr, (hsize_t)hdr->pline_root_direct_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") - } /* end if */ + /* Begin by preping the direct block to be written to disk. Do + * this by writing the correct magic number, the dblock version, + * the address of the header, the offset of the block in the heap, + * and the checksum at the beginning of the block. + */ - /* Allocate space for the compressed direct block */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") + HDassert(dblock->blk); + image = dblock->blk; - /* Let the metadata cache know, if the block moved */ - if(!H5F_addr_eq(hdr->man_dtable.table_addr, addr)) - if(H5AC_move_entry(f, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, addr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") + /* Magic number */ + HDmemcpy(image, H5HF_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Update information about compressed direct block's location & size */ - hdr->man_dtable.table_addr = addr; - hdr->pline_root_direct_size = write_size; + /* Version # */ + *image++ = H5HF_DBLOCK_VERSION; - /* Note that heap header was modified */ - hdr_changed = TRUE; - } /* end if */ + /* Address of heap header for heap which owns this block */ + H5F_addr_encode(f, &image, hdr->heap_addr); - /* Check if heap header was modified */ - if(hdr_changed) - if(H5HF_hdr_dirty(hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end if */ - else { - hbool_t par_changed = FALSE; /* Whether the parent's information changed */ - H5HF_indirect_t *par_iblock; /* Parent indirect block */ - unsigned par_entry; /* Entry in parent indirect block */ + /* Offset of block in heap */ + UINT64ENCODE_VAR(image, dblock->block_off, hdr->heap_off_size); - /* Get parent information */ - par_iblock = dblock->parent; - par_entry = dblock->par_entry; + /* Metadata checksum */ + if(hdr->checksum_dblocks) { + uint32_t metadata_chksum; /* Computed metadata checksum value */ - /* Sanity check */ - HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)); - HDassert(par_iblock->filt_ents[par_entry].size > 0); + /* Clear the checksum field, to compute the checksum */ + HDmemset(image, 0, (size_t)H5HF_SIZEOF_CHKSUM); - /* Check if the filter mask changed */ - if(par_iblock->filt_ents[par_entry].filter_mask != filter_mask) { - par_iblock->filt_ents[par_entry].filter_mask = filter_mask; - par_changed = TRUE; - } /* end if */ + /* Compute checksum on entire direct block */ + metadata_chksum = H5_checksum_metadata(dblock->blk, dblock->size, 0); - /* Check if we need to re-size the block on disk */ - if(par_iblock->filt_ents[par_entry].size != write_size || at_tmp_addr) { - /* Check if the direct block is NOT currently allocated in temp. file space */ - /* (temp. file space does not need to be freed) */ - if(!at_tmp_addr) { - /* Release direct block's current disk space */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, addr, (hsize_t)par_iblock->filt_ents[par_entry].size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") - } /* end if */ + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + } /* end if */ - /* Allocate space for the compressed direct block */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") + /* at this point, dblock->blk should point to an uncompressed image of + * the direct block. If I/O filters are not enabled, this image should + * be ready to hand off to the metadata cache. + */ - /* Let the metadata cache know, if the block moved */ - if(!H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)) - if(H5AC_move_entry(f, H5AC_FHEAP_DBLOCK, par_iblock->ents[par_entry].addr, addr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") + /* Sanity check */ + HDassert((size_t)(image - dblock->blk) == (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)); - /* Update information about compressed direct block's location & size */ - par_iblock->ents[par_entry].addr = addr; - par_iblock->filt_ents[par_entry].size = write_size; + /* If I/O filters are enabled on this heap, we must run the direct block + * image through the filters to obtain the image that we will hand off + * to the metadata cache. + */ - /* Note that parent was modified */ - par_changed = TRUE; - } /* end if */ + /* Check for I/O filters on this heap */ + if(hdr->filter_len > 0) { + H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ + size_t nbytes; /* Number of bytes used */ + unsigned filter_mask = 0; /* Filter mask for block */ + + /* Allocate buffer to perform I/O filtering on */ + write_size = dblock->size; + + if(NULL == (write_buf = H5MM_malloc(write_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer") + HDmemcpy(write_buf, dblock->blk, write_size); + + /* Push direct block data through I/O filter pipeline */ + nbytes = write_size; + if(H5Z_pipeline(&(hdr->pline), 0, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &write_size, &write_buf) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "output pipeline failed") + + /* Use the compressed number of bytes as the size to write */ + write_size = nbytes; + + /* If the size and/or location of the on disk image of the + * direct block changes, we must touch up its parent to reflect + * these changes. Do this differently depending on whether the + * direct block's parent is an indirect block or (rarely) the + * fractal heap header. In this case, the direct block is known + * as a root direct block. + */ - /* Check if parent was modified */ - if(par_changed) - if(H5HF_iblock_dirty(par_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end else */ - } /* end if */ - else { - write_buf = dblock->blk; - write_size = dblock->size; + /* Check for root direct block */ + if(dblock->parent == NULL) { + hbool_t hdr_changed = FALSE; /* Whether the header info changed */ - /* Check for needing to re-allocate direct block from 'temp.' to 'normal' file space */ - if(at_tmp_addr) { - /* Check for root direct block */ - if(NULL == dblock->parent) { - /* Sanity check */ - HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr)); + /* Sanity check */ + HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr)); + HDassert(hdr->pline_root_direct_size > 0); - /* Allocate 'normal' space for the direct block */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") + /* Check if the filter mask changed */ + if(hdr->pline_root_direct_filter_mask != filter_mask) { + hdr->pline_root_direct_filter_mask = filter_mask; + hdr_changed = TRUE; + } /* end if */ + + /* verify that the cache's last record of the compressed + * size matches the heap's last record. This value will + * likely change shortly. + */ + HDassert(compressed_len == hdr->pline_root_direct_size); + + /* Check if we need to re-size the block on disk */ + if(hdr->pline_root_direct_size != write_size || at_tmp_addr) { + /* Check if the direct block is NOT currently allocated + * in temp. file space + * + * (temp. file space does not need to be freed) + */ + if(!at_tmp_addr) { + /* Release direct block's current disk space */ + if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, addr, (hsize_t)hdr->pline_root_direct_size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") + } /* end if */ - /* Sanity check */ - HDassert(!H5F_addr_eq(hdr->man_dtable.table_addr, addr)); + /* Allocate space for the compressed direct block */ + if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") - /* Let the metadata cache know the block moved */ - if(H5AC_move_entry(f, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, addr) < 0) + /* Let the metadata cache know, if the block moved */ + if(!H5F_addr_eq(hdr->man_dtable.table_addr, dblock_addr)) + if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, dblock_addr) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") - /* Update information about direct block's location */ - hdr->man_dtable.table_addr = addr; + /* Update information about compressed direct block's + * location & size + */ + HDassert(hdr->man_dtable.table_addr == addr); + HDassert(hdr->pline_root_direct_size == compressed_len); + hdr->man_dtable.table_addr = dblock_addr; + hdr->pline_root_direct_size = write_size; - /* Mark that heap header was modified */ - if(H5HF_hdr_dirty(hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end if */ - else { - H5HF_indirect_t *par_iblock; /* Parent indirect block */ - unsigned par_entry; /* Entry in parent indirect block */ + /* Note that heap header was modified */ + hdr_changed = TRUE; + } /* end if */ + + /* Check if heap header was modified */ + if(hdr_changed) + if(H5HF_hdr_dirty(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") + } /* end if */ + else { /* the direct block's parent is an indirect block */ + hbool_t par_changed = FALSE; /* Whether the parent's infochanged */ + + /* Sanity check */ + HDassert(par_iblock); + HDassert(par_iblock->filt_ents[par_entry].size > 0); - /* Get parent information */ - par_iblock = dblock->parent; - par_entry = dblock->par_entry; + /* Check if the filter mask changed */ + if(par_iblock->filt_ents[par_entry].filter_mask != filter_mask) { + par_iblock->filt_ents[par_entry].filter_mask = filter_mask; + par_changed = TRUE; + } /* end if */ - /* Sanity check */ - HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)); + /* verify that the cache's last record of the compressed + * size matches the heap's last record. This value will + * likely change shortly. + */ + HDassert(compressed_len == par_iblock->filt_ents[par_entry].size); - /* Allocate 'normal' space for the direct block */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") + /* Check if we need to re-size the block on disk */ + if(par_iblock->filt_ents[par_entry].size != write_size || at_tmp_addr) { + /* Check if the direct block is NOT currently allocated + * in temp. file space + * + * (temp. file space does not need to be freed) + */ + if(!at_tmp_addr) { + /* Release direct block's current disk space */ + if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, addr, (hsize_t)par_iblock->filt_ents[par_entry].size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") + } /* end if */ - /* Sanity check */ - HDassert(!H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)); + /* Allocate space for the compressed direct block */ + if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") - /* Let the metadata cache know the block moved */ - if(H5AC_move_entry(f, H5AC_FHEAP_DBLOCK, par_iblock->ents[par_entry].addr, addr) < 0) + /* Let the metadata cache know, if the block moved */ + if(!H5F_addr_eq(par_iblock->ents[par_entry].addr, dblock_addr)) + if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_DBLOCK, par_iblock->ents[par_entry].addr, dblock_addr) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") - /* Update information about direct block's location */ - par_iblock->ents[par_entry].addr = addr; + /* Update information about compressed direct block's + * location & size + */ + HDassert(par_iblock->ents[par_entry].addr == addr); + HDassert(par_iblock->filt_ents[par_entry].size == compressed_len); + par_iblock->ents[par_entry].addr = dblock_addr; + par_iblock->filt_ents[par_entry].size = write_size; - /* Mark that parent was modified */ - if(H5HF_iblock_dirty(par_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end else */ + /* Note that parent was modified */ + par_changed = TRUE; } /* end if */ + + /* Check if parent was modified */ + if(par_changed) + if(H5HF_iblock_dirty(par_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") } /* end else */ + } /* end if */ + else { + /* I/O filters are not enabled -- thus all we need to do is check to + * see if the direct block is in temporary (AKA imaginary) file + * space, and move it to real file space if it is. + * + * As in the I/O filters case above, we will have to touch up the + * direct blocks parent if the direct block is relocated. + * + * Recall that temporary file space need not be freed, which + * simplifies matters slightly. + */ + write_buf = dblock->blk; + write_size = dblock->size; - /* Direct block must be in 'normal' file space now */ - HDassert(!H5F_IS_TMP_ADDR(f, addr)); + /* Check to see if we must re-allocate direct block from 'temp.' + * to 'normal' file space + */ + if(at_tmp_addr) { + /* Check for root direct block */ + if(NULL == dblock->parent) { + /* Sanity check */ + HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr)); - /* Write the direct block */ - if(H5F_block_write(f, H5FD_MEM_FHEAP_DBLOCK, addr, write_size, dxpl_id, write_buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFLUSH, FAIL, "unable to save fractal heap direct block to disk") + /* Allocate 'normal' space for the direct block */ + if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") - /* Release the write buffer, if it was allocated */ - if(write_buf != dblock->blk) - H5MM_xfree(write_buf); + /* Sanity check */ + HDassert(!H5F_addr_eq(hdr->man_dtable.table_addr, dblock_addr)); - dblock->cache_info.is_dirty = FALSE; - } /* end if */ + /* Let the metadata cache know the block moved */ + if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, dblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") - if(destroy) - if(H5HF_cache_dblock_dest(f, dblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block") + /* Update information about direct block's location */ + hdr->man_dtable.table_addr = dblock_addr; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_cache_dblock_flush() */ + /* Mark that heap header was modified */ + if(H5HF_hdr_dirty(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") + } /* end if */ + else { /* the direct block's parent is an indirect block */ + /* Sanity check */ + HDassert(par_iblock); + HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)); - -/*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_dest - * - * Purpose: Destroys a fractal heap direct block in memory. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 27 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5HF_cache_dblock_dest(H5F_t *f, H5HF_direct_t *dblock) -{ - herr_t ret_value = SUCCEED; /* Return value */ + /* Allocate 'normal' space for the direct block */ + if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") - FUNC_ENTER_NOAPI_NOINIT + /* Sanity check */ + HDassert(!H5F_addr_eq(par_iblock->ents[par_entry].addr, dblock_addr)); - /* - * Check arguments. - */ - HDassert(dblock); + /* Let the metadata cache know the block moved */ + if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_DBLOCK, par_iblock->ents[par_entry].addr, dblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!dblock->cache_info.free_file_space_on_destroy || H5F_addr_defined(dblock->cache_info.addr)); + /* Update information about direct block's location */ + par_iblock->ents[par_entry].addr = dblock_addr; - /* Check for freeing file space for direct block */ - if(dblock->cache_info.free_file_space_on_destroy) { - /* Sanity check */ - HDassert(dblock->file_size > 0); - - /* Check if the direct block is NOT currently allocated in temp. file space */ - /* (temp. file space does not need to be freed) */ - if(!H5F_IS_TMP_ADDR(f, dblock->cache_info.addr)) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, H5AC_dxpl_id, dblock->cache_info.addr, dblock->file_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") + /* Mark that parent was modified */ + if(H5HF_iblock_dirty(par_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") + } /* end else */ } /* end if */ + } /* end else */ + + /* At this point, write_buf points to a buffer containing the image + * of the direct block that is ready to copy into the image buffer, + * and write_size contains the length of this buffer. + * + * Also, if image size or address has changed, the direct block's + * parent has been modified to reflect the change. + * + * Now, make note of the pointer and length of the above buffer for + * use by the serialize function. + */ + dblock->write_buf = (uint8_t *)write_buf; + dblock->write_size = write_size; + + /* finally, pass data back to the metadata cache as appropriate */ + if(!H5F_addr_eq(addr, dblock_addr)) { + dblock_flags |= H5C__SERIALIZE_MOVED_FLAG; + *new_addr = dblock_addr; } /* end if */ - /* Destroy fractal heap direct block */ - if(H5HF_man_dblock_dest(dblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block") + if((hdr->filter_len > 0) && (compressed_len != write_size)) { + dblock_flags |= H5C__SERIALIZE_COMPRESSED_FLAG; + *new_compressed_len = write_size; + } /* end if */ + + *flags = dblock_flags; + + /* final sanity check */ + HDassert(dblock->write_buf); + HDassert(dblock->write_size > 0); done: + /* discard the write buf if we have an error */ + if(write_buf && (write_buf != dblock->blk) && (dblock->write_buf == NULL)) + H5MM_xfree(write_buf); + FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_dblock_dest() */ +} /* end H5HF__cache_dblock_pre_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_clear + * Function: H5HF__cache_dblock_serialize * - * Purpose: Mark a fractal heap direct block in memory as non-dirty. + * Purpose: In principle, this function is supposed to construct the on + * disk image of the direct block, and place that image in the + * image buffer provided by the metadata cache. * - * Return: Non-negative on success/Negative on failure + * However, since there are cases in which the pre_serialize + * function has to construct the on disk image to determine its size + * and address, this function simply copies the image prepared by + * the pre-serialize function into the supplied image buffer, and + * discards a buffer if necessary. * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 27 2006 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_dblock_clear(H5F_t *f, H5HF_direct_t *dblock, hbool_t destroy) +static herr_t +H5HF__cache_dblock_serialize(const H5F_t *f, void *image, size_t len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Direct block info */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* - * Check arguments. - */ + /* Sanity checks */ + HDassert(f); + HDassert(image); + HDassert(len > 0); HDassert(dblock); + HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK); + HDassert((dblock->blk != dblock->write_buf) || (dblock->cache_info.size == dblock->size)); + HDassert(dblock->write_buf); + HDassert(dblock->write_size > 0); + HDassert((dblock->blk != dblock->write_buf) || (dblock->write_size == dblock->size)); + HDassert(dblock->write_size == len); + + /* Copy the image from *(dblock->write_buf) to *image */ + HDmemcpy(image, dblock->write_buf, dblock->write_size); + + /* Free *(dblock->write_buf) if it was allocated by the + * pre-serialize function + */ + if(dblock->write_buf != dblock->blk) + H5MM_xfree(dblock->write_buf); - /* Reset the dirty flag. */ - dblock->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5HF_cache_dblock_dest(f, dblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block") + /* Reset the write_buf and write_size fields */ + dblock->write_buf = NULL; + dblock->write_size = 0; -done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_dblock_clear() */ +} /* end H5HF__cache_dblock_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_notify + * Function: H5HF__cache_dblock_notify * * Purpose: Setup / takedown flush dependencies as direct blocks * are loaded / inserted and evicted from the metadata cache. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * * Programmer: John Mainzer - * 5/17/14 + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_dblock_notify(H5C_notify_action_t action, H5HF_direct_t *dblock) +static herr_t +H5HF__cache_dblock_notify(H5C_notify_action_t action, void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Fractal heap direct block */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ HDassert(dblock); HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK); HDassert(dblock->hdr); HDassert((dblock->fd_parent) || ((dblock->hdr->man_dtable.curr_root_rows == 0) && (dblock->block_off == (hsize_t)0))); switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: HDassert(dblock->parent == dblock->fd_parent); if(dblock->parent) { /* this is a leaf dblock */ /* create flush dependency with parent iblock */ @@ -2001,6 +2678,10 @@ H5HF_cache_dblock_notify(H5C_notify_action_t action, H5HF_direct_t *dblock) } /* end else */ break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: HDassert((dblock->parent == dblock->fd_parent) || ((NULL == dblock->parent) && (dblock->fd_parent))); @@ -2023,39 +2704,47 @@ H5HF_cache_dblock_notify(H5C_notify_action_t action, H5HF_direct_t *dblock) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_dblock_notify() */ +} /* end H5HF__cache_dblock_notify() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_size + * Function: H5HF__cache_dblock_free_icr * - * Purpose: Compute the size in bytes of a fractal heap direct block - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Free the in core memory allocated to the supplied direct + * block. * - * Return: Non-negative on success/Negative on failure + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_dblock_size(const H5F_t H5_ATTR_UNUSED *f, const H5HF_direct_t *dblock, size_t *size_ptr) +static herr_t +H5HF__cache_dblock_free_icr(void *_thing) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Fractal heap direct block */ + herr_t ret_value = SUCCEED; /* Return value */ - /* check arguments */ - HDassert(dblock); - HDassert(size_ptr); + FUNC_ENTER_STATIC - /* Set size value */ - *size_ptr = dblock->size; + /* Sanity checks */ + HDassert(dblock); + HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK); - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5HF_cache_dblock_size() */ + /* Destroy fractal heap direct block */ + if(H5HF_man_dblock_dest(dblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block") +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_dblock_free_icr() */ /*------------------------------------------------------------------------ @@ -2181,7 +2870,7 @@ H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, hid_t dxpl_id, * in this case, since we know that the entry is in cache, * we can pass NULL udata. */ - if(NULL == (root_iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5AC_READ))) + if(NULL == (root_iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5C__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.") unprotect_root_iblock = TRUE; } /* end if */ @@ -2242,7 +2931,7 @@ H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, hid_t dxpl_id, * in this case, since we know that the entry is in cache, * we can pass NULL udata. */ - if(NULL == (iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5AC_READ))) + if(NULL == (iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5C__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.") unprotect_root_iblock = TRUE; HDassert(iblock == root_iblock); @@ -2632,7 +3321,7 @@ H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f, hid_t dxpl_id, /* in this case, since we know that the */ /* entry is in cache, we can pass NULL udata */ - if(NULL == (child_iblock = (H5HF_indirect_t *) H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, child_iblock_addr, NULL, H5AC_READ))) + if(NULL == (child_iblock = (H5HF_indirect_t *) H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, child_iblock_addr, NULL, H5C__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.") unprotect_child_iblock = TRUE; } /* end if */ diff --git a/src/H5HFdbg.c b/src/H5HFdbg.c index 8620f6f..5183b67 100644 --- a/src/H5HFdbg.c +++ b/src/H5HFdbg.c @@ -323,7 +323,7 @@ H5HF_hdr_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, HDassert(fwidth >= 0); /* Load the fractal heap header */ - if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, addr, H5AC_READ))) + if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header") /* Print the information about the heap's header */ @@ -459,13 +459,13 @@ H5HF_dblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, HDassert(block_size > 0); /* Load the fractal heap header */ - if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, hdr_addr, H5AC_READ))) + if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, hdr_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header") /* * Load the heap direct block */ - if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, addr, block_size, NULL, 0, H5AC_READ))) + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, addr, block_size, NULL, 0, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to load fractal heap direct block") /* Print opening message */ @@ -716,13 +716,13 @@ H5HF_iblock_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, HDassert(nrows > 0); /* Load the fractal heap header */ - if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, hdr_addr, H5AC_READ))) + if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, hdr_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header") /* * Load the heap indirect block */ - if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, addr, nrows, NULL, 0, FALSE, H5AC_READ, &did_protect))) + if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, addr, nrows, NULL, 0, FALSE, H5AC__READ_ONLY_FLAG, &did_protect))) HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to load fractal heap indirect block") /* Print the information about the heap's indirect block */ @@ -825,7 +825,7 @@ H5HF_sects_debug(H5F_t *f, hid_t dxpl_id, haddr_t fh_addr, HDassert(fwidth >= 0); /* Load the fractal heap header */ - if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC_READ))) + if(NULL == (hdr = H5HF_hdr_protect(f, dxpl_id, fh_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header") /* Initialize the free space information for the heap */ diff --git a/src/H5HFdblock.c b/src/H5HFdblock.c index 3a54bb9..0d5172c 100644 --- a/src/H5HFdblock.c +++ b/src/H5HFdblock.c @@ -149,6 +149,9 @@ H5HF_man_dblock_create(hid_t dxpl_id, H5HF_hdr_t *hdr, H5HF_indirect_t *par_iblo HDmemset(dblock->blk, 0, dblock->size); #endif /* H5_CLEAR_MEMORY */ + dblock->write_buf = NULL; + dblock->write_size = 0; + /* Allocate [temporary] space for the direct block on disk */ if(H5F_USE_TMP_SPACE(hdr->f)) { if(HADDR_UNDEF == (dblock_addr = H5MF_alloc_tmp(hdr->f, (hsize_t)dblock->size))) @@ -308,9 +311,13 @@ H5HF_man_dblock_destroy(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_direct_t *dblock, } /* end if */ } /* end else */ - /* Indicate that the indirect block should be deleted & file space freed */ + /* Indicate that the indirect block should be deleted */ dblock->file_size = dblock_size; - cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; + cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG; + + /* If the dblock is in real file space, also tell the cache to free its file space */ + if (!H5F_IS_TMP_ADDR(hdr->f, dblock_addr)) + cache_flags |= H5AC__FREE_FILE_SPACE_FLAG; done: /* Unprotect the indirect block, with appropriate flags */ @@ -436,7 +443,7 @@ done: H5HF_direct_t * H5HF_man_dblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t dblock_addr, size_t dblock_size, H5HF_indirect_t *par_iblock, unsigned par_entry, - H5AC_protect_t rw) + unsigned flags) { H5HF_direct_t *dblock; /* Direct block from cache */ H5HF_dblock_cache_ud_t udata; /* parent and other infor for deserializing direct block */ @@ -451,6 +458,9 @@ H5HF_man_dblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t dblock_addr, HDassert(H5F_addr_defined(dblock_addr)); HDassert(dblock_size > 0); + /* only H5AC__READ_ONLY_FLAG may appear in flags */ + HDassert((flags & (~H5AC__READ_ONLY_FLAG)) == 0); + /* Set up parent info */ udata.par_info.hdr = hdr; udata.par_info.iblock = par_iblock; @@ -485,7 +495,7 @@ H5HF_man_dblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t dblock_addr, } /* end else */ /* Protect the direct block */ - if(NULL == (dblock = (H5HF_direct_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, &udata, rw))) + if(NULL == (dblock = (H5HF_direct_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FHEAP_DBLOCK, dblock_addr, &udata, flags))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap direct block") /* Set the return value */ @@ -512,7 +522,7 @@ done: herr_t H5HF_man_dblock_locate(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t obj_off, H5HF_indirect_t **ret_iblock, unsigned *ret_entry, hbool_t *ret_did_protect, - H5AC_protect_t rw) + unsigned flags) { haddr_t iblock_addr; /* Indirect block's address */ H5HF_indirect_t *iblock; /* Pointer to indirect block */ @@ -531,6 +541,9 @@ H5HF_man_dblock_locate(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t obj_off, HDassert(ret_iblock); HDassert(ret_did_protect); + /* only H5AC__READ_ONLY_FLAG may appear in flags */ + HDassert((flags & (~H5AC__READ_ONLY_FLAG)) == 0); + /* Look up row & column for object */ if(H5HF_dtable_lookup(&hdr->man_dtable, obj_off, &row, &col) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of object") @@ -539,7 +552,7 @@ H5HF_man_dblock_locate(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t obj_off, iblock_addr = hdr->man_dtable.table_addr; /* Lock root indirect block */ - if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, hdr->man_dtable.curr_root_rows, NULL, 0, FALSE, rw, &did_protect))) + if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, hdr->man_dtable.curr_root_rows, NULL, 0, FALSE, flags, &did_protect))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") /* Check for indirect block row */ @@ -569,7 +582,7 @@ H5HF_man_dblock_locate(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t obj_off, } /* end if */ /* Lock child indirect block */ - if(NULL == (new_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, nrows, iblock, entry, FALSE, rw, &new_did_protect))) + if(NULL == (new_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, nrows, iblock, entry, FALSE, flags, &new_did_protect))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") /* Release the current indirect block */ diff --git a/src/H5HFhdr.c b/src/H5HFhdr.c index bfc8fc6..814d524 100644 --- a/src/H5HFhdr.c +++ b/src/H5HFhdr.c @@ -530,7 +530,7 @@ done: *------------------------------------------------------------------------- */ H5HF_hdr_t * -H5HF_hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, H5AC_protect_t rw) +H5HF_hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags) { H5HF_hdr_cache_ud_t cache_udata; /* User-data for callback */ H5HF_hdr_t *hdr; /* Fractal heap header */ @@ -542,12 +542,15 @@ H5HF_hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, H5AC_protect_t rw) HDassert(f); HDassert(H5F_addr_defined(addr)); + /* only H5AC__READ_ONLY_FLAG may appear in flags */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Set up userdata for protect call */ cache_udata.f = f; cache_udata.dxpl_id = dxpl_id; /* Lock the heap header into memory */ - if(NULL == (hdr = (H5HF_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_HDR, addr, &cache_udata, rw))) + if(NULL == (hdr = (H5HF_hdr_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_HDR, addr, &cache_udata, flags))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header") /* Set the header's address */ @@ -1110,7 +1113,7 @@ H5HF_hdr_update_iter(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_size) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap indirect block") /* Lock new indirect block */ - if(NULL == (new_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, new_iblock_addr, child_nrows, iblock, next_entry, FALSE, H5AC_WRITE, &did_protect))) + if(NULL == (new_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, new_iblock_addr, child_nrows, iblock, next_entry, FALSE, H5AC__NO_FLAGS_SET, &did_protect))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") /* Move iterator down one level (pins indirect block) */ @@ -1304,7 +1307,7 @@ H5HF_hdr_reverse_iter(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t dblock_addr) child_nrows = H5HF_dtable_size_to_rows(&hdr->man_dtable, hdr->man_dtable.row_block_size[row]); /* Lock child indirect block */ - if(NULL == (child_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock->ents[curr_entry].addr, child_nrows, iblock, curr_entry, FALSE, H5AC_WRITE, &did_protect))) + if(NULL == (child_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock->ents[curr_entry].addr, child_nrows, iblock, curr_entry, FALSE, H5AC__NO_FLAGS_SET, &did_protect))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") /* Set the current location of the iterator */ diff --git a/src/H5HFiblock.c b/src/H5HFiblock.c index 4473803..547aaf0 100644 --- a/src/H5HFiblock.c +++ b/src/H5HFiblock.c @@ -330,8 +330,15 @@ H5HF_iblock_decr(H5HF_indirect_t *iblock) /* Check for expunging the indirect block from the metadata cache */ if(expunge_iblock) { - /* Evict the indirect block from the metadata cache */ - if(H5AC_expunge_entry(hdr->f, H5AC_dxpl_id, H5AC_FHEAP_IBLOCK, iblock_addr, H5AC__FREE_FILE_SPACE_FLAG) < 0) + unsigned cache_flags = H5AC__NO_FLAGS_SET; + + /* if the indirect block is in real file space, tell + * the cache to free its file space. + */ + if (!H5F_IS_TMP_ADDR(hdr->f, iblock_addr)) + cache_flags |= H5AC__FREE_FILE_SPACE_FLAG; + + if(H5AC_expunge_entry(hdr->f, H5AC_dxpl_id, H5AC_FHEAP_IBLOCK, iblock_addr, cache_flags) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "unable to remove indirect block from cache") } /* end if */ } /* end if */ @@ -424,7 +431,7 @@ H5HF_man_iblock_root_create(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_si /* Move current direct block (used as root) into new indirect block */ /* Lock new indirect block */ - if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, nrows, NULL, 0, FALSE, H5AC_WRITE, &did_protect))) + if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, nrows, NULL, 0, FALSE, H5AC__NO_FLAGS_SET, &did_protect))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") /* Check if there's already a direct block as root) */ @@ -433,7 +440,7 @@ H5HF_man_iblock_root_create(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t min_dblock_si H5HF_direct_t *dblock; /* Pointer to direct block to query */ /* Lock first (root) direct block */ - if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, hdr->man_dtable.table_addr, hdr->man_dtable.cparam.start_block_size, NULL, 0, H5AC_WRITE))) + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, hdr->man_dtable.table_addr, hdr->man_dtable.cparam.start_block_size, NULL, 0, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block") /* Attach direct block to new root indirect block */ @@ -879,7 +886,7 @@ H5HF_man_iblock_root_revert(H5HF_indirect_t *root_iblock, hid_t dxpl_id) dblock_size = hdr->man_dtable.cparam.start_block_size; /* Get pointer to last direct block */ - if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, root_iblock, 0, H5AC_WRITE))) + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, root_iblock, 0, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block") HDassert(dblock->parent == root_iblock); HDassert(dblock->par_entry == 0); @@ -1159,7 +1166,7 @@ done: H5HF_indirect_t * H5HF_man_iblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t iblock_addr, unsigned iblock_nrows, H5HF_indirect_t *par_iblock, unsigned par_entry, - hbool_t must_protect, H5AC_protect_t rw, hbool_t *did_protect) + hbool_t must_protect, unsigned flags, hbool_t *did_protect) { H5HF_parent_t par_info; /* Parent info for loading block */ H5HF_indirect_t *iblock = NULL; /* Indirect block from cache */ @@ -1176,6 +1183,9 @@ H5HF_man_iblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t iblock_addr, HDassert(iblock_nrows > 0); HDassert(did_protect); + /* only H5AC__READ_ONLY_FLAG may appear in flags */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Check if we are allowed to use existing pinned iblock pointer */ if(!must_protect) { /* Check for this block already being pinned */ @@ -1235,7 +1245,7 @@ H5HF_man_iblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t iblock_addr, cache_udata.nrows = &iblock_nrows; /* Protect the indirect block */ - if(NULL == (iblock = (H5HF_indirect_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, iblock_addr, &cache_udata, rw))) + if(NULL == (iblock = (H5HF_indirect_t *)H5AC_protect(hdr->f, dxpl_id, H5AC_FHEAP_IBLOCK, iblock_addr, &cache_udata, flags))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap indirect block") /* Set the indirect block's address */ @@ -1579,7 +1589,7 @@ H5HF_man_iblock_delete(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t iblock_addr, HDassert(iblock_nrows > 0); /* Lock indirect block */ - if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, iblock_nrows, par_iblock, par_entry, TRUE, H5AC_WRITE, &did_protect))) + if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, iblock_nrows, par_iblock, par_entry, TRUE, H5AC__NO_FLAGS_SET, &did_protect))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") HDassert(iblock->nchildren > 0); HDassert(did_protect == TRUE); @@ -1637,8 +1647,14 @@ H5HF_man_iblock_delete(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t iblock_addr, } #endif /* NDEBUG */ - /* Indicate that the indirect block should be deleted & file space freed */ - cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; + /* Indicate that the indirect block should be deleted */ + cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG; + + /* If the indirect block is in real file space, tell + * the cache to free its file space as well. + */ + if (!H5F_IS_TMP_ADDR(hdr->f, iblock_addr)) + cache_flags |= H5AC__FREE_FILE_SPACE_FLAG; done: /* Unprotect the indirect block, with appropriate flags */ @@ -1680,7 +1696,7 @@ H5HF_man_iblock_size(H5F_t *f, hid_t dxpl_id, H5HF_hdr_t *hdr, haddr_t iblock_ad HDassert(heap_size); /* Protect the indirect block */ - if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, nrows, par_iblock, par_entry, FALSE, H5AC_READ, &did_protect))) + if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, nrows, par_iblock, par_entry, FALSE, H5AC__READ_ONLY_FLAG, &did_protect))) HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to load fractal heap indirect block") /* Accumulate size of this indirect block */ diff --git a/src/H5HFiter.c b/src/H5HFiter.c index 137d0ee..262a9ee 100644 --- a/src/H5HFiter.c +++ b/src/H5HFiter.c @@ -217,7 +217,7 @@ H5HF_man_iter_start_offset(H5HF_hdr_t *hdr, hid_t dxpl_id, } /* end else */ /* Load indirect block for this context location */ - if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, iblock_nrows, iblock_parent, iblock_par_entry, FALSE, H5AC_WRITE, &did_protect))) + if(NULL == (iblock = H5HF_man_iblock_protect(hdr, dxpl_id, iblock_addr, iblock_nrows, iblock_parent, iblock_par_entry, FALSE, H5AC__NO_FLAGS_SET, &did_protect))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") /* Make indirect block the context for the current location */ diff --git a/src/H5HFman.c b/src/H5HFman.c index 58dab10..5f95a91 100644 --- a/src/H5HFman.c +++ b/src/H5HFman.c @@ -161,7 +161,7 @@ H5HF_man_insert(H5HF_hdr_t *hdr, hid_t dxpl_id, size_t obj_size, const void *obj HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't retrieve direct block information") /* Lock direct block */ - if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, sec_node->u.single.parent, sec_node->u.single.par_entry, H5AC_WRITE))) + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, sec_node->u.single.parent, sec_node->u.single.par_entry, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block") /* Insert object into block */ @@ -274,7 +274,11 @@ H5HF_man_op_real(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, H5HF_operator_t op, void *op_data, unsigned op_flags) { H5HF_direct_t *dblock = NULL; /* Pointer to direct block to query */ - H5AC_protect_t dblock_access; /* Access method for direct block */ + unsigned dblock_access_flags; /* Access method for direct block */ + /* must equal either + * H5AC__NO_FLAGS_SET or + * H5AC__READ_ONLY_FLAG + */ haddr_t dblock_addr; /* Direct block address */ size_t dblock_size; /* Direct block size */ unsigned dblock_cache_flags; /* Flags for unprotecting direct block */ @@ -298,11 +302,11 @@ H5HF_man_op_real(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, /* Check pipeline */ H5HF_MAN_WRITE_CHECK_PLINE(hdr) - dblock_access = H5AC_WRITE; + dblock_access_flags = H5AC__NO_FLAGS_SET; dblock_cache_flags = H5AC__DIRTIED_FLAG; } /* end if */ else { - dblock_access = H5AC_READ; + dblock_access_flags = H5AC__READ_ONLY_FLAG; dblock_cache_flags = H5AC__NO_FLAGS_SET; } /* end else */ @@ -332,7 +336,7 @@ H5HF_man_op_real(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, dblock_size = hdr->man_dtable.cparam.start_block_size; /* Lock direct block */ - if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, NULL, 0, dblock_access))) + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, NULL, 0, dblock_access_flags))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap direct block") } /* end if */ else { @@ -341,7 +345,7 @@ H5HF_man_op_real(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, unsigned entry; /* Entry of block */ /* Look up indirect block containing direct block */ - if(H5HF_man_dblock_locate(hdr, dxpl_id, obj_off, &iblock, &entry, &did_protect, H5AC_READ) < 0) + if(H5HF_man_dblock_locate(hdr, dxpl_id, obj_off, &iblock, &entry, &did_protect, H5AC__READ_ONLY_FLAG) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") /* Set direct block info */ @@ -359,7 +363,7 @@ H5HF_man_op_real(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id, } /* end if */ /* Lock direct block */ - if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, iblock, entry, dblock_access))) { + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, iblock, entry, dblock_access_flags))) { /* Unlock indirect block */ if(H5HF_man_iblock_unprotect(iblock, dxpl_id, H5AC__NO_FLAGS_SET, did_protect) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block") @@ -578,7 +582,7 @@ H5HF_man_remove(H5HF_hdr_t *hdr, hid_t dxpl_id, const uint8_t *id) } /* end if */ else { /* Look up indirect block containing direct block */ - if(H5HF_man_dblock_locate(hdr, dxpl_id, obj_off, &iblock, &dblock_entry, &did_protect, H5AC_WRITE) < 0) + if(H5HF_man_dblock_locate(hdr, dxpl_id, obj_off, &iblock, &dblock_entry, &did_protect, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") /* Check for offset of invalid direct block */ diff --git a/src/H5HFpkg.h b/src/H5HFpkg.h index b0eba2f..cb5488b 100644 --- a/src/H5HFpkg.h +++ b/src/H5HFpkg.h @@ -341,7 +341,7 @@ typedef struct H5HF_hdr_t { size_t rc; /* Reference count of heap's components using heap header */ haddr_t heap_addr; /* Address of heap header in the file */ size_t heap_size; /* Size of heap header in the file */ - H5AC_protect_t mode; /* Access mode for heap */ + unsigned mode; /* Access mode for heap */ H5F_t *f; /* Pointer to file for heap */ size_t file_rc; /* Reference count of files using heap header */ hbool_t pending_delete; /* Heap is pending deletion */ @@ -425,6 +425,31 @@ typedef struct H5HF_direct_t { size_t size; /* Size of direct block */ hsize_t file_size; /* Size of direct block in file (only valid when block's space is being freed) */ uint8_t *blk; /* Pointer to buffer containing block data */ + uint8_t *write_buf; /* Pointer to buffer containing the block data */ + /* in form ready to copy to the metadata */ + /* cache's image buffer. */ + /* */ + /* This field is used by */ + /* H5HF_cache_dblock_pre_serialize() to pass */ + /* the serialized image of the direct block to */ + /* H5HF_cache_dblock_serialize(). It should */ + /* NULL at all other times. */ + /* */ + /* If I/O filters are enabled, the pre- */ + /* the pre-serialize function will allocate */ + /* a buffer, copy the filtered version of the */ + /* direct block image into it, and place the */ + /* base address of the buffer in this field. */ + /* The serialize function must discard this */ + /* buffer after it copies the contents into */ + /* the image buffer provided by the metadata */ + /* cache. */ + /* */ + /* If I/O filters are not enabled, the */ + /* write_buf field is simply set equal to the */ + /* blk field by the pre-serialize function, */ + /* and back to NULL by the serialize function. */ + size_t write_size; /* size of the buffer pointed to by write_buf. */ /* Stored values */ hsize_t block_off; /* Offset of the block within the heap's address space */ @@ -520,6 +545,14 @@ typedef struct H5HF_dblock_cache_ud_t { * calls to it. */ unsigned filter_mask; /* Excluded filters for direct block */ + uint8_t *dblk; /* Pointer to the buffer containing the decompressed + * direct block data obtained in verify_chksum callback. + * It will be used later in deserialize callback. + */ + htri_t decompressed; /* Indicate that the direct block has been + * decompressed in verify_chksum callback. + * It will be used later in deserialize callback. + */ } H5HF_dblock_cache_ud_t; @@ -604,7 +637,7 @@ H5_DLL hsize_t H5HF_dtable_span_size(const H5HF_dtable_t *dtable, unsigned start H5_DLL H5HF_hdr_t * H5HF_hdr_alloc(H5F_t *f); H5_DLL haddr_t H5HF_hdr_create(H5F_t *f, hid_t dxpl_id, const H5HF_create_t *cparam); H5_DLL H5HF_hdr_t *H5HF_hdr_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, - H5AC_protect_t rw); + unsigned flags); H5_DLL herr_t H5HF_hdr_finish_init_phase1(H5HF_hdr_t *hdr); H5_DLL herr_t H5HF_hdr_finish_init_phase2(H5HF_hdr_t *hdr); H5_DLL herr_t H5HF_hdr_finish_init(H5HF_hdr_t *hdr); @@ -645,7 +678,7 @@ H5_DLL herr_t H5HF_man_iblock_create(H5HF_hdr_t *hdr, hid_t dxpl_id, H5_DLL H5HF_indirect_t *H5HF_man_iblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t iblock_addr, unsigned iblock_nrows, H5HF_indirect_t *par_iblock, unsigned par_entry, hbool_t must_protect, - H5AC_protect_t rw, hbool_t *did_protect); + unsigned flags, hbool_t *did_protect); H5_DLL herr_t H5HF_man_iblock_unprotect(H5HF_indirect_t *iblock, hid_t dxpl_id, unsigned cache_flags, hbool_t did_protect); H5_DLL herr_t H5HF_man_iblock_attach(H5HF_indirect_t *iblock, unsigned entry, @@ -671,10 +704,10 @@ H5_DLL herr_t H5HF_man_dblock_destroy(H5HF_hdr_t *hdr, hid_t dxpl_id, H5_DLL H5HF_direct_t *H5HF_man_dblock_protect(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t dblock_addr, size_t dblock_size, H5HF_indirect_t *par_iblock, unsigned par_entry, - H5AC_protect_t rw); + unsigned flags); H5_DLL herr_t H5HF_man_dblock_locate(H5HF_hdr_t *hdr, hid_t dxpl_id, hsize_t obj_off, H5HF_indirect_t **par_iblock, - unsigned *par_entry, hbool_t *par_did_protect, H5AC_protect_t rw); + unsigned *par_entry, hbool_t *par_did_protect, unsigned flags); H5_DLL herr_t H5HF_man_dblock_delete(H5F_t *f, hid_t dxpl_id, haddr_t dblock_addr, hsize_t dblock_size); H5_DLL herr_t H5HF_man_dblock_dest(H5HF_direct_t *dblock); diff --git a/src/H5HFsection.c b/src/H5HFsection.c index 7f960d4..6da456b 100644 --- a/src/H5HFsection.c +++ b/src/H5HFsection.c @@ -555,7 +555,7 @@ H5HF_sect_single_locate_parent(H5HF_hdr_t *hdr, hid_t dxpl_id, hbool_t refresh, HDassert(sect); /* Look up indirect block containing direct blocks for range */ - if(H5HF_man_dblock_locate(hdr, dxpl_id, sect->sect_info.addr, &sec_iblock, &sec_entry, &did_protect, H5AC_READ) < 0) + if(H5HF_man_dblock_locate(hdr, dxpl_id, sect->sect_info.addr, &sec_iblock, &sec_entry, &did_protect, H5AC__READ_ONLY_FLAG) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") /* Increment reference count on indirect block that free section is in */ @@ -776,7 +776,7 @@ H5HF_sect_single_full_dblock(H5HF_hdr_t *hdr, hid_t dxpl_id, hdr->man_dtable.curr_root_rows > 0) { H5HF_direct_t *dblock; /* Pointer to direct block for section */ - if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, sect->u.single.parent, sect->u.single.par_entry, H5AC_WRITE))) + if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, dblock_size, sect->u.single.parent, sect->u.single.par_entry, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block") HDassert(H5F_addr_eq(dblock->block_off + dblock_overhead, sect->sect_info.addr)); @@ -1094,7 +1094,7 @@ H5HF_sect_single_shrink(H5FS_section_info_t **_sect, void H5_ATTR_UNUSED *_udata /* (should be a root direct block) */ HDassert(dblock_addr == hdr->man_dtable.table_addr); if(NULL == (dblock = H5HF_man_dblock_protect(hdr, dxpl_id, dblock_addr, - dblock_size, (*sect)->u.single.parent, (*sect)->u.single.par_entry, H5AC_WRITE))) + dblock_size, (*sect)->u.single.parent, (*sect)->u.single.par_entry, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load fractal heap direct block") HDassert(H5F_addr_eq(dblock->block_off + dblock_size, (*sect)->sect_info.addr + (*sect)->sect_info.size)); @@ -1221,7 +1221,7 @@ H5HF_sect_single_valid(const H5FS_section_class_t H5_ATTR_UNUSED *cls, const H5F H5HF_direct_t *dblock; /* Direct block for section */ /* Protect the direct block for the section */ - dblock = H5HF_man_dblock_protect(iblock->hdr, H5AC_dxpl_id, dblock_addr, dblock_size, iblock, sect->u.single.par_entry, H5AC_READ); + dblock = H5HF_man_dblock_protect(iblock->hdr, H5AC_dxpl_id, dblock_addr, dblock_size, iblock, sect->u.single.par_entry, H5AC__READ_ONLY_FLAG); HDassert(dblock); /* Sanity check settings for section */ @@ -2536,7 +2536,7 @@ H5HF_sect_indirect_init_rows(H5HF_hdr_t *hdr, hid_t dxpl_id, /* If the child indirect block's address is defined, protect it */ if(H5F_addr_defined(child_iblock_addr)) { - if(NULL == (child_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, child_iblock_addr, child_nrows, sect->u.indirect.u.iblock, curr_entry, FALSE, H5AC_WRITE, &did_protect))) + if(NULL == (child_iblock = H5HF_man_iblock_protect(hdr, dxpl_id, child_iblock_addr, child_nrows, sect->u.indirect.u.iblock, curr_entry, FALSE, H5AC__NO_FLAGS_SET, &did_protect))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block") } /* end if */ else @@ -2771,7 +2771,7 @@ H5HF_sect_indirect_revive_row(H5HF_hdr_t *hdr, hid_t dxpl_id, H5HF_free_section_ HDassert(sect->sect_info.state == H5FS_SECT_SERIALIZED); /* Look up indirect block containing indirect blocks for section */ - if(H5HF_man_dblock_locate(hdr, dxpl_id, sect->sect_info.addr, &sec_iblock, NULL, &did_protect, H5AC_READ) < 0) + if(H5HF_man_dblock_locate(hdr, dxpl_id, sect->sect_info.addr, &sec_iblock, NULL, &did_protect, H5AC__READ_ONLY_FLAG) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of section") /* Increment reference count on indirect block that free section is in */ @@ -246,7 +246,7 @@ done: *------------------------------------------------------------------------- */ H5HG_heap_t * -H5HG_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, H5AC_protect_t rw) +H5HG_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags) { H5HG_heap_t *heap; /* Global heap */ H5HG_heap_t *ret_value; /* Return value */ @@ -257,8 +257,11 @@ H5HG_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, H5AC_protect_t rw) HDassert(f); HDassert(H5F_addr_defined(addr)); + /* only H5AC__READ_ONLY_FLAG may appear in flags */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Lock the heap into memory */ - if(NULL == (heap = (H5HG_heap_t *)H5AC_protect(f, dxpl_id, H5AC_GHEAP, addr, f, rw))) + if(NULL == (heap = (H5HG_heap_t *)H5AC_protect(f, dxpl_id, H5AC_GHEAP, addr, f, flags))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect global heap") /* Set the heap's address */ @@ -440,7 +443,7 @@ H5HG_extend(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t need) HDassert(H5F_addr_defined(addr)); /* Protect the heap */ - if(NULL == (heap = H5HG_protect(f, dxpl_id, addr, H5AC_WRITE))) + if(NULL == (heap = H5HG_protect(f, dxpl_id, addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap") /* Re-allocate the heap information in memory */ @@ -554,7 +557,7 @@ H5HG_insert(H5F_t *f, hid_t dxpl_id, size_t size, void *obj, H5HG_t *hobj/*out*/ } /* end if */ HDassert(H5F_addr_defined(addr)); - if(NULL == (heap = H5HG_protect(f, dxpl_id, addr, H5AC_WRITE))) + if(NULL == (heap = H5HG_protect(f, dxpl_id, addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap") /* Split the free space to make room for the new object */ @@ -618,7 +621,7 @@ H5HG_read(H5F_t *f, hid_t dxpl_id, H5HG_t *hobj, void *object/*out*/, HDassert(hobj); /* Load the heap */ - if(NULL == (heap = H5HG_protect(f, dxpl_id, hobj->addr, H5AC_READ))) + if(NULL == (heap = H5HG_protect(f, dxpl_id, hobj->addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect global heap") HDassert(hobj->idx < heap->nused); @@ -692,7 +695,7 @@ H5HG_link(H5F_t *f, hid_t dxpl_id, const H5HG_t *hobj, int adjust) HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file") /* Load the heap */ - if(NULL == (heap = H5HG_protect(f, dxpl_id, hobj->addr, H5AC_WRITE))) + if(NULL == (heap = H5HG_protect(f, dxpl_id, hobj->addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap") if(adjust != 0) { @@ -755,7 +758,7 @@ H5HG_remove (H5F_t *f, hid_t dxpl_id, H5HG_t *hobj) HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file") /* Load the heap */ - if(NULL == (heap = H5HG_protect(f, dxpl_id, hobj->addr, H5AC_WRITE))) + if(NULL == (heap = H5HG_protect(f, dxpl_id, hobj->addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap") HDassert(hobj->idx < heap->nused); diff --git a/src/H5HGcache.c b/src/H5HGcache.c index aac73ed..c5d5517 100644 --- a/src/H5HGcache.c +++ b/src/H5HGcache.c @@ -62,12 +62,16 @@ /********************/ /* Metadata cache callbacks */ -static H5HG_heap_t *H5HG_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5HG_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, - H5HG_heap_t *heap, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5HG_dest(H5F_t *f, H5HG_heap_t *heap); -static herr_t H5HG_clear(H5F_t *f, H5HG_heap_t *heap, hbool_t destroy); -static herr_t H5HG_size(const H5F_t *f, const H5HG_heap_t *heap, size_t *size_ptr); +static herr_t H5HG__cache_heap_get_load_size(const void *_image, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static void *H5HG__cache_heap_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5HG__cache_heap_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5HG__cache_heap_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5HG__cache_heap_free_icr(void *thing); /*********************/ @@ -76,13 +80,20 @@ static herr_t H5HG_size(const H5F_t *f, const H5HG_heap_t *heap, size_t *size_pt /* H5HG inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_GHEAP[1] = {{ - H5AC_GHEAP_ID, - (H5AC_load_func_t)H5HG_load, - (H5AC_flush_func_t)H5HG_flush, - (H5AC_dest_func_t)H5HG_dest, - (H5AC_clear_func_t)H5HG_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5HG_size, + H5AC_GHEAP_ID, /* Metadata client ID */ + "global heap", /* Metadata client name (for debugging) */ + H5FD_MEM_GHEAP, /* File space memory type for client */ + H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ + H5HG__cache_heap_get_load_size, /* 'get_load_size' callback */ + NULL, /* 'verify_chksum' callback */ + H5HG__cache_heap_deserialize, /* 'deserialize' callback */ + H5HG__cache_heap_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5HG__cache_heap_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5HG__cache_heap_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -98,162 +109,237 @@ const H5AC_class_t H5AC_GHEAP[1] = {{ /*------------------------------------------------------------------------- - * Function: H5HG_load + * Function: H5HG__cache_heap_get_load_size() * - * Purpose: Loads a global heap collection from disk. + * Purpose: Return the initial speculative read size to the metadata + * cache. This size will be used in the initial attempt to read + * the global heap. If this read is too small, the cache will + * try again with the correct value obtained from + * H5HG__cache_heap_image_len(). * - * Return: Success: Ptr to a global heap collection. + * Return: Success: SUCCEED + * Failure: FAIL * - * Failure: NULL + * Programmer: John Mainzer + * 7/27/14 * - * Programmer: Robb Matzke - * Friday, March 27, 1998 + *------------------------------------------------------------------------- + */ +static herr_t +H5HG__cache_heap_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5F_t *f = (H5F_t *)_udata; /* File pointer -- obtained from user data */ + size_t heap_size; /* Total size of collection */ + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + HDassert(image_len); + + if(image == NULL) { + *image_len = (size_t)H5HG_MINSIZE; + + } else { /* compute actual_len */ + HDassert(f); + HDassert(actual_len); + HDassert(*actual_len == *image_len); + + /* Magic number */ + if(HDmemcmp(image, H5HG_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "bad global heap collection signature") + image += H5_SIZEOF_MAGIC; + + /* Version */ + if(H5HG_VERSION != *image++) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "wrong version number in global heap") + + /* Reserved */ + image += 3; + + /* Size */ + H5F_DECODE_LENGTH(f, image, heap_size); + HDassert(heap_size >= H5HG_MINSIZE); + HDassert(*image_len == H5HG_MINSIZE); + + *actual_len = heap_size; + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HG__cache_heap_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5HG__cache_heap_deserialize + * + * Purpose: Given a buffer containing the on disk image of the global + * heap, deserialize it, load its contents into a newly allocated + * instance of H5HG_heap_t, and return a pointer to the new instance. + * + * Note that this heap client uses speculative reads. If the supplied + * buffer is too small, we simply make note of the correct size, and + * wait for the metadata cache to try again. + * + * Return: Success: Pointer to in core representation + * Failure: NULL + * + * Programmer: John Mainzer + * 7/27/14 * *------------------------------------------------------------------------- */ -static H5HG_heap_t * -H5HG_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata) +static void * +H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { - H5HG_heap_t *heap = NULL; - uint8_t *p; - size_t nalloc, need; - size_t max_idx = 0; /* The maximum index seen */ - H5HG_heap_t *ret_value = NULL; /* Return value */ + H5F_t *f = (H5F_t *)_udata; /* File pointer -- obtained from user data */ + H5HG_heap_t *heap = NULL; /* New global heap */ + uint8_t *image; /* Pointer to image to decode */ + void *ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* check arguments */ + /* Sanity checks */ + HDassert(_image); + HDassert(len >= (size_t)H5HG_MINSIZE); HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata); + HDassert(dirty); - /* Read the initial 4k page */ + /* Allocate a new global heap */ if(NULL == (heap = H5FL_CALLOC(H5HG_heap_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") heap->shared = H5F_SHARED(f); - if(NULL == (heap->chunk = H5FL_BLK_MALLOC(gheap_chunk, (size_t)H5HG_MINSIZE))) + if(NULL == (heap->chunk = H5FL_BLK_MALLOC(gheap_chunk, len))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - if(H5F_block_read(f, H5FD_MEM_GHEAP, addr, (size_t)H5HG_MINSIZE, dxpl_id, heap->chunk) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "unable to read global heap collection") - p = heap->chunk; + + /* copy the image buffer into the newly allocate chunk */ + HDmemcpy(heap->chunk, _image, len); + + image = heap->chunk; /* Magic number */ - if(HDmemcmp(p, H5HG_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "bad global heap collection signature") - p += H5_SIZEOF_MAGIC; + if(HDmemcmp(image, H5HG_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "bad global heap collection signature") + image += H5_SIZEOF_MAGIC; /* Version */ - if(H5HG_VERSION != *p++) - HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "wrong version number in global heap") + if(H5HG_VERSION != *image++) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "wrong version number in global heap") /* Reserved */ - p += 3; + image += 3; /* Size */ - H5F_DECODE_LENGTH(f, p, heap->size); + H5F_DECODE_LENGTH(f, image, heap->size); HDassert(heap->size >= H5HG_MINSIZE); - - /* - * If we didn't read enough in the first try, then read the rest of the - * collection now. - */ - if(heap->size > H5HG_MINSIZE) { - haddr_t next_addr = addr + (hsize_t)H5HG_MINSIZE; - - if(NULL == (heap->chunk = H5FL_BLK_REALLOC(gheap_chunk, heap->chunk, heap->size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - if(H5F_block_read(f, H5FD_MEM_GHEAP, next_addr, (heap->size - H5HG_MINSIZE), dxpl_id, heap->chunk + H5HG_MINSIZE) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "unable to read global heap collection") - } /* end if */ - - /* Decode each object */ - p = heap->chunk + H5HG_SIZEOF_HDR(f); - nalloc = H5HG_NOBJS(f, heap->size); - - /* Calloc the obj array because the file format spec makes no guarantee - * about the order of the objects, and unused slots must be set to zero. - */ - if(NULL == (heap->obj = H5FL_SEQ_CALLOC(H5HG_obj_t, nalloc))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - heap->nalloc = nalloc; - while(p < (heap->chunk + heap->size)) { - if((p + H5HG_SIZEOF_OBJHDR(f)) > (heap->chunk + heap->size)) { - /* - * The last bit of space is too tiny for an object header, so we - * assume that it's free space. - */ - HDassert(NULL == heap->obj[0].begin); - heap->obj[0].size = (size_t)(((const uint8_t *)heap->chunk + heap->size) - p); - heap->obj[0].begin = p; - p += heap->obj[0].size; - } /* end if */ - else { - unsigned idx; - uint8_t *begin = p; - - UINT16DECODE(p, idx); - - /* Check if we need more room to store heap objects */ - if(idx >= heap->nalloc) { - size_t new_alloc; /* New allocation number */ - H5HG_obj_t *new_obj; /* New array of object descriptions */ - - /* Determine the new number of objects to index */ - new_alloc = MAX(heap->nalloc * 2, (idx + 1)); - HDassert(idx < new_alloc); - - /* Reallocate array of objects */ - if(NULL == (new_obj = H5FL_SEQ_REALLOC(H5HG_obj_t, heap->obj, new_alloc))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - /* Clear newly allocated space */ - HDmemset(&new_obj[heap->nalloc], 0, (new_alloc - heap->nalloc) * sizeof(heap->obj[0])); - - /* Update heap information */ - heap->nalloc = new_alloc; - heap->obj = new_obj; - HDassert(heap->nalloc > heap->nused); + HDassert((len == H5HG_MINSIZE) /* first try */ || + ((len == heap->size) && (len > H5HG_MINSIZE))); /* second try */ + + if(len == heap->size) { /* proceed with the deserialize */ + size_t max_idx = 0; + size_t nalloc; + + /* Decode each object */ + image = heap->chunk + H5HG_SIZEOF_HDR(f); + nalloc = H5HG_NOBJS(f, heap->size); + + /* Calloc the obj array because the file format spec makes no guarantee + * about the order of the objects, and unused slots must be set to zero. + */ + if(NULL == (heap->obj = H5FL_SEQ_CALLOC(H5HG_obj_t, nalloc))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + heap->nalloc = nalloc; + + while(image < (heap->chunk + heap->size)) { + if((image + H5HG_SIZEOF_OBJHDR(f)) > (heap->chunk + heap->size)) { + /* + * The last bit of space is too tiny for an object header, so + * we assume that it's free space. + */ + HDassert(NULL == heap->obj[0].begin); + heap->obj[0].size = (size_t)(((const uint8_t *)heap->chunk + heap->size) - image); + heap->obj[0].begin = image; + image += heap->obj[0].size; } /* end if */ - - UINT16DECODE(p, heap->obj[idx].nrefs); - p += 4; /*reserved*/ - H5F_DECODE_LENGTH(f, p, heap->obj[idx].size); - heap->obj[idx].begin = begin; - - /* - * The total storage size includes the size of the object header - * and is zero padded so the next object header is properly - * aligned. The entire obj array was calloc'ed, so no need to zero - * the space here. The last bit of space is the free space object - * whose size is never padded and already includes the object - * header. - */ - if(idx > 0) { - need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(heap->obj[idx].size); - - if(idx > max_idx) - max_idx = idx; - } /* end if */ - else - need = heap->obj[idx].size; - p = begin + need; - } /* end else */ - } /* end while */ - HDassert(p == heap->chunk + heap->size); - HDassert(H5HG_ISALIGNED(heap->obj[0].size)); - - /* Set the next index value to use */ - if(max_idx > 0) - heap->nused = max_idx + 1; + else { + size_t need; + unsigned idx; + uint8_t *begin = image; + + UINT16DECODE(image, idx); + + /* Check if we need more room to store heap objects */ + if(idx >= heap->nalloc) { + size_t new_alloc; /* New allocation number */ + H5HG_obj_t *new_obj; /* New array of object descriptions */ + + /* Determine the new number of objects to index */ + new_alloc = MAX(heap->nalloc * 2, (idx + 1)); + HDassert(idx < new_alloc); + + /* Reallocate array of objects */ + if(NULL == (new_obj = H5FL_SEQ_REALLOC(H5HG_obj_t, heap->obj, new_alloc))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Clear newly allocated space */ + HDmemset(&new_obj[heap->nalloc], 0, (new_alloc - heap->nalloc) * sizeof(heap->obj[0])); + + /* Update heap information */ + heap->nalloc = new_alloc; + heap->obj = new_obj; + HDassert(heap->nalloc > heap->nused); + } /* end if */ + + UINT16DECODE(image, heap->obj[idx].nrefs); + image += 4; /*reserved*/ + H5F_DECODE_LENGTH(f, image, heap->obj[idx].size); + heap->obj[idx].begin = begin; + + /* + * The total storage size includes the size of the object + * header and is zero padded so the next object header is + * properly aligned. The entire obj array was calloc'ed, + * so no need to zero the space here. The last bit of space + * is the free space object whose size is never padded and + * already includes the object header. + */ + if(idx > 0) { + need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(heap->obj[idx].size); + if(idx > max_idx) + max_idx = idx; + } /* end if */ + else + need = heap->obj[idx].size; + + image = begin + need; + } /* end else */ + } /* end while */ + + HDassert(image == heap->chunk + heap->size); + HDassert(H5HG_ISALIGNED(heap->obj[0].size)); + + /* Set the next index value to use */ + if(max_idx > 0) + heap->nused = max_idx + 1; + else + heap->nused = 1; + + HDassert(max_idx < heap->nused); + + /* Add the new heap to the CWFS list for the file */ + if(H5F_cwfs_add(f, heap) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "unable to add global heap collection to file's CWFS") + } /* end if ( len == heap->size ) */ else - heap->nused = 1; - - HDassert(max_idx < heap->nused); - - /* Add the new heap to the CWFS list for the file */ - if(H5F_cwfs_add(f, heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "unable to add global heap collection to file's CWFS") + /* if len is less than heap size, then the initial speculative + * read was too small. In this case we return without reporting + * failure. H5C_load_entry() will call H5HG__cache_heap_image_len() + * to get the actual read size, and then repeat the read with the + * correct size, and call this function a second time. + */ + HDassert(len < heap->size); ret_value = heap; @@ -263,154 +349,126 @@ done: HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy global heap collection") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HG_load() */ +} /* end H5HG__cache_heap_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5HG_flush + * Function: H5HG__cache_heap_image_len * - * Purpose: Flushes a global heap collection from memory to disk if it's - * dirty. Optionally deletes teh heap from memory. + * Purpose: Return the on disk image size of the global heap to the + * metadata cache via the image_len. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Robb Matzke - * Friday, March 27, 1998 + * Programmer: John Mainzer + * 7/27/14 * *------------------------------------------------------------------------- */ static herr_t -H5HG_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HG_heap_t *heap, unsigned H5_ATTR_UNUSED * flags_ptr) +H5HG__cache_heap_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const H5HG_heap_t *heap = (const H5HG_heap_t *)_thing; - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(H5F_addr_eq(addr, heap->addr)); + /* Sanity checks */ HDassert(heap); + HDassert(heap->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(heap->cache_info.type == H5AC_GHEAP); + HDassert(heap->size >= H5HG_MINSIZE); + HDassert(image_len); - if(heap->cache_info.is_dirty) { - if(H5F_block_write(f, H5FD_MEM_GHEAP, addr, heap->size, dxpl_id, heap->chunk) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "unable to write global heap collection to file") - heap->cache_info.is_dirty = FALSE; - } /* end if */ + *image_len = heap->size; - if(destroy) - if(H5HG_dest(f, heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy global heap collection") + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HG__cache_heap_image_len() */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HG_flush() */ +/**************************************/ +/* no H5HG_cache_heap_pre_serialize() */ +/**************************************/ /*------------------------------------------------------------------------- - * Function: H5HG_dest + * Function: H5HG__cache_heap_serialize + * + * Purpose: Given an appropriately sized buffer and an instance of + * H5HG_heap_t, serialize the global heap for writing to file, + * and copy the serialized verion into the buffer. * - * Purpose: Destroys a global heap collection in memory * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * Wednesday, January 15, 2003 + * Programmer: John Mainzer + * 7/27/14 * *------------------------------------------------------------------------- */ static herr_t -H5HG_dest(H5F_t *f, H5HG_heap_t *heap) +H5HG__cache_heap_serialize(const H5F_t *f, void *image, size_t len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HG_heap_t *heap = (H5HG_heap_t *)_thing; - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* Check arguments */ + HDassert(f); + HDassert(image); HDassert(heap); + HDassert(heap->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(heap->cache_info.type == H5AC_GHEAP); + HDassert(heap->size == len); + HDassert(heap->chunk); - /* Verify that node is clean */ - HDassert(heap->cache_info.is_dirty == FALSE); - - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!heap->cache_info.free_file_space_on_destroy || H5F_addr_defined(heap->cache_info.addr)); + /* copy the image into the buffer */ + HDmemcpy(image, heap->chunk, len); - /* Check for freeing file space for globalheap */ - if(heap->cache_info.free_file_space_on_destroy) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_GHEAP, H5AC_dxpl_id, heap->cache_info.addr, (hsize_t)heap->size) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free global heap") - } /* end if */ - - /* Destroy global heap collection */ - if(H5HG_free(heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy global heap collection") + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HG__cache_heap_serialize() */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5HG_dest() */ +/****************************************/ +/* no H5HG_cache_heap_notify() function */ +/****************************************/ /*------------------------------------------------------------------------- - * Function: H5HG_clear + * Function: H5HG__cache_heap_free_icr + * + * Purpose: Free the in memory representation of the supplied global heap. * - * Purpose: Mark a global heap in memory as non-dirty. + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * Thursday, March 20, 2003 + * Programmer: John Mainzer + * 7/27/14 * *------------------------------------------------------------------------- */ static herr_t -H5HG_clear(H5F_t *f, H5HG_heap_t *heap, hbool_t destroy) +H5HG__cache_heap_free_icr(void *_thing) { + H5HG_heap_t *heap = (H5HG_heap_t *)_thing; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Sanity checks */ HDassert(heap); + HDassert(heap->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(heap->cache_info.type == H5AC_GHEAP); - /* Mark heap as clean */ - heap->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5HG_dest(f, heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy global heap collection") + /* Destroy global heap collection */ + if(H5HG_free(heap) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy global heap collection") done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5HG_clear() */ - - -/*------------------------------------------------------------------------- - * Function: H5HG_size - * - * Purpose: Compute the size in bytes of the specified instance of - * H5HG_heap_t on disk, and return it in *len_ptr. On failure, - * the value of *len_ptr is undefined. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: John Mainzer - * 5/13/04 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5HG_size(const H5F_t H5_ATTR_UNUSED *f, const H5HG_heap_t *heap, size_t *size_ptr) -{ - FUNC_ENTER_NOAPI_NOINIT_NOERR - - /* Check arguments */ - HDassert(heap); - HDassert(size_ptr); - - *size_ptr = heap->size; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5HG_size() */ +} /* end H5HG__cache_heap_free_icr() */ diff --git a/src/H5HGdbg.c b/src/H5HGdbg.c index 16d8c49..c79aac8 100644 --- a/src/H5HGdbg.c +++ b/src/H5HGdbg.c @@ -103,7 +103,7 @@ H5HG_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, HDassert(indent >= 0); HDassert(fwidth >= 0); - if(NULL == (h = H5HG_protect(f, dxpl_id, addr, H5AC_READ))) + if(NULL == (h = H5HG_protect(f, dxpl_id, addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap collection"); HDfprintf(stream, "%*sGlobal Heap Collection...\n", indent, ""); diff --git a/src/H5HGpkg.h b/src/H5HGpkg.h index c1ce954..5d00cbd 100644 --- a/src/H5HGpkg.h +++ b/src/H5HGpkg.h @@ -143,7 +143,7 @@ struct H5HG_heap_t { /* Package Private Prototypes */ /******************************/ H5_DLL herr_t H5HG_free(H5HG_heap_t *heap); -H5_DLL H5HG_heap_t *H5HG_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, H5AC_protect_t rw); +H5_DLL H5HG_heap_t *H5HG_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags); #endif /* _H5HGpkg_H */ @@ -322,7 +322,7 @@ END_FUNC(STATIC) /* H5HL__minimize_heap_space() */ */ BEGIN_FUNC(PRIV, ERR, H5HL_t *, NULL, NULL, -H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, H5AC_protect_t rw)) +H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags)) H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */ H5HL_prfx_t *prfx = NULL; /* Local heap prefix */ @@ -335,14 +335,19 @@ H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, H5AC_protect_t rw)) HDassert(f); HDassert(H5F_addr_defined(addr)); + /* only the H5AC__READ_ONLY_FLAG may appear in flags */ + HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Construct the user data for protect callback */ + prfx_udata.made_attempt = FALSE; prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); prfx_udata.prfx_addr = addr; prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); + prfx_udata.loaded = FALSE; /* Protect the local heap prefix */ - if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, rw))) + if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix"); /* Get the pointer to the heap */ @@ -364,7 +369,7 @@ H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, H5AC_protect_t rw)) dblk_udata.loaded = FALSE; /* Protect the local heap data block */ - if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, &dblk_udata, rw))) + if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, &dblk_udata, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to load heap data block"); /* Pin the prefix, if the data block was loaded from file */ @@ -924,13 +929,15 @@ H5HL_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr)) HDassert(H5F_addr_defined(addr)); /* Construct the user data for protect callback */ + prfx_udata.made_attempt = FALSE; prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); prfx_udata.prfx_addr = addr; prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); + prfx_udata.loaded = FALSE; /* Protect the local heap prefix */ - if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC_WRITE))) + if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix"); /* Get the pointer to the heap */ @@ -945,7 +952,7 @@ H5HL_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr)) dblk_udata.loaded = FALSE; /* Protect the local heap data block */ - if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, &dblk_udata, H5AC_WRITE))) + if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, &dblk_udata, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to load heap data block"); /* Pin the prefix, if the data block was loaded from file */ @@ -996,13 +1003,15 @@ H5HL_get_size(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t *size)) HDassert(size); /* Construct the user data for protect callback */ + prfx_udata.made_attempt = FALSE; prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); prfx_udata.prfx_addr = addr; prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); + prfx_udata.loaded = FALSE; /* Protect the local heap prefix */ - if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC_READ))) + if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix"); /* Get the pointer to the heap */ @@ -1045,13 +1054,15 @@ H5HL_heapsize(H5F_t *f, hid_t dxpl_id, haddr_t addr, hsize_t *heap_size)) HDassert(heap_size); /* Construct the user data for protect callback */ + prfx_udata.made_attempt = FALSE; prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); prfx_udata.prfx_addr = addr; prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); + prfx_udata.loaded = FALSE; /* Protect the local heap prefix */ - if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC_READ))) + if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix"); /* Get the pointer to the heap */ diff --git a/src/H5HLcache.c b/src/H5HLcache.c index 74d414a..e3c8ded 100644 --- a/src/H5HLcache.c +++ b/src/H5HLcache.c @@ -71,21 +71,31 @@ /* Metadata cache callbacks */ /* Local heap prefix */ -static H5HL_prfx_t *H5HL__prefix_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5HL__prefix_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, - H5HL_prfx_t *prfx, unsigned *flags_ptr); -static herr_t H5HL__prefix_dest(H5F_t *f, H5HL_prfx_t *prfx); -static herr_t H5HL__prefix_clear(H5F_t *f, H5HL_prfx_t *prfx, hbool_t destroy); -static herr_t H5HL__prefix_size(const H5F_t *f, H5HL_prfx_t *prfx, size_t *size_ptr); +static herr_t H5HL__cache_prefix_get_load_size(const void *_image, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static void *H5HL__cache_prefix_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5HL__cache_prefix_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5HL__cache_prefix_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5HL__cache_prefix_free_icr(void *thing); /* Local heap data block */ -static H5HL_dblk_t *H5HL__datablock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5HL__datablock_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, - H5HL_dblk_t *dblk, unsigned *flags_ptr); -static herr_t H5HL__datablock_dest(H5F_t *f, H5HL_dblk_t *dblk); -static herr_t H5HL__datablock_clear(H5F_t *f, H5HL_dblk_t *dblk, hbool_t destroy); -static herr_t H5HL__datablock_notify(H5AC_notify_action_t action, H5HL_dblk_t *dblk); -static herr_t H5HL__datablock_size(const H5F_t *f, H5HL_dblk_t *dblk, size_t *size_ptr); +static herr_t H5HL__cache_datablock_get_load_size(const void *_image, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static void *H5HL__cache_datablock_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5HL__cache_datablock_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5HL__cache_datablock_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5HL__cache_datablock_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5HL__cache_datablock_free_icr(void *thing); /* Free list de/serialization */ static herr_t H5HL__fl_deserialize(H5HL_t *heap); @@ -97,23 +107,37 @@ static void H5HL__fl_serialize(const H5HL_t *heap); /* H5HL inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_LHEAP_PRFX[1] = {{ - H5AC_LHEAP_PRFX_ID, - (H5AC_load_func_t) H5HL__prefix_load, - (H5AC_flush_func_t) H5HL__prefix_flush, - (H5AC_dest_func_t) H5HL__prefix_dest, - (H5AC_clear_func_t) H5HL__prefix_clear, - (H5AC_notify_func_t) NULL, - (H5AC_size_func_t) H5HL__prefix_size, + H5AC_LHEAP_PRFX_ID, /* Metadata client ID */ + "local heap prefix", /* Metadata client name (for debugging) */ + H5FD_MEM_LHEAP, /* File space memory type for client */ + H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ + H5HL__cache_prefix_get_load_size, /* 'get_load_size' callback */ + NULL, /* 'verify_chksum' callback */ + H5HL__cache_prefix_deserialize, /* 'deserialize' callback */ + H5HL__cache_prefix_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5HL__cache_prefix_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5HL__cache_prefix_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; const H5AC_class_t H5AC_LHEAP_DBLK[1] = {{ - H5AC_LHEAP_DBLK_ID, - (H5AC_load_func_t) H5HL__datablock_load, - (H5AC_flush_func_t) H5HL__datablock_flush, - (H5AC_dest_func_t) H5HL__datablock_dest, - (H5AC_clear_func_t) H5HL__datablock_clear, - (H5AC_notify_func_t) H5HL__datablock_notify, - (H5AC_size_func_t) H5HL__datablock_size, + H5AC_LHEAP_DBLK_ID, /* Metadata client ID */ + "local heap datablock", /* Metadata client name (for debugging) */ + H5FD_MEM_LHEAP, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5HL__cache_datablock_get_load_size,/* 'get_load_size' callback */ + NULL, /* 'verify_chksum' callback */ + H5HL__cache_datablock_deserialize, /* 'deserialize' callback */ + H5HL__cache_datablock_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5HL__cache_datablock_serialize, /* 'serialize' callback */ + H5HL__cache_datablock_notify, /* 'notify' callback */ + H5HL__cache_datablock_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -153,7 +177,7 @@ H5HL__fl_deserialize(H5HL_t *heap)) /* Build free list */ free_block = heap->free_block; while(H5HL_FREE_NULL != free_block) { - const uint8_t *p; /* Pointer into image buffer */ + const uint8_t *image; /* Pointer into image buffer */ /* Sanity check */ if(free_block >= heap->dblk_size) @@ -167,13 +191,13 @@ H5HL__fl_deserialize(H5HL_t *heap)) fl->next = NULL; /* Decode offset of next free block */ - p = heap->dblk_image + free_block; - H5F_DECODE_LENGTH_LEN(p, free_block, heap->sizeof_size); + image = heap->dblk_image + free_block; + H5F_DECODE_LENGTH_LEN(image, free_block, heap->sizeof_size); if(0 == free_block) H5E_THROW(H5E_BADVALUE, "free block size is zero?"); /* Decode length of this free block */ - H5F_DECODE_LENGTH_LEN(p, fl->size, heap->sizeof_size); + H5F_DECODE_LENGTH_LEN(image, fl->size, heap->sizeof_size); if((fl->offset + fl->size) > heap->dblk_size) H5E_THROW(H5E_BADRANGE, "bad heap free list"); @@ -217,105 +241,180 @@ H5HL__fl_serialize(const H5HL_t *heap)) /* Serialize the free list into the heap data's image */ for(fl = heap->freelist; fl; fl = fl->next) { - uint8_t *p; /* Pointer into raw data buffer */ + uint8_t *image; /* Pointer into raw data buffer */ HDassert(fl->offset == H5HL_ALIGN(fl->offset)); - p = heap->dblk_image + fl->offset; + image = heap->dblk_image + fl->offset; if(fl->next) - H5F_ENCODE_LENGTH_LEN(p, fl->next->offset, heap->sizeof_size) + H5F_ENCODE_LENGTH_LEN(image, fl->next->offset, heap->sizeof_size) else - H5F_ENCODE_LENGTH_LEN(p, H5HL_FREE_NULL, heap->sizeof_size) + H5F_ENCODE_LENGTH_LEN(image, H5HL_FREE_NULL, heap->sizeof_size) - H5F_ENCODE_LENGTH_LEN(p, fl->size, heap->sizeof_size) + H5F_ENCODE_LENGTH_LEN(image, fl->size, heap->sizeof_size) } /* end for */ END_FUNC_VOID(STATIC) /* end H5HL__fl_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HL__prefix_load + * Function: H5HL__cache_prefix_get_load_size() * - * Purpose: Loads a local heap prefix from disk. + * Purpose: Return the size of the buffer the metadata cache should + * load from file and pass to the deserialize routine. * - * Return: Success: Pointer to a local heap prefix structure. - * Failure: NULL + * The version 2 metadata cache callbacks included a test to + * ensure that the read did not pass the end of file, but this + * functionality has been moved to H5C_load_entry(). Thus + * all this function does is set *image_len equal to + * H5HL_SPEC_READ_SIZE, leaving it to the metadata cache to + * reduce the size of the read if appropriate. * - * Programmer: Robb Matzke - * Jul 17 1997 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -H5HL_prfx_t *, NULL, NULL, -H5HL__prefix_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) - - H5HL_t *heap = NULL; /* Local heap */ - H5HL_prfx_t *prfx = NULL; /* Heap prefix deserialized */ - H5HL_cache_prfx_ud_t *udata = (H5HL_cache_prfx_ud_t *)_udata; /* User data for callback */ - uint8_t buf[H5HL_SPEC_READ_SIZE]; /* Buffer for decoding */ - size_t spec_read_size; /* Size of buffer to speculatively read in */ - const uint8_t *p; /* Pointer into decoding buffer */ - haddr_t eoa; /* Relative end of file address */ - hsize_t min; /* temp min value to avoid macro nesting */ +static herr_t +H5HL__cache_prefix_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5HL_cache_prfx_ud_t *udata = (H5HL_cache_prfx_ud_t *)_udata; /* User data for callback */ + H5HL_t heap; /* Local heap */ + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); HDassert(udata); - HDassert(udata->sizeof_size > 0); - HDassert(udata->sizeof_addr > 0); - HDassert(udata->sizeof_prfx > 0); - HDassert(udata->sizeof_prfx <= sizeof(buf)); + HDassert(image_len); + + if(image == NULL) + *image_len = H5HL_SPEC_READ_SIZE; + + else { /* compute actual_len */ + + HDassert(actual_len); + HDassert(*actual_len == *image_len); + + /* Check magic number */ + if(HDmemcmp(image, H5HL_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "bad local heap signature") + image += H5_SIZEOF_MAGIC; + + /* Version */ + if(H5HL_VERSION != *image++) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "wrong version number in local heap") + + /* Reserved */ + image += 3; + + /* Store the prefix's address & length */ + heap.prfx_addr = udata->prfx_addr; /* NEED */ + heap.prfx_size = udata->sizeof_prfx; /* NEED */ + + /* Heap data size */ + H5F_DECODE_LENGTH_LEN(image, heap.dblk_size, udata->sizeof_size); /* NEED */ + + /* Free list head */ + H5F_DECODE_LENGTH_LEN(image, heap.free_block, udata->sizeof_size); + if(heap.free_block != H5HL_FREE_NULL && heap.free_block >= heap.dblk_size) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "bad heap free list"); + + /* Heap data address */ + H5F_addr_decode_len(udata->sizeof_addr, &image, &(heap.dblk_addr)); /* NEED */ + + *actual_len = heap.prfx_size; + + /* Check if heap block exists */ + if(heap.dblk_size) { + /* Check if heap data block is contiguous with header */ + if(H5F_addr_eq((heap.prfx_addr + heap.prfx_size), heap.dblk_addr)) { + /* Note that the heap should be a single object in the cache */ + *actual_len += heap.dblk_size; + } + } /* end if */ + } /* end compute actual_len */ - /* Make certain we don't speculatively read off the end of the file */ - if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_LHEAP))) - H5E_THROW(H5E_CANTGET, "unable to determine file size"); +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL__cache_prefix_get_load_size() */ - /* Compute the size of the speculative local heap prefix buffer */ - min = MIN(eoa - addr, H5HL_SPEC_READ_SIZE); - H5_CHECKED_ASSIGN(spec_read_size, size_t, min, hsize_t); - HDassert(spec_read_size >= udata->sizeof_prfx); + +/*------------------------------------------------------------------------- + * Function: H5HL__cache_prefix_deserialize + * + * Purpose: Given a buffer containing the on disk image of the local + * heap prefix, deserialize it, load its contents into a newly allocated + * instance of H5HL_prfx_t, and return a pointer to the new instance. + * + * Return: Success: Pointer to in core representation + * Failure: NULL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static void * +H5HL__cache_prefix_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) +{ + H5HL_t *heap = NULL; /* Local heap */ + H5HL_prfx_t *prfx = NULL; /* Heap prefix deserialized */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into decoding buffer */ + H5HL_cache_prfx_ud_t *udata = (H5HL_cache_prfx_ud_t *)_udata; /* User data for callback */ + void *ret_value; /* Return value */ + + FUNC_ENTER_STATIC - /* Attempt to speculatively read both local heap prefix and heap data */ - if(FAIL == H5F_block_read(f, H5FD_MEM_LHEAP, addr, spec_read_size, dxpl_id, buf)) - H5E_THROW(H5E_READERROR, "unable to read local heap prefix"); - p = buf; + /* Check arguments */ + HDassert(image); + HDassert(len > 0); + HDassert(udata); + HDassert(udata->sizeof_size > 0); + HDassert(udata->sizeof_addr > 0); + HDassert(udata->sizeof_prfx > 0); + HDassert(H5F_addr_defined(udata->prfx_addr)); + HDassert(dirty); /* Check magic number */ - if(HDmemcmp(p, H5HL_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - H5E_THROW(H5E_BADVALUE, "bad local heap signature"); - p += H5_SIZEOF_MAGIC; + if(HDmemcmp(image, H5HL_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "bad local heap signature") + image += H5_SIZEOF_MAGIC; /* Version */ - if(H5HL_VERSION != *p++) - H5E_THROW(H5E_BADVALUE, "wrong version number in local heap"); + if(H5HL_VERSION != *image++) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "wrong version number in local heap") /* Reserved */ - p += 3; - + image += 3; + /* Allocate space in memory for the heap */ if(NULL == (heap = H5HL__new(udata->sizeof_size, udata->sizeof_addr, udata->sizeof_prfx))) - H5E_THROW(H5E_CANTALLOC, "can't allocate local heap structure"); + HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "can't allocate local heap structure"); /* Allocate the heap prefix */ if(NULL == (prfx = H5HL__prfx_new(heap))) - H5E_THROW(H5E_CANTALLOC, "can't allocate local heap prefix"); + HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "can't allocate local heap prefix"); /* Store the prefix's address & length */ heap->prfx_addr = udata->prfx_addr; heap->prfx_size = udata->sizeof_prfx; /* Heap data size */ - H5F_DECODE_LENGTH_LEN(p, heap->dblk_size, udata->sizeof_size); + H5F_DECODE_LENGTH_LEN(image, heap->dblk_size, udata->sizeof_size); /* Free list head */ - H5F_DECODE_LENGTH_LEN(p, heap->free_block, udata->sizeof_size); + H5F_DECODE_LENGTH_LEN(image, heap->free_block, udata->sizeof_size); if(heap->free_block != H5HL_FREE_NULL && heap->free_block >= heap->dblk_size) - H5E_THROW(H5E_BADVALUE, "bad heap free list"); + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "bad heap free list"); /* Heap data address */ - H5F_addr_decode_len(udata->sizeof_addr, &p, &(heap->dblk_addr)); + H5F_addr_decode_len(udata->sizeof_addr, &image, &(heap->dblk_addr)); /* Check if heap block exists */ if(heap->dblk_size) { @@ -324,318 +423,345 @@ H5HL__prefix_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) /* Note that the heap should be a single object in the cache */ heap->single_cache_obj = TRUE; - /* Allocate space for the heap data image */ - if(NULL == (heap->dblk_image = H5FL_BLK_MALLOC(lheap_chunk, heap->dblk_size))) - H5E_THROW(H5E_CANTALLOC, "memory allocation failed"); + /* Check if the current buffer from the speculative read + * already has the heap data + */ + if(len >= (heap->prfx_size + heap->dblk_size)) { + /* Allocate space for the heap data image */ + if(NULL == (heap->dblk_image = H5FL_BLK_MALLOC(lheap_chunk, heap->dblk_size))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed") - /* Check if the current buffer from the speculative read already has the heap data */ - if(spec_read_size >= (heap->prfx_size + heap->dblk_size)) { - /* Set p to the start of the data block. This is necessary + /* Set image to the start of the data block. This is necessary * because there may be a gap between the used portion of the * prefix and the data block due to alignment constraints. */ - p = buf + heap->prfx_size; + image = ((const uint8_t *)_image) + heap->prfx_size; /* Copy the heap data from the speculative read buffer */ - HDmemcpy(heap->dblk_image, p, heap->dblk_size); + HDmemcpy(heap->dblk_image, image, heap->dblk_size); + + /* Build free list */ + if(H5HL__fl_deserialize(heap) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't initialize free list") } /* end if */ else { - /* Read the local heap data block directly into buffer */ - if(FAIL == H5F_block_read(f, H5FD_MEM_LHEAP, heap->dblk_addr, heap->dblk_size, dxpl_id, heap->dblk_image)) - H5E_THROW(H5E_READERROR, "unable to read heap data"); - } /* end else */ - - /* Build free list */ - if(FAIL == H5HL__fl_deserialize(heap)) - H5E_THROW(H5E_CANTINIT, "can't initialize free list"); + /* the supplied buffer is too small -- We have already made note + * of the correct size, so simply return success. H5C_load_entry() + * will notice the size discrepency, and re-try the load. + */ + + /* Make certain that this is the first try ... */ + HDassert(!udata->made_attempt); + + /* ... and mark the udata so that we know that we have used up + * our first try. + */ + udata->made_attempt = TRUE; + } /* end else */ } /* end if */ - else - /* Note that the heap should _NOT_ be a single object in the cache */ + else { + /* Note that the heap should _NOT_ be a single + * object in the cache + */ heap->single_cache_obj = FALSE; + + } /* end else */ } /* end if */ + /* Set flag to indicate prefix from loaded from file */ + udata->loaded = TRUE; + /* Set return value */ ret_value = prfx; -CATCH +done: /* Release the [possibly partially initialized] local heap on errors */ if(!ret_value) { if(prfx) { if(FAIL == H5HL__prfx_dest(prfx)) - H5E_THROW(H5E_CANTRELEASE, "unable to destroy local heap prefix"); + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "unable to destroy local heap prefix"); } /* end if */ else { if(heap && FAIL == H5HL__dest(heap)) - H5E_THROW(H5E_CANTRELEASE, "unable to destroy local heap"); + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "unable to destroy local heap"); } /* end else */ } /* end if */ -END_FUNC(STATIC) /* end H5HL__prefix_load() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL__cache_prefix_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5HL__prefix_flush + * Function: H5HL__cache_prefix_image_len * - * Purpose: Flushes a heap from memory to disk if it's dirty. Optionally - * deletes the heap from memory. + * Purpose: Return the on disk image size of a local heap prefix to the + * metadata cache via the image_len. * - * Return: SUCCEED/FAIL + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Robb Matzke - * Jul 17 1997 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5HL__prefix_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5HL_prfx_t *prfx, unsigned H5_ATTR_UNUSED *flags_ptr)) +static herr_t +H5HL__cache_prefix_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const H5HL_prfx_t *prfx = (const H5HL_prfx_t *)_thing; /* Pointer to local heap prefix to query */ - H5WB_t *wb = NULL; /* Wrapped buffer for heap data */ - uint8_t heap_buf[H5HL_SPEC_READ_SIZE]; /* Buffer for heap */ + FUNC_ENTER_STATIC_NOERR - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(prfx); + HDassert(prfx->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(prfx->cache_info.type == H5AC_LHEAP_PRFX); + HDassert(image_len); - if(prfx->cache_info.is_dirty) { - H5HL_t *heap = prfx->heap; /* Pointer to the local heap */ - uint8_t *buf; /* Pointer to heap buffer */ - size_t buf_size; /* Size of buffer for encoding & writing heap info */ - uint8_t *p; /* Pointer into raw data buffer */ - - /* Wrap the local buffer for serialized heap info */ - if(NULL == (wb = H5WB_wrap(heap_buf, sizeof(heap_buf)))) - H5E_THROW(H5E_CANTINIT, "can't wrap buffer"); - - - /* Compute the size of the buffer to encode & write */ - buf_size = heap->prfx_size; - if(heap->single_cache_obj) - buf_size += heap->dblk_size; - - /* Get a pointer to a buffer that's large enough for serialized heap */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, buf_size))) - H5E_THROW(H5E_NOSPACE, "can't get actual buffer"); - - /* Update the free block value from the free list */ - heap->free_block = heap->freelist ? heap->freelist->offset : H5HL_FREE_NULL; - - /* Serialize the heap prefix */ - p = buf; - HDmemcpy(p, H5HL_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - *p++ = H5HL_VERSION; - *p++ = 0; /*reserved*/ - *p++ = 0; /*reserved*/ - *p++ = 0; /*reserved*/ - H5F_ENCODE_LENGTH_LEN(p, heap->dblk_size, heap->sizeof_size); - H5F_ENCODE_LENGTH_LEN(p, heap->free_block, heap->sizeof_size); - H5F_addr_encode_len(heap->sizeof_addr, &p, heap->dblk_addr); - - /* Check if the local heap is a single object in cache */ - if(heap->single_cache_obj) { - if((size_t)(p - buf) < heap->prfx_size) { - size_t gap; /* Size of gap between prefix and data block */ - - /* Set p to the start of the data block. This is necessary because - * there may be a gap between the used portion of the prefix and the - * data block due to alignment constraints. */ - gap = heap->prfx_size - (size_t)(p - buf); - HDmemset(p, 0, gap); - p += gap; - } /* end if */ - - /* Serialize the free list into the heap data's image */ - H5HL__fl_serialize(heap); + /* Set the prefix's size */ + *image_len = prfx->heap->prfx_size; - /* Copy the heap data block into the cache image */ - HDmemcpy(p, heap->dblk_image, heap->dblk_size); - } /* end if */ - - /* Write the prefix [and possibly the data block] to the file */ - if(FAIL == H5F_block_write(f, H5FD_MEM_LHEAP, addr, buf_size, dxpl_id, buf)) - H5E_THROW(H5E_WRITEERROR, "unable to write heap header and data to file"); - - prfx->cache_info.is_dirty = FALSE; - } /* end if */ - - /* Should we destroy the memory version? */ - if(destroy) - if(FAIL == H5HL__prefix_dest(f, prfx)) - H5E_THROW(H5E_CANTFREE, "unable to destroy local heap prefix"); + /* If the heap is stored as a single object, add in the + * data block size also + */ + if(prfx->heap->single_cache_obj) + *image_len += prfx->heap->dblk_size; -CATCH - /* Release resources */ - if(wb && FAIL == H5WB_unwrap(wb)) - H5E_THROW(H5E_CLOSEERROR, "can't close wrapped buffer"); + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HL__cache_prefix_image_len() */ -END_FUNC(STATIC) /* end H5HL__prefix_flush() */ +/****************************************/ +/* no H5HL_cache_prefix_pre_serialize() */ +/****************************************/ /*------------------------------------------------------------------------- - * Function: H5HL__prefix_dest + * Function: H5HL__cache_prefix_serialize * - * Purpose: Destroys a heap prefix in memory. + * Purpose: Given a pointer to an instance of H5HL_prfx_t and an + * appropriately sized buffer, serialize the contents of the + * instance for writing to disk, and copy the serialized data + * into the buffer. * - * Return: SUCCEED/FAIL + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * Jan 15 2003 + * Programmer: John Mainzer + * 7/21/14 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5HL__prefix_dest(H5F_t *f, H5HL_prfx_t *prfx)) +static herr_t +H5HL__cache_prefix_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) +{ + H5HL_prfx_t *prfx = (H5HL_prfx_t *)_thing; /* Pointer to local heap prefix to query */ + H5HL_t *heap; /* Pointer to the local heap */ + uint8_t *image = (uint8_t *)_image; /* Pointer into image buffer */ + size_t buf_size; /* expected size of the image buffer */ - /* check arguments */ + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(f); + HDassert(image); HDassert(prfx); - HDassert(prfx->heap); + HDassert(prfx->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(prfx->cache_info.type == H5AC_LHEAP_PRFX); HDassert(H5F_addr_eq(prfx->cache_info.addr, prfx->heap->prfx_addr)); + HDassert(prfx->heap); - /* Verify that entry is clean */ - HDassert(prfx->cache_info.is_dirty == FALSE); - - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!prfx->cache_info.free_file_space_on_destroy || H5F_addr_defined(prfx->cache_info.addr)); + /* Get the pointer to the heap */ + heap = prfx->heap; + HDassert(heap); - /* Check for freeing file space for local heap prefix */ - if(prfx->cache_info.free_file_space_on_destroy) { - hsize_t free_size; /* Size of region to free in file */ + /* Compute the buffer size */ + buf_size = heap->prfx_size; + if(heap->single_cache_obj) + buf_size += heap->dblk_size; + HDassert(len == buf_size); + + /* Update the free block value from the free list */ + heap->free_block = heap->freelist ? heap->freelist->offset : H5HL_FREE_NULL; + + /* Serialize the heap prefix */ + HDmemcpy(image, H5HL_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; + *image++ = H5HL_VERSION; + *image++ = 0; /*reserved*/ + *image++ = 0; /*reserved*/ + *image++ = 0; /*reserved*/ + H5F_ENCODE_LENGTH_LEN(image, heap->dblk_size, heap->sizeof_size); + H5F_ENCODE_LENGTH_LEN(image, heap->free_block, heap->sizeof_size); + H5F_addr_encode_len(heap->sizeof_addr, &image, heap->dblk_addr); + + /* Check if the local heap is a single object in cache */ + if(heap->single_cache_obj) { + if((size_t)(image - (uint8_t *)_image) < heap->prfx_size) { + size_t gap; /* Size of gap between prefix and data block */ + + /* Set image to the start of the data block. This is necessary + * because there may be a gap between the used portion of + * the prefix and the data block due to alignment constraints. + */ + gap = heap->prfx_size - (size_t)(image - (uint8_t *)_image); + HDmemset(image, 0, gap); + image += gap; + } /* end if */ - /* Compute size to free for later */ - free_size = prfx->heap->prfx_size; - if(prfx->heap->single_cache_obj) - free_size += prfx->heap->dblk_size; + /* Serialize the free list into the heap data's image */ + H5HL__fl_serialize(heap); - /* Free the local heap prefix [and possible the data block] on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(FAIL == H5MF_xfree(f, H5FD_MEM_LHEAP, H5AC_dxpl_id, prfx->cache_info.addr, free_size)) - H5E_THROW(H5E_CANTFREE, "unable to free local heap prefix"); + /* Copy the heap data block into the cache image */ + HDmemcpy(image, heap->dblk_image, heap->dblk_size); } /* end if */ - /* Destroy local heap prefix */ - if(FAIL == H5HL__prfx_dest(prfx)) - H5E_THROW(H5E_CANTRELEASE, "can't destroy local heap prefix"); + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HL__cache_prefix_serialize() */ -CATCH - /* No special processing on errors */ - -END_FUNC(STATIC) /* end H5HL__prefix_dest() */ +/******************************************/ +/* no H5HL_cache_prefix_notify() function */ +/******************************************/ /*------------------------------------------------------------------------- - * Function: H5HL__prefix_clear + * Function: H5HL__cache_prefix_free_icr * - * Purpose: Mark a local heap prefix in memory as non-dirty. + * Purpose: Free the supplied in core representation of a local heap + * prefix. * - * Return: SUCCEED/FAIL + * Note that this function handles the partially initialize prefix + * from a failed speculative load attempt. See comments below for + * details. * - * Programmer: Quincey Koziol - * Mar 20 2003 + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5HL__prefix_clear(H5F_t H5_ATTR_UNUSED *f, H5HL_prfx_t *prfx, hbool_t destroy)) +static herr_t +H5HL__cache_prefix_free_icr(void *_thing) +{ + H5HL_prfx_t *prfx = (H5HL_prfx_t *)_thing; /* Pointer to local heap prefix to query */ + herr_t ret_value = SUCCEED; /* Return value */ - /* check arguments */ - HDassert(prfx); + FUNC_ENTER_STATIC - /* Mark heap prefix as clean */ - prfx->cache_info.is_dirty = FALSE; + /* Check arguments */ + HDassert(prfx); + HDassert(prfx->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(prfx->cache_info.type == H5AC_LHEAP_PRFX); + HDassert(H5F_addr_eq(prfx->cache_info.addr, prfx->heap->prfx_addr)); - if(destroy) - if(FAIL == H5HL__prefix_dest(f, prfx)) - H5E_THROW(H5E_CANTFREE, "unable to destroy local heap prefix"); - -CATCH - /* No special processing on errors */ + /* Destroy local heap prefix */ + if(H5HL__prfx_dest(prfx) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't destroy local heap prefix") -END_FUNC(STATIC) /* end H5HL__prefix_clear() */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL__cache_prefix_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5HL__prefix_size + * Function: H5HL__cache_datablock_get_load_size() * - * Purpose: Compute the size in bytes of the heap prefix on disk, - * and return it in *len_ptr. On failure, the value of *len_ptr - * is undefined. + * Purpose: Tell the metadata cache how large a buffer to read from + * file when loading a datablock. In this case, we simply lookup + * the correct value in the user data, and return it in *image_len. * - * Return: SUCCEED (Can't fail) + * Return: Success: SUCCEED + * Failure: FAIL * * Programmer: John Mainzer - * 5/13/04 + * 6/21/14 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, NOERR, -herr_t, SUCCEED, -, -H5HL__prefix_size(const H5F_t H5_ATTR_UNUSED *f, H5HL_prfx_t *prfx, size_t *size_ptr)) +static herr_t +H5HL__cache_datablock_get_load_size(const void *_image, void *_udata, + size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into image buffer */ + H5HL_cache_dblk_ud_t *udata = (H5HL_cache_dblk_ud_t *)_udata; /* User data for callback */ - /* check arguments */ - HDassert(prfx); - HDassert(prfx->heap); - HDassert(size_ptr); + FUNC_ENTER_STATIC_NOERR - /* Calculate size of prefix in cache */ - *size_ptr = prfx->heap->prfx_size; + /* Check arguments */ + HDassert(udata); + HDassert(udata->heap); + HDassert(udata->heap->dblk_size > 0); + HDassert(image_len); - /* If the heap is stored as a single object, add in the data block size also */ - if(prfx->heap->single_cache_obj) - *size_ptr += prfx->heap->dblk_size; + if(image == NULL) + *image_len = udata->heap->dblk_size; + else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } -END_FUNC(STATIC) /* H5HL__prefix_size() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HL__cache_datablock_get_load_size() */ /*------------------------------------------------------------------------- - * Function: H5HL__datablock_load + * Function: H5HL__cache_datablock_deserialize * - * Purpose: Loads a local heap data block from disk. + * Purpose: Given a buffer containing the on disk image of a local + * heap data block, deserialize it, load its contents into a newly allocated + * instance of H5HL_dblk_t, and return a pointer to the new instance. * - * Return: Success: Pointer to a local heap data block memory data - * structure. - * Failure: NULL + * Return: Success: Pointer to in core representation + * Failure: NULL * - * Programmer: Quincey Koziol - * Jan 5 2010 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -H5HL_dblk_t *, NULL, NULL, -H5HL__datablock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) +static void * +H5HL__cache_datablock_deserialize(const void *image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) +{ + H5HL_dblk_t *dblk = NULL; /* Local heap data block deserialized */ + H5HL_cache_dblk_ud_t *udata = (H5HL_cache_dblk_ud_t *)_udata; /* User data for callback */ + void * ret_value; /* Return value */ - H5HL_dblk_t *dblk = NULL; /* Local heap data block deserialized */ - H5HL_cache_dblk_ud_t *udata = (H5HL_cache_dblk_ud_t *)_udata; /* User data for callback */ + FUNC_ENTER_STATIC /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(image); + HDassert(len > 0); HDassert(udata); HDassert(udata->heap); + HDassert(udata->heap->dblk_size == len); HDassert(!udata->heap->single_cache_obj); HDassert(NULL == udata->heap->dblk); + HDassert(dirty); /* Allocate space in memory for the heap data block */ if(NULL == (dblk = H5HL__dblk_new(udata->heap))) - H5E_THROW(H5E_CANTALLOC, "memory allocation failed"); + HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed"); /* Check for heap still retaining image */ if(NULL == udata->heap->dblk_image) { /* Allocate space for the heap data image */ if(NULL == (udata->heap->dblk_image = H5FL_BLK_MALLOC(lheap_chunk, udata->heap->dblk_size))) - H5E_THROW(H5E_CANTALLOC, "can't allocate data block image buffer"); + HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "can't allocate data block image buffer"); - /* Read local heap data block */ - if(FAIL == H5F_block_read(f, H5FD_MEM_LHEAP, udata->heap->dblk_addr, udata->heap->dblk_size, dxpl_id, udata->heap->dblk_image)) - H5E_THROW(H5E_READERROR, "unable to read local heap data block"); + /* copy the datablock from the read buffer */ + HDmemcpy(udata->heap->dblk_image, image, len); /* Build free list */ if(FAIL == H5HL__fl_deserialize(udata->heap)) - H5E_THROW(H5E_CANTINIT, "can't initialize free list"); + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't initialize free list"); } /* end if */ /* Set flag to indicate data block from loaded from file */ @@ -644,146 +770,104 @@ H5HL__datablock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata)) /* Set return value */ ret_value = dblk; -CATCH +done: /* Release the [possibly partially initialized] local heap on errors */ if(!ret_value && dblk) if(FAIL == H5HL__dblk_dest(dblk)) - H5E_THROW(H5E_CANTRELEASE, "unable to destroy local heap data block"); + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "unable to destroy local heap data block"); -END_FUNC(STATIC) /* end H5HL__datablock_load() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL__cache_datablock_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5HL__datablock_flush + * Function: H5HL__cache_datablock_image_len * - * Purpose: Flushes a heap's data block from memory to disk if it's dirty. - * Optionally deletes the heap data block from memory. + * Purpose: Return the size of the on disk image of the datablock. * - * Return: SUCCEED/FAIL + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Robb Matzke - * Jul 17 1997 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5HL__datablock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5HL_dblk_t *dblk, unsigned H5_ATTR_UNUSED * flags_ptr)) +static herr_t +H5HL__cache_datablock_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const H5HL_dblk_t *dblk = (const H5HL_dblk_t *)_thing; /* Pointer to the local heap data block */ - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(dblk); - HDassert(dblk->heap); - HDassert(!dblk->heap->single_cache_obj); - - if(dblk->cache_info.is_dirty) { - H5HL_t *heap = dblk->heap; /* Pointer to the local heap */ - - /* Update the free block value from the free list */ - heap->free_block = heap->freelist ? heap->freelist->offset : H5HL_FREE_NULL; - - /* Serialize the free list into the heap data's image */ - H5HL__fl_serialize(heap); - - /* Write the data block to the file */ - if(FAIL == H5F_block_write(f, H5FD_MEM_LHEAP, heap->dblk_addr, heap->dblk_size, dxpl_id, heap->dblk_image)) - H5E_THROW(H5E_WRITEERROR, "unable to write heap data block to file"); - - dblk->cache_info.is_dirty = FALSE; - } /* end if */ - - /* Should we destroy the memory version? */ - if(destroy) - if(FAIL == H5HL__datablock_dest(f, dblk)) - H5E_THROW(H5E_CANTFREE, "unable to destroy local heap data block"); - -CATCH - /* No special processing on errors */ - -END_FUNC(STATIC) /* end H5HL__datablock_flush() */ - - -/*------------------------------------------------------------------------- - * Function: H5HL__datablock_dest - * - * Purpose: Destroys a local heap data block in memory. - * - * Return: SUCCEED/FAIL - * - * Programmer: Quincey Koziol - * Jan 15 2003 - * - *------------------------------------------------------------------------- - */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5HL__datablock_dest(H5F_t *f, H5HL_dblk_t *dblk)) + FUNC_ENTER_STATIC_NOERR /* Check arguments */ HDassert(dblk); + HDassert(dblk->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblk->cache_info.type == H5AC_LHEAP_DBLK); HDassert(dblk->heap); - HDassert(!dblk->heap->single_cache_obj); - HDassert(H5F_addr_eq(dblk->cache_info.addr, dblk->heap->dblk_addr)); + HDassert(dblk->heap->dblk_size > 0); + HDassert(image_len); - /* Verify that entry is clean */ - HDassert(dblk->cache_info.is_dirty == FALSE); + *image_len = dblk->heap->dblk_size; - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!dblk->cache_info.free_file_space_on_destroy || H5F_addr_defined(dblk->cache_info.addr)); + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HL__cache_datablock_image_len() */ - /* Check for freeing file space for local heap data block */ - if(dblk->cache_info.free_file_space_on_destroy) { - /* Free the local heap data block on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(FAIL == H5MF_xfree(f, H5FD_MEM_LHEAP, H5AC_dxpl_id, dblk->cache_info.addr, (hsize_t)dblk->heap->dblk_size)) - H5E_THROW(H5E_CANTFREE, "unable to free local heap data block"); - } /* end if */ - - /* Destroy local heap data block */ - if(FAIL == H5HL__dblk_dest(dblk)) - H5E_THROW(H5E_CANTRELEASE, "can't destroy local heap data block"); - -CATCH - /* No special processing on errors */ - -END_FUNC(STATIC) /* end H5HL__datablock_dest() */ +/*******************************************/ +/* no H5HL_cache_datablock_pre_serialize() */ +/*******************************************/ /*------------------------------------------------------------------------- - * Function: H5HL__datablock_clear + * Function: H5HL__cache_datablock_serialize * - * Purpose: Mark a local heap data block in memory as non-dirty. + * Purpose: Serialize the supplied datablock, and copy the serialized + * image into the supplied image buffer. * - * Return: SUCCEED/FAIL + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * Mar 20 2003 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, ERR, -herr_t, SUCCEED, FAIL, -H5HL__datablock_clear(H5F_t *f, H5HL_dblk_t *dblk, hbool_t destroy)) +static herr_t +H5HL__cache_datablock_serialize(const H5F_t *f, void *image, size_t len, + void *_thing) +{ + H5HL_t *heap; /* Pointer to the local heap */ + H5HL_dblk_t *dblk = (H5HL_dblk_t *)_thing; /* Pointer to the local heap data block */ + + FUNC_ENTER_STATIC_NOERR /* Check arguments */ + HDassert(f); + HDassert(image); HDassert(dblk); + HDassert(dblk->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblk->cache_info.type == H5AC_LHEAP_DBLK); + HDassert(dblk->heap); + heap = dblk->heap; + HDassert(heap->dblk_size == len); + HDassert(!heap->single_cache_obj); - /* Mark local heap data block as clean */ - dblk->cache_info.is_dirty = FALSE; + /* Update the free block value from the free list */ + heap->free_block = heap->freelist ? heap->freelist->offset : H5HL_FREE_NULL; - if(destroy) - if(FAIL == H5HL__datablock_dest(f, dblk)) - H5E_THROW(H5E_CANTFREE, "unable to destroy local heap data block"); + /* Serialize the free list into the heap data's image */ + H5HL__fl_serialize(heap); -CATCH + /* Copy the heap's data block into the cache's image */ + HDmemcpy(image, heap->dblk_image, heap->dblk_size); -END_FUNC(STATIC) /* end H5HL__datablock_clear() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HL__cache_datablock_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HL__datablock_notify + * Function: H5HL__cache_datablock_notify * * Purpose: Handle cache action notifications * @@ -796,8 +880,11 @@ END_FUNC(STATIC) /* end H5HL__datablock_clear() */ */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, -H5HL__datablock_notify(H5AC_notify_action_t action, H5HL_dblk_t *dblk)) +H5HL__cache_datablock_notify(H5AC_notify_action_t action, void *_thing)) + /* Local variables */ + H5HL_dblk_t *dblk = (H5HL_dblk_t *)_thing; + /* Sanity check */ HDassert(dblk); @@ -806,13 +893,20 @@ H5HL__datablock_notify(H5AC_notify_action_t action, H5HL_dblk_t *dblk)) /* Determine which action to take */ switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: /* Create flush dependency on parent */ if(FAIL == H5HL__create_flush_depend((H5AC_info_t *)dblk->heap->prfx, (H5AC_info_t *)dblk)) H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block and parent, address = %llu", (unsigned long long)dblk->heap->dblk_addr); break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ + /* Destroy flush dependency on parent */ + if(H5HL__destroy_flush_depend((H5AC_info_t *)dblk->heap->prfx, (H5AC_info_t *)dblk) < 0) + H5E_THROW(H5E_CANTUNDEPEND, "unable to destroy flush dependency") break; default: @@ -827,34 +921,43 @@ H5HL__datablock_notify(H5AC_notify_action_t action, H5HL_dblk_t *dblk)) CATCH /* No special processing on errors */ -END_FUNC(STATIC) /* end H5HL__datablock_notify() */ +END_FUNC(STATIC) /* end H5HL__cache_datablock_notify() */ /*------------------------------------------------------------------------- - * Function: H5HL__datablock_size + * Function: H5HL__cache_datablock_free_icr + * + * Purpose: Free the in memory representation of the supplied local heap data block. * - * Purpose: Compute the size in bytes of the local heap data block on disk, - * and return it in *len_ptr. On failure, the value of *len_ptr - * is undefined. + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Return: SUCCEED (Can't fail) + * Return: Success: SUCCEED + * Failure: FAIL * * Programmer: John Mainzer - * 5/13/04 + * 6/21/14 * *------------------------------------------------------------------------- */ -BEGIN_FUNC(STATIC, NOERR, -herr_t, SUCCEED, -, -H5HL__datablock_size(const H5F_t H5_ATTR_UNUSED *f, H5HL_dblk_t *dblk, size_t *size_ptr)) +static herr_t +H5HL__cache_datablock_free_icr(void *_thing) +{ + H5HL_dblk_t *dblk = (H5HL_dblk_t *)_thing; /* Pointer to the local heap data block */ + herr_t ret_value = SUCCEED; /* Return value */ - /* check arguments */ - HDassert(dblk); - HDassert(dblk->heap); - HDassert(size_ptr); + FUNC_ENTER_STATIC - /* Set size of data block in cache */ - *size_ptr = dblk->heap->dblk_size; + /* Check arguments */ + HDassert(dblk); + HDassert(dblk->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(dblk->cache_info.type == H5AC_LHEAP_DBLK); -END_FUNC(STATIC) /* H5HL__datablock_size() */ + /* Destroy the data block */ + if(H5HL__dblk_dest(dblk) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy local heap data block") +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL__cache_datablock_free_icr() */ diff --git a/src/H5HLdbg.c b/src/H5HLdbg.c index e481b20..f94b0cc 100644 --- a/src/H5HLdbg.c +++ b/src/H5HLdbg.c @@ -57,7 +57,7 @@ H5HL_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent, int HDassert(indent >= 0); HDassert(fwidth >= 0); - if(NULL == (h = (H5HL_t *)H5HL_protect(f, dxpl_id, addr, H5AC_READ))) + if(NULL == (h = (H5HL_t *)H5HL_protect(f, dxpl_id, addr, H5AC__READ_ONLY_FLAG))) H5E_THROW(H5E_CANTPROTECT, "unable to load/protect local heap"); HDfprintf(stream, "%*sLocal Heap...\n", indent, ""); diff --git a/src/H5HLpkg.h b/src/H5HLpkg.h index 2670b18..77d6255 100644 --- a/src/H5HLpkg.h +++ b/src/H5HLpkg.h @@ -133,12 +133,16 @@ struct H5HL_prfx_t { /* Callback information for loading local heap prefix from disk */ typedef struct H5HL_cache_prfx_ud_t { /* Downwards */ - size_t sizeof_size; /* Size of file sizes */ - size_t sizeof_addr; /* Size of file addresses */ - haddr_t prfx_addr; /* Address of prefix */ - size_t sizeof_prfx; /* Size of heap prefix */ + hbool_t made_attempt; /* Whether the deserialize routine */ + /* was already attempted */ + size_t sizeof_size; /* Size of file sizes */ + size_t sizeof_addr; /* Size of file addresses */ + haddr_t prfx_addr; /* Address of prefix */ + size_t sizeof_prfx; /* Size of heap prefix */ /* Upwards */ + hbool_t loaded; /* Whether prefix was loaded */ + /* from file */ } H5HL_cache_prfx_ud_t; /* Callback information for loading local heap data block from disk */ diff --git a/src/H5HLprivate.h b/src/H5HLprivate.h index 7ca54b0..92ad9bc 100644 --- a/src/H5HLprivate.h +++ b/src/H5HLprivate.h @@ -65,7 +65,7 @@ H5_DLL herr_t H5HL_heapsize(H5F_t *f, hid_t dxpl_id, haddr_t addr, hsize_t *heap H5_DLL size_t H5HL_insert(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t size, const void *buf); H5_DLL void *H5HL_offset_into(const H5HL_t *heap, size_t offset); -H5_DLL H5HL_t *H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, H5AC_protect_t rw); +H5_DLL H5HL_t *H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags); H5_DLL herr_t H5HL_remove(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t offset, size_t size); H5_DLL herr_t H5HL_unprotect(H5HL_t *heap); @@ -1772,7 +1772,7 @@ done: *------------------------------------------------------------------------- */ H5O_t * -H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, H5AC_protect_t prot) +H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, unsigned prot_flags) { H5O_t *oh = NULL; /* Object header protected */ H5O_cache_ud_t udata; /* User data for protecting object header */ @@ -1786,13 +1786,16 @@ H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, H5AC_protect_t prot) HDassert(loc); HDassert(loc->file); + /* prot_flags may only contain the H5AC__READ_ONLY_FLAG */ + HDassert((prot_flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); + /* Check for valid address */ if(!H5F_addr_defined(loc->addr)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "address undefined") /* Check for write access on the file */ file_intent = H5F_INTENT(loc->file); - if((prot == H5AC_WRITE) && (0 == (file_intent & H5F_ACC_RDWR))) + if((0 == (prot_flags & H5AC__READ_ONLY_FLAG)) && (0 == (file_intent & H5F_ACC_RDWR))) HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "no write intent on file") /* Construct the user data for protect callback */ @@ -1808,7 +1811,7 @@ H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, H5AC_protect_t prot) udata.common.addr = loc->addr; /* Lock the object header into the cache */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, &udata, prot))) + if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, &udata, prot_flags))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header") /* Check if there are any continuation messages to process */ @@ -1845,7 +1848,7 @@ H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, H5AC_protect_t prot) /* (which adds to the object header) */ chk_udata.common.addr = cont_msg_info.msgs[curr_msg].addr; chk_udata.size = cont_msg_info.msgs[curr_msg].size; - if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR_CHK, cont_msg_info.msgs[curr_msg].addr, &chk_udata, prot))) + if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR_CHK, cont_msg_info.msgs[curr_msg].addr, &chk_udata, prot_flags))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header chunk") /* Sanity check */ @@ -1889,7 +1892,7 @@ H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, H5AC_protect_t prot) /* (object header will have been marked dirty during protect, if we * have write access -QAK) */ - if(prot != H5AC_WRITE) + if((prot_flags & H5AC__READ_ONLY_FLAG) != 0) oh->prefix_modified = TRUE; #ifndef NDEBUG else { @@ -1907,7 +1910,7 @@ H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, H5AC_protect_t prot) } /* end if */ /* Check for any messages that were modified while being read in */ - if(udata.common.mesgs_modified && prot != H5AC_WRITE) + if(udata.common.mesgs_modified && (0 == (prot_flags & H5AC__READ_ONLY_FLAG))) oh->mesgs_modified = TRUE; /* Reset the field that contained chunk 0's size during speculative load */ @@ -1917,7 +1920,7 @@ H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, H5AC_protect_t prot) /* Take care of loose ends for modifications made while bringing in the * object header & chunks. */ - if(prot == H5AC_WRITE) { + if(0 == (prot_flags & H5AC__READ_ONLY_FLAG)) { /* Check for the object header prefix being modified somehow */ /* (usually through updating the # of object header messages) */ if(oh->prefix_modified) { @@ -2003,7 +2006,7 @@ H5O_pin(const H5O_loc_t *loc, hid_t dxpl_id) HDassert(loc); /* Get header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_WRITE))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header") /* Increment the reference count on the object header */ @@ -2216,7 +2219,7 @@ H5O_touch(const H5O_loc_t *loc, hbool_t force, hid_t dxpl_id) HDassert(loc); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_WRITE))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Create/Update the modification time message */ @@ -2333,7 +2336,7 @@ H5O_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr) loc.holding_file = FALSE; /* Get the object header information */ - if(NULL == (oh = H5O_protect(&loc, dxpl_id, H5AC_WRITE))) + if(NULL == (oh = H5O_protect(&loc, dxpl_id, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Delete object */ @@ -2425,7 +2428,7 @@ H5O_obj_type(const H5O_loc_t *loc, H5O_type_t *obj_type, hid_t dxpl_id) FUNC_ENTER_NOAPI_TAG(dxpl_id, loc->addr, FAIL) /* Load the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Retrieve the type of the object */ @@ -2503,7 +2506,7 @@ H5O_obj_class(const H5O_loc_t *loc, hid_t dxpl_id) FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, loc->addr, NULL) /* Load the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header") /* Test whether entry qualifies as a particular type of object */ @@ -2800,7 +2803,7 @@ H5O_get_hdr_info(const H5O_loc_t *loc, hid_t dxpl_id, H5O_hdr_info_t *hdr) HDmemset(hdr, 0, sizeof(*hdr)); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Get the information for the object header */ @@ -2924,7 +2927,7 @@ H5O_get_info(const H5O_loc_t *loc, hid_t dxpl_id, hbool_t want_ih_info, HDassert(oinfo); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Reset the object info structure */ @@ -3045,7 +3048,7 @@ H5O_get_create_plist(const H5O_loc_t *loc, hid_t dxpl_id, H5P_genplist_t *oc_pli HDassert(oc_plist); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Set property values, if they were used for the object */ @@ -3100,7 +3103,7 @@ H5O_get_nlinks(const H5O_loc_t *loc, hid_t dxpl_id, hsize_t *nlinks) HDassert(nlinks); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Retrieve the # of link messages seen when the object header was loaded */ @@ -3217,7 +3220,7 @@ H5O_get_rc_and_type(const H5O_loc_t *loc, hid_t dxpl_id, unsigned *rc, H5O_type_ HDassert(loc); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Set the object's reference count */ @@ -3590,7 +3593,7 @@ H5O_dec_rc_by_loc(const H5O_loc_t *loc, hid_t dxpl_id) HDassert(loc); /* Get header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header") /* Decrement the reference count on the object header */ @@ -3694,7 +3697,7 @@ H5O_pin_flush_dep_proxy(H5O_loc_t *loc, hid_t dxpl_id) HDassert(loc); /* Get header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header") /* Pin object header proxy */ diff --git a/src/H5Oattribute.c b/src/H5Oattribute.c index f7910f5..79ec506 100644 --- a/src/H5Oattribute.c +++ b/src/H5Oattribute.c @@ -493,7 +493,7 @@ H5O_attr_open_by_name(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) HDassert(name); /* Protect the object header to iterate over */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, NULL, "unable to load object header") /* Check for attribute info stored */ @@ -650,7 +650,7 @@ H5O_attr_open_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, HGOTO_ERROR(H5E_ATTR, H5E_BADITER, NULL, "can't locate attribute") /* Protect the object header to iterate over */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, NULL, "unable to load object header") /* Find out whether it has already been opened. If it has, close the object @@ -1311,7 +1311,7 @@ H5O_attr_iterate_real(hid_t loc_id, const H5O_loc_t *loc, hid_t dxpl_id, HDassert(attr_op); /* Protect the object header to iterate over */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -1910,7 +1910,7 @@ H5O_attr_exists(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) HDassert(name); /* Protect the object header to iterate over */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -2081,7 +2081,7 @@ H5O_attr_count(const H5O_loc_t *loc, hid_t dxpl_id) HDassert(loc); /* Protect the object header to iterate over */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Retrieve # of attributes on object */ diff --git a/src/H5Ocache.c b/src/H5Ocache.c index 8653817..c7632bd 100644 --- a/src/H5Ocache.c +++ b/src/H5Ocache.c @@ -53,11 +53,6 @@ * size to save the extra I/O operations) */ #define H5O_SPEC_READ_SIZE 512 -/* Set the estimated size of the chunk to read */ -/* (Avoids an allocation, if we estimate correctly) */ -#define H5O_EST_CHUNK_SIZE 512 - - /******************/ /* Local Typedefs */ @@ -74,18 +69,32 @@ /********************/ /* Metadata cache callbacks */ -static H5O_t *H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5O_t *oh, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5O_dest(H5F_t *f, H5O_t *oh); -static herr_t H5O_clear(H5F_t *f, H5O_t *oh, hbool_t destroy); -static herr_t H5O_size(const H5F_t *f, const H5O_t *oh, size_t *size_ptr); - -static H5O_chunk_proxy_t *H5O_cache_chk_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5O_cache_chk_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5O_chunk_proxy_t *chk_proxy, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5O_cache_chk_dest(H5F_t *f, H5O_chunk_proxy_t *chk_proxy); -static herr_t H5O_cache_chk_clear(H5F_t *f, H5O_chunk_proxy_t *chk_proxy, hbool_t destroy); -static herr_t H5O_cache_chk_notify(H5AC_notify_action_t action, H5O_chunk_proxy_t *chk_proxy); -static herr_t H5O_cache_chk_size(const H5F_t *f, const H5O_chunk_proxy_t *chk_proxy, size_t *size_ptr); +static herr_t H5O__cache_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5O__cache_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5O__cache_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5O__cache_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5O__cache_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5O__cache_free_icr(void *thing); +static herr_t H5O__cache_clear(const H5F_t *f, void *thing, hbool_t about_to_destroy); + +static herr_t H5O__cache_chk_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5O__cache_chk_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5O__cache_chk_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5O__cache_chk_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len, + void *thing); +static herr_t H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing); +static herr_t H5O__cache_chk_free_icr(void *thing); +static herr_t H5O__cache_chk_clear(const H5F_t *f, void *thing, hbool_t about_to_destroy); /* Chunk proxy routines */ static herr_t H5O__chunk_proxy_dest(H5O_chunk_proxy_t *chunk_proxy); @@ -107,24 +116,38 @@ static herr_t H5O_decode_prefix(H5F_t *f, H5O_t *oh, const uint8_t *buf, void *_ /* H5O object header prefix inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_OHDR[1] = {{ - H5AC_OHDR_ID, - (H5AC_load_func_t)H5O_load, - (H5AC_flush_func_t)H5O_flush, - (H5AC_dest_func_t)H5O_dest, - (H5AC_clear_func_t)H5O_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5O_size, + H5AC_OHDR_ID, /* Metadata client ID */ + "object header", /* Metadata client name (for debugging) */ + H5FD_MEM_OHDR, /* File space memory type for client */ + H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ + H5O__cache_get_load_size, /* 'get_load_size' callback */ + H5O__cache_verify_chksum, /* 'verify_chksum' callback */ + H5O__cache_deserialize, /* 'deserialize' callback */ + H5O__cache_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5O__cache_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5O__cache_free_icr, /* 'free_icr' callback */ + H5O__cache_clear, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* H5O object header chunk inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_OHDR_CHK[1] = {{ - H5AC_OHDR_CHK_ID, - (H5AC_load_func_t)H5O_cache_chk_load, - (H5AC_flush_func_t)H5O_cache_chk_flush, - (H5AC_dest_func_t)H5O_cache_chk_dest, - (H5AC_clear_func_t)H5O_cache_chk_clear, - (H5AC_notify_func_t)H5O_cache_chk_notify, - (H5AC_size_func_t)H5O_cache_chk_size, + H5AC_OHDR_CHK_ID, /* Metadata client ID */ + "object header continuation chunk", /* Metadata client name (for debugging) */ + H5FD_MEM_OHDR, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5O__cache_chk_get_load_size, /* 'get_load_size' callback */ + H5O__cache_chk_verify_chksum, /* 'verify_chksum' callback */ + H5O__cache_chk_deserialize, /* 'deserialize' callback */ + H5O__cache_chk_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5O__cache_chk_serialize, /* 'serialize' callback */ + H5O__cache_chk_notify, /* 'notify' callback */ + H5O__cache_chk_free_icr, /* 'free_icr' callback */ + H5O__cache_chk_clear, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* Declare external the free list for H5O_unknown_t's */ @@ -151,11 +174,11 @@ H5FL_SEQ_DEFINE(H5O_cont_t); * Function: H5O_decode_prefix * * Purpose: To decode the object header prefix. - * The coding is extracted fromt H5O_load() to this routine. + * The coding is extracted fromt H5O__cache_deserialize() to this routine. * * Return: Non-negative on success/Negative on failure * - * Programmer: Vailin Choi; June 2013 + * Programmer: Vailin Choi; Aug 2015 * *------------------------------------------------------------------------- */ @@ -291,155 +314,177 @@ done: /*------------------------------------------------------------------------- - * Function: H5O_load + * Function: H5O__cache_get_load_size() + * + * Purpose: Tell the metadata cache how much data to read from file in + * the first speculative read for the object header. Note that we do + * not have to be concerned about reading past the end of file, as the + * cache will clamp the read to avoid this if needed. * - * Purpose: Loads an object header from disk. + * Return: Success: SUCCEED + * Failure: FAIL * - * Return: Success: Pointer to the new object header. + * Programmer: John Mainzer + * 7/28/14 * - * Failure: NULL + *------------------------------------------------------------------------- + */ +static herr_t +H5O__cache_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */ + H5O_t oh; /* Object header read in */ + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image_len); + + if(image == NULL) + *image_len = H5O_SPEC_READ_SIZE; + + else { /* compute actual_len */ + HDassert(udata); + HDassert(actual_len); + HDassert(*actual_len == *image_len); + + /* Decode header prefix */ + if(H5O_decode_prefix(udata->common.f, &oh, image, udata) < 0) + HGOTO_DONE(FAIL) + + /* Save the version to be used in verify_chksum callback */ + udata->version = oh.version; + *actual_len = oh.chunk0_size + (size_t)H5O_SIZEOF_HDR(&oh); + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__cache_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5O__cache_verify_chksum * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 5 1997 + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 * - * Modifications: - * Vailin Choi; June 2013 - * This is a fix for SWMR: - * When reading a block that is > spec_read_size, read the whole block in - * again and possibly decode the header. - * Move the coding for decoding the object header prefix to another routine - * H5O_decode_prefix(). *------------------------------------------------------------------------- */ -static H5O_t * -H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static htri_t +H5O__cache_verify_chksum(const void *_image, size_t len, void *_udata) { - H5O_t *oh = NULL; /* Object header read in */ - H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */ - uint8_t read_buf[H5O_SPEC_READ_SIZE]; /* Buffer for speculative read */ - uint8_t *buf = NULL; /* Buffer to decode */ - size_t spec_read_size; /* Size of buffer to speculatively read in */ - size_t buf_size; /* Size of prefix+chunk #0 buffer */ - haddr_t eoa; /* Relative end of file address */ - unsigned tries, max_tries; /* The # of read attempts */ - unsigned retries; /* The # of retries */ - unsigned fixed_tries; /* The # of read attempts for prefix */ - uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum;/* Computed metadata checksum value */ - H5O_t *ret_value; /* Return value */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(image); HDassert(udata); - HDassert(udata->common.f); - HDassert(udata->common.cont_msg_info); - /* Make certain we don't speculatively read off the end of the file */ - if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_OHDR))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to determine file size") + /* There is no checksum for version 1 */ + if(udata->version != H5O_VERSION_1) { + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__cache_verify_chksum() */ + + +/*------------------------------------------------------------------------- + * Function: H5O__cache_deserialize + * + * Purpose: Attempt to deserialize the object header contained in the + * supplied buffer, load the data into an instance of H5O_t, and + * return a pointer to the new instance. + * + * Note that the object header is read with with a speculative read. + * If the initial read is too small, make note of this fact and return + * without error. H5C_load_entry() will note the size discrepency + * and retry the deserialize operation with the correct size read. + * + * Return: Success: Pointer to in core representation + * Failure: NULL + * + * Programmer: John Mainzer + * 7/28/14 + * + *------------------------------------------------------------------------- + */ +static void * +H5O__cache_deserialize(const void *_image, size_t len, void *_udata, + hbool_t *dirty) +{ + H5O_t *oh = NULL; /* Object header read in */ + H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into buffer to decode */ + size_t buf_size; /* Size of prefix+chunk #0 buffer */ + void * ret_value = NULL; /* Return value */ + + FUNC_ENTER_STATIC - /* Compute the size of the speculative object header buffer */ - H5_CHECKED_ASSIGN(spec_read_size, size_t, MIN(eoa - addr, H5O_SPEC_READ_SIZE), hsize_t); + /* Check arguments */ + HDassert(image); + HDassert(len > 0); + HDassert(udata); + HDassert(udata->common.f); + HDassert(udata->common.cont_msg_info); + HDassert(dirty); /* Allocate space for the object header data structure */ if(NULL == (oh = H5FL_CALLOC(H5O_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - /* Get the # of read attempts */ - tries = max_tries = H5F_GET_READ_ATTEMPTS(f); - do { - fixed_tries = max_tries; - do { - /* Attempt to speculatively read both object header prefix and first chunk */ - if(H5F_block_read(f, H5FD_MEM_OHDR, addr, spec_read_size, dxpl_id, read_buf) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header") - - /* Decode header prefix */ - if(H5O_decode_prefix(f, oh, read_buf, udata) >= 0) - break; - } while (--fixed_tries); - - if(fixed_tries == 0) - /* After all tries (for SWMR access) or after 1 try (for non-SWMR) */ - HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "bad object header prefix after all tries") - - /* Compute the size of the buffer required */ - buf_size = oh->chunk0_size + (size_t)H5O_SIZEOF_HDR(oh); - - /* Check if the speculative read was large enough to parse the first chunk */ - if(spec_read_size < buf_size) { - /* Allocate space for a buffer that's large enough for serialized header */ - if(NULL == (buf = (uint8_t *)H5MM_malloc(buf_size))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "can't get actual buffer") - - /* SWMR access */ - if(H5F_INTENT(f) & (H5F_ACC_SWMR_READ | H5F_ACC_SWMR_WRITE)) { - /* Read the chunk that is bigger than the speculative read size */ - if(H5F_block_read(f, H5FD_MEM_OHDR, addr, buf_size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header") - - /* See if the data read now is the same as what is read initially */ - if(HDmemcmp(buf, read_buf, spec_read_size)) { - HDmemset(oh, 0, sizeof(*oh)); - - /* Decode the prefix again */ - if(H5O_decode_prefix(f, oh, buf, udata) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't decode object header prefix") - } /* end if */ - } /* end if */ - else { - /* Copy existing raw data into new buffer */ - HDmemcpy(buf, read_buf, spec_read_size); - - /* Read rest of the raw data */ - if(H5F_block_read(f, H5FD_MEM_OHDR, (addr + spec_read_size), (buf_size - spec_read_size), dxpl_id, (buf + spec_read_size)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header data") - } /* end else */ - } else - buf = read_buf; - - /* There is no checksum for version 1 */ - if(oh->version == H5O_VERSION_1) - break; - - /* For version 2: retrieve the stored checksum and compute the checksum */ - H5F_get_checksums(buf, buf_size, &stored_chksum, &computed_chksum); - - /* Verify checksums */ - if(stored_chksum == computed_chksum) - break; - } while (--tries); - - if(tries == 0) - HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "incorrect metadata checksum for object header chunk after all read tries (%u) for %u bytes", max_tries, buf_size) - - /* Calculate and track the # of retries */ - retries = max_tries - tries; - if(retries) /* Does not track 0 retry */ - if(H5F_track_metadata_read_retries(f, H5AC_OHDR_ID, retries) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "cannot track read retries = %u ", retries) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") /* File-specific, non-stored information */ oh->sizeof_size = H5F_SIZEOF_SIZE(udata->common.f); oh->sizeof_addr = H5F_SIZEOF_ADDR(udata->common.f); + + /* Decode header prefix */ + if(H5O_decode_prefix(udata->common.f, oh, image, udata) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize object header prefix") + + /* Compute the size of the buffer used */ + buf_size = oh->chunk0_size + (size_t)H5O_SIZEOF_HDR(oh); + oh->swmr_write = !!(H5F_INTENT(udata->common.f) & H5F_ACC_SWMR_WRITE); /* Create object header proxy if doing SWMR writes */ HDassert(!oh->proxy_present); - if(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE) { - if(H5O_proxy_create(f, dxpl_id, oh) < 0) + if(H5F_INTENT(udata->common.f) & H5F_ACC_SWMR_WRITE) { + if(H5O_proxy_create(udata->common.f, udata->common.dxpl_id, oh) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, NULL, "can't create object header proxy") } /* end if */ else oh->proxy_addr = HADDR_UNDEF; - /* Parse the first chunk */ - if(H5O__chunk_deserialize(oh, udata->common.addr, oh->chunk0_size, buf, &(udata->common), &oh->cache_info.is_dirty) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize first object header chunk") + /* Check to see if the buffer provided is large enough to contain both + * the prefix and the first chunk. If it isn't, make note of the desired + * size, but otherwise do nothing. H5C_load_entry() will notice the + * discrepency, load the correct size buffer, and retry the deserialize. + */ + if(len >= buf_size) { + /* Parse the first chunk */ + if(H5O__chunk_deserialize(oh, udata->common.addr, oh->chunk0_size, (const uint8_t *)_image, &(udata->common), dirty) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize first object header chunk") + } /* end if */ + else + HDassert(!udata->made_attempt); /* Note that we've loaded the object header from the file */ udata->made_attempt = TRUE; @@ -448,202 +493,234 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) ret_value = oh; done: - /* Release resources */ - if(buf && buf != read_buf) - H5MM_free(buf); - /* Release the [possibly partially initialized] object header on errors */ if(!ret_value && oh) if(H5O_free(oh) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header data") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_load() */ +} /* end H5O__cache_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5O_flush + * Function: H5O__cache_image_len * - * Purpose: Flushes (and destroys) an object header. + * Purpose: Compute the size in bytes of the specified instance of + * H5O_t on disk, and return it in *image_len. On failure, + * the value of *image_len is undefined. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 5 1997 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t H5_ATTR_UNUSED addr, H5O_t *oh, unsigned H5_ATTR_UNUSED * flags_ptr) +H5O__cache_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const H5O_t *oh = (const H5O_t *)_thing; /* Object header to query */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); HDassert(oh); + HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(oh->cache_info.type == H5AC_OHDR); + HDassert(image_len); + + /* Report the object header's prefix+first chunk length */ + if(oh->chunk0_size) + *image_len = (size_t)H5O_SIZEOF_HDR(oh) + oh->chunk0_size; + else + *image_len = oh->chunk[0].size; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O__cache_image_len() */ + +/********************************/ +/* no H5O_cache_pre_serialize() */ +/********************************/ + + +/*------------------------------------------------------------------------- + * Function: H5O__cache_serialize + * + * Purpose: Serialize the contents of the supplied object header, and + * load this data into the supplied buffer. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 7/28/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O__cache_serialize(const H5F_t *f, void *image, size_t len, void *_thing) +{ + H5O_t *oh = (H5O_t *)_thing; /* Object header to encode */ + uint8_t *chunk_image; /* Pointer to object header prefix buffer */ + herr_t ret_value = SUCCEED; /* Return value */ - /* flush */ - if(oh->cache_info.is_dirty) { - uint8_t *p; /* Pointer to object header prefix buffer */ + FUNC_ENTER_STATIC + /* Check arguments */ + HDassert(f); + HDassert(image); + HDassert(oh); + HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(oh->cache_info.type == H5AC_OHDR); + HDassert(oh->chunk[0].size == len); #ifdef H5O_DEBUG -H5O_assert(oh); + H5O_assert(oh); #endif /* H5O_DEBUG */ - /* Point to raw data 'image' for first chunk, which has room for the prefix */ - p = oh->chunk[0].image; - - /* Later versions of object header prefix have different format and - * also require that chunk 0 always be updated, since the checksum - * on the entire block of memory needs to be updated if anything is - * modified */ - if(oh->version > H5O_VERSION_1) { - uint64_t chunk0_size; /* Size of chunk 0's data */ + /* Point to raw data 'image' for first chunk, which + * has room for the prefix + */ + chunk_image = oh->chunk[0].image; - HDassert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh)); - chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh); + /* Later versions of object header prefix have different format and + * also require that chunk 0 always be updated, since the checksum + * on the entire block of memory needs to be updated if anything is + * modified + */ + if(oh->version > H5O_VERSION_1) { + uint64_t chunk0_size; /* Size of chunk 0's data */ - /* Verify magic number */ - HDassert(!HDmemcmp(p, H5O_HDR_MAGIC, H5_SIZEOF_MAGIC)); - p += H5_SIZEOF_MAGIC; + HDassert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh)); + chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh); - /* Version */ - *p++ = oh->version; + /* Verify magic number */ + HDassert(!HDmemcmp(chunk_image, H5O_HDR_MAGIC, H5_SIZEOF_MAGIC)); + chunk_image += H5_SIZEOF_MAGIC; - /* Flags */ - *p++ = oh->flags; + /* Version */ + *chunk_image++ = oh->version; - /* Time fields */ - if(oh->flags & H5O_HDR_STORE_TIMES) { - UINT32ENCODE(p, oh->atime); - UINT32ENCODE(p, oh->mtime); - UINT32ENCODE(p, oh->ctime); - UINT32ENCODE(p, oh->btime); - } /* end if */ + /* Flags */ + *chunk_image++ = oh->flags; - /* Attribute fields */ - if(oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) { - UINT16ENCODE(p, oh->max_compact); - UINT16ENCODE(p, oh->min_dense); - } /* end if */ + /* Time fields */ + if(oh->flags & H5O_HDR_STORE_TIMES) { + UINT32ENCODE(chunk_image, oh->atime); + UINT32ENCODE(chunk_image, oh->mtime); + UINT32ENCODE(chunk_image, oh->ctime); + UINT32ENCODE(chunk_image, oh->btime); + } /* end if */ - /* First chunk size */ - switch(oh->flags & H5O_HDR_CHUNK0_SIZE) { - case 0: /* 1 byte size */ - HDassert(chunk0_size < 256); - *p++ = (uint8_t)chunk0_size; - break; - - case 1: /* 2 byte size */ - HDassert(chunk0_size < 65536); - UINT16ENCODE(p, chunk0_size); - break; - - case 2: /* 4 byte size */ - /* use <= 2**32 -1 to stay within 4 bytes integer range */ - HDassert(chunk0_size <= 4294967295UL); - UINT32ENCODE(p, chunk0_size); - break; - - case 3: /* 8 byte size */ - UINT64ENCODE(p, chunk0_size); - break; - - default: - HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0") - } /* end switch */ + /* Attribute fields */ + if(oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) { + UINT16ENCODE(chunk_image, oh->max_compact); + UINT16ENCODE(chunk_image, oh->min_dense); } /* end if */ - else { - /* Version */ - *p++ = oh->version; - /* Reserved */ - *p++ = 0; + /* First chunk size */ + switch(oh->flags & H5O_HDR_CHUNK0_SIZE) { + case 0: /* 1 byte size */ + HDassert(chunk0_size < 256); + *chunk_image++ = (uint8_t)chunk0_size; + break; + + case 1: /* 2 byte size */ + HDassert(chunk0_size < 65536); + UINT16ENCODE(chunk_image, chunk0_size); + break; + + case 2: /* 4 byte size */ + /* use <= 2**32 -1 to stay within 4 bytes integer range */ + HDassert(chunk0_size <= 4294967295UL); + UINT32ENCODE(chunk_image, chunk0_size); + break; + + case 3: /* 8 byte size */ + UINT64ENCODE(chunk_image, chunk0_size); + break; + + default: + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0") + } /* end switch */ + } /* end if */ + else { + /* Version */ + *chunk_image++ = oh->version; + + /* Reserved */ + *chunk_image++ = 0; - /* Number of messages */ + /* Number of messages */ #ifdef H5O_ENABLE_BAD_MESG_COUNT - if(oh->store_bad_mesg_count) - UINT16ENCODE(p, (oh->nmesgs - 1)) - else + if(oh->store_bad_mesg_count) + UINT16ENCODE(chunk_image, (oh->nmesgs - 1)) + else #endif /* H5O_ENABLE_BAD_MESG_COUNT */ - UINT16ENCODE(p, oh->nmesgs); + UINT16ENCODE(chunk_image, oh->nmesgs); - /* Link count */ - UINT32ENCODE(p, oh->nlink); + /* Link count */ + UINT32ENCODE(chunk_image, oh->nlink); - /* First chunk size */ - UINT32ENCODE(p, (oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh))); + /* First chunk size */ + UINT32ENCODE(chunk_image, (oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh))); - /* Zero to alignment */ - HDmemset(p, 0, (size_t)(H5O_SIZEOF_HDR(oh) - 12)); - p += (size_t)(H5O_SIZEOF_HDR(oh) - 12); - } /* end else */ - HDassert((size_t)(p - oh->chunk[0].image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); + /* Zero to alignment */ + HDmemset(chunk_image, 0, (size_t)(H5O_SIZEOF_HDR(oh) - 12)); + chunk_image += (size_t)(H5O_SIZEOF_HDR(oh) - 12); + } /* end else */ - /* Serialize messages for this chunk */ - if(H5O__chunk_serialize(f, oh, (unsigned)0) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize first object header chunk") + HDassert((size_t)(chunk_image - oh->chunk[0].image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); - /* Write the chunk out */ - HDassert(H5F_addr_defined(oh->chunk[0].addr)); - if(H5F_block_write(f, H5FD_MEM_OHDR, oh->chunk[0].addr, oh->chunk[0].size, dxpl_id, oh->chunk[0].image) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header chunk to disk") + /* Serialize messages for this chunk */ + if(H5O__chunk_serialize(f, oh, (unsigned)0) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize first object header chunk") - /* Mark object header as clean now */ - oh->cache_info.is_dirty = FALSE; - } /* end if */ - - /* Destroy the object header, if requested */ - if(destroy) - if(H5O_dest(f, oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data") + /* copy the chunk into the image -- this is potentially expensive. + * Can we rework things so that the object header and the cache + * share a buffer? + */ + HDmemcpy(image, oh->chunk[0].image, len); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_flush() */ +} /* end H5O__cache_serialize() */ + +/**********************************/ +/* no H5O_cache_notify() function */ +/**********************************/ /*------------------------------------------------------------------------- - * Function: H5O_dest + * Function: H5O__cache_free_icr * - * Purpose: Destroys an object header. + * Purpose: Free the in core representation of the supplied object header. * - * Return: Non-negative on success/Negative on failure + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Jan 15 2003 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5O_dest(H5F_t *f, H5O_t *oh) -{ - herr_t ret_value = SUCCEED; /* Return value */ +H5O__cache_free_icr(void *_thing) +{ + H5O_t *oh = (H5O_t *)_thing; /* Object header to destroy */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check arguments */ HDassert(oh); - HDassert(oh->rc == 0); - - /* Verify that node is clean */ - HDassert(!oh->cache_info.is_dirty); - - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!oh->cache_info.free_file_space_on_destroy || H5F_addr_defined(oh->cache_info.addr)); - - /* Check for releasing file space for object header */ - if(oh->chunk && oh->cache_info.free_file_space_on_destroy) { - /* Free main (first) object header "chunk" */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_OHDR, H5AC_dxpl_id, oh->chunk[0].addr, (hsize_t)oh->chunk[0].size) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free object header") - } /* end if */ + HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(oh->cache_info.type == H5AC_OHDR); /* Destroy object header */ if(H5O_free(oh) < 0) @@ -651,178 +728,191 @@ H5O_dest(H5F_t *f, H5O_t *oh) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_dest() */ +} /* end H5O__cache_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5O_clear + * Function: H5O__cache_clear * - * Purpose: Mark a object header in memory as non-dirty. + * Purpose: Clear all dirty bits associated with this cache entry. * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 20 2003 + * This is ncessary as the object header cache client maintains + * its own dirty bits on individual messages. These dirty bits + * used to be cleared by the old V2 metadata cache flush callback, + * but now the metadata cache must clear them explicitly, as + * the serialize callback does not imply that the data has been + * written to disk. * - * Changes: In the parallel case, there is the possibility that the - * the object header may be flushed by different processes - * over the life of the computation. Thus we must ensure - * that the chunk images are up to date before we mark the - * messages clean -- as otherwise we may overwrite valid - * data with a blank section of a chunk image. + * This callback is also necessary for the parallel case. * - * To deal with this, I have added code to call - * H5O_chunk_serialize() for all chunks before we - * mark all messages as clean if we are not destroying the - * object. Do this in the parallel case only, as the problem - * can only occur in this context. + * Return: Success: SUCCEED + * Failure: FAIL * - * JRM -- 10/12/10 + * Programmer: John Mainzer + * 9/22/14 * *------------------------------------------------------------------------- */ static herr_t -H5O_clear(H5F_t *f, H5O_t *oh, hbool_t destroy) -{ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; +H5O__cache_clear(const H5F_t *f, void *_thing, hbool_t about_to_destroy) +{ + H5O_t *oh = (H5O_t *)_thing; /* Object header to reset */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check arguments */ HDassert(oh); + HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(oh->cache_info.type == H5AC_OHDR); #ifdef H5_HAVE_PARALLEL - if ( ( oh->cache_info.is_dirty ) && ( ! destroy ) ) { - - size_t i; - - /* scan through all chunks associated with the object header, - * and cause them to update their images for all entries currently - * marked dirty. Must do this in the parallel case, as it is possible - * that this processor may clear this object header several times - * before flushing it -- thus causing undefined sections of the image - * to be written to disk overwriting valid data. + if((oh->nchunks > 0) && (!about_to_destroy)) { + /* Scan through chunk 0 (the chunk stored contiguously with this + * object header) and cause it to update its image of all entries + * currently marked dirty. Must do this in the parallel case, as + * it is possible that this processor may clear this object header + * several times before flushing it -- thus causing undefined + * sections of the image to be written to disk overwriting valid data. */ - - for ( i = 0; i < oh->nchunks; i++ ) { - - if(H5O__chunk_serialize(f, oh, i) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize object header chunk") - } - } + if(H5O__chunk_serialize(f, oh, 0) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize object header chunk") + } /* end if */ #endif /* H5_HAVE_PARALLEL */ /* Mark messages stored with the object header (i.e. messages in chunk 0) as clean */ for(u = 0; u < oh->nmesgs; u++) - oh->mesg[u].dirty = FALSE; + if(oh->mesg[u].chunkno == 0) + oh->mesg[u].dirty = FALSE; #ifndef NDEBUG /* Reset the number of messages dirtied by decoding */ oh->ndecode_dirtied = 0; #endif /* NDEBUG */ - /* Mark whole header as clean */ - oh->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5O_dest(f, oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data") - done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_clear() */ +} /* end H5O__cache_clear() */ /*------------------------------------------------------------------------- - * Function: H5O_size + * Function: H5O__cache_chk_get_load_size() * - * Purpose: Compute the size in bytes of the specified instance of - * H5O_t on disk, and return it in *len_ptr. On failure, - * the value of *len_ptr is undefined. + * Purpose: Tell the metadata cache how large the on disk image of the + * chunk proxy is, so it can load the image into a buffer for the + * deserialize call. In this case, we simply look up the size in + * the user data, and return it in *image_len, * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: John Mainzer - * 5/13/04 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5O_size(const H5F_t H5_ATTR_UNUSED *f, const H5O_t *oh, size_t *size_ptr) +H5O__cache_chk_get_load_size(const void *_image, void *_udata, + size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + const H5O_chk_cache_ud_t *udata = (const H5O_chk_cache_ud_t *)_udata; /* User data for callback */ - /* check args */ - HDassert(oh); - HDassert(size_ptr); + FUNC_ENTER_STATIC_NOERR - /* Report the object header's prefix+first chunk length */ - if(oh->chunk0_size) - *size_ptr = (size_t)H5O_SIZEOF_HDR(oh) + oh->chunk0_size; - else - *size_ptr = oh->chunk[0].size; + /* Check arguments */ + HDassert(udata); + HDassert(udata->oh); + HDassert(image_len); + + if(image == NULL) + *image_len = udata->size; + else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5O_size() */ +} /* end H5O__cache_chk_get_load_size() */ + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_chk_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5O__cache_chk_verify_chksum(const void *_image, size_t len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata; /* User data for callback */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* There is no checksum for version 1 */ + if(udata->oh->version != H5O_VERSION_1) { + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__cache_chk_verify_chksum() */ /*------------------------------------------------------------------------- - * Function: H5O_cache_chk_load + * Function: H5O__cache_chk_deserialize * - * Purpose: Loads an object header continuation chunk from disk. + * Purpose: Attempt to deserialize the object header continuation chunk + * contained in the supplied buffer, load the data into an instance + * of H5O_chunk_proxy_t, and return a pointer to the new instance. * - * Return: Success: Pointer to the new object header chunk proxy. - * Failure: NULL + * Return: Success: Pointer to in core representation + * Failure: NULL * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Jul 12 2008 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ -static H5O_chunk_proxy_t * -H5O_cache_chk_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5O__cache_chk_deserialize(const void *image, size_t len, void *_udata, + hbool_t *dirty) { - H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk proxy object */ - H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata; /* User data for callback */ - H5WB_t *wb = NULL; /* Wrapped buffer for prefix data */ - uint8_t chunk_buf[H5O_EST_CHUNK_SIZE]; /* Buffer for estimated chunk size */ - uint8_t *buf; /* Buffer to decode */ - H5O_chunk_proxy_t *ret_value; /* Return value */ + H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk proxy object */ + H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata; /* User data for callback */ + void * ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + HDassert(image); + HDassert(len > 0); HDassert(udata); HDassert(udata->oh); + HDassert(dirty); /* Allocate space for the object header data structure */ - if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed") - - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(chunk_buf, sizeof(chunk_buf)))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't wrap buffer") - - /* Get a pointer to a buffer that's large enough for serialized header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, udata->size))) - HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "can't get actual buffer") - - /* Read rest of the raw data */ - if(udata->oh->version == H5O_VERSION_2 && udata->decoding) { - /* Read and validate object header continuation chunk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_OHDR, H5AC_OHDR_CHK_ID, addr, udata->size, udata->size, buf) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "incorrect metadata checksum for object header continuation chunk") - } /* end if */ - else { - /* Read the header object continuation chunk */ - if(H5F_block_read(f, H5FD_MEM_OHDR, addr, udata->size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header continuation chunk") - } /* end else */ + if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed") /* Check if we are still decoding the object header */ /* (as opposed to bringing a piece of it back from the file) */ @@ -832,7 +922,7 @@ H5O_cache_chk_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) HDassert(udata->common.cont_msg_info); /* Parse the chunk */ - if(H5O__chunk_deserialize(udata->oh, udata->common.addr, udata->size, buf, &(udata->common), &chk_proxy->cache_info.is_dirty) < 0) + if(H5O__chunk_deserialize(udata->oh, udata->common.addr, udata->size, (const uint8_t *)image, &(udata->common), dirty) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize object header chunk") /* Set the fields for the chunk proxy */ @@ -850,7 +940,7 @@ H5O_cache_chk_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) /* Sanity check that the chunk representation we have in memory is * the same as the one being brought in from disk. */ - HDassert(0 == HDmemcmp(buf, chk_proxy->oh->chunk[chk_proxy->chunkno].image, chk_proxy->oh->chunk[chk_proxy->chunkno].size)); + HDassert(0 == HDmemcmp(image, chk_proxy->oh->chunk[chk_proxy->chunkno].image, chk_proxy->oh->chunk[chk_proxy->chunkno].size)); } /* end else */ /* Increment reference count of object header */ @@ -861,186 +951,98 @@ H5O_cache_chk_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) ret_value = chk_proxy; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_OHDR, H5E_CLOSEERROR, NULL, "can't close wrapped buffer") - - /* Release the [possibly partially initialized] object header on errors */ - if(!ret_value && chk_proxy) - if(H5O__chunk_proxy_dest(chk_proxy) < 0) - HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header chunk proxy") - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_cache_chk_load() */ +} /* end H5O__cache_chk_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5O_cache_chk_flush + * Function: H5O__cache_chk_image_len * - * Purpose: Flushes (and destroys) an object header continuation chunk. + * Purpose: Return the on disk image size of a object header chunk to the + * metadata cache via the image_len. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Jul 12 2008 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5O_cache_chk_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, - H5O_chunk_proxy_t *chk_proxy, unsigned H5_ATTR_UNUSED * flags_ptr) +H5O__cache_chk_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const H5O_chunk_proxy_t * chk_proxy = (const H5O_chunk_proxy_t *)_thing; /* Chunk proxy to query */ - FUNC_ENTER_NOAPI_NOINIT - - /* flush */ - if(chk_proxy->cache_info.is_dirty) { - /* Serialize messages for this chunk */ - if(H5O__chunk_serialize(f, chk_proxy->oh, chk_proxy->chunkno) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize object header continuation chunk") - - /* Write the chunk out */ - HDassert(H5F_addr_defined(chk_proxy->oh->chunk[chk_proxy->chunkno].addr)); - HDassert(H5F_addr_eq(addr, chk_proxy->oh->chunk[chk_proxy->chunkno].addr)); - if(H5F_block_write(f, H5FD_MEM_OHDR, addr, chk_proxy->oh->chunk[chk_proxy->chunkno].size, dxpl_id, chk_proxy->oh->chunk[chk_proxy->chunkno].image) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header continuation chunk to disk") - - /* Mark object header as clean now */ - chk_proxy->cache_info.is_dirty = FALSE; - } /* end if */ - - /* Destroy the object header, if requested */ - if(destroy) - if(H5O_cache_chk_dest(f, chk_proxy) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header continuation chunk data") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_cache_chk_flush() */ - - -/*------------------------------------------------------------------------- - * Function: H5O_cache_chk_dest - * - * Purpose: Destroys an object header continuation chunk. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * July 12, 2008 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5O_cache_chk_dest(H5F_t *f, H5O_chunk_proxy_t *chk_proxy) -{ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR /* Check arguments */ HDassert(chk_proxy); - HDassert(chk_proxy->chunkno > 0); - - /* Verify that node is clean */ - HDassert(chk_proxy->cache_info.is_dirty == FALSE); - - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!chk_proxy->cache_info.free_file_space_on_destroy || H5F_addr_defined(chk_proxy->cache_info.addr)); + HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK); + HDassert(chk_proxy->oh); + HDassert(image_len); - /* Check for releasing file space for object header */ - if(chk_proxy->cache_info.free_file_space_on_destroy) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_OHDR, H5AC_dxpl_id, chk_proxy->oh->chunk[chk_proxy->chunkno].addr, (hsize_t)chk_proxy->oh->chunk[chk_proxy->chunkno].size) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free object header continuation chunk") - } /* end if */ + *image_len = chk_proxy->oh->chunk[chk_proxy->chunkno].size; - /* Destroy object header chunk proxy */ - if(H5O__chunk_proxy_dest(chk_proxy) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header chunk proxy") + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O__cache_chk_image_len() */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_cache_chk_dest() */ +/************************************/ +/* no H5O_cache_chk_pre_serialize() */ +/************************************/ /*------------------------------------------------------------------------- - * Function: H5O_cache_chk_clear - * - * Purpose: Mark a object header continuation chunk in memory as non-dirty. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * July 12, 2008 - * - * Changes: In the parallel case, there is the possibility that the - * the object header chunk may be flushed by different - * processes over the life of the computation. Thus we must - * ensure that the chunk image is up to date before we mark its - * messages clean -- as otherwise we may overwrite valid - * data with a blank section of a chunk image. + * Function: H5O__cache_chk_serialize * - * To deal with this, I have added code to call - * H5O_chunk_serialize() for this chunk before we - * mark all messages as clean if we are not destroying the - * chunk. + * Purpose: Given a pointer to an instance of an object header chunk and an + * appropriately sized buffer, serialize the contents of the + * instance for writing to disk, and copy the serialized data + * into the buffer. * - * Do this in the parallel case only, as the problem - * can only occur in this context. + * Return: Success: SUCCEED + * Failure: FAIL * - * Note that at present at least, it seems that this fix - * is not necessary, as we don't seem to be able to - * generate a dirty chunk without creating a dirty object - * header. However, the object header code will be changing - * a lot in the near future, so I'll leave this fix in - * for now, unless Quincey requests otherwise. - * - * JRM -- 10/12/10 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5O_cache_chk_clear(H5F_t *f, H5O_chunk_proxy_t *chk_proxy, hbool_t destroy) +H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len, void *_thing) { - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; + H5O_chunk_proxy_t * chk_proxy = (H5O_chunk_proxy_t *)_thing; /* Object header chunk to serialize */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check arguments */ + HDassert(f); + HDassert(image); HDassert(chk_proxy); + HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK); + HDassert(chk_proxy->oh); + HDassert(chk_proxy->oh->chunk[chk_proxy->chunkno].size == len); -#ifdef H5_HAVE_PARALLEL - if((chk_proxy->oh->cache_info.is_dirty) && (!destroy)) - if(H5O__chunk_serialize(f, chk_proxy->oh, chk_proxy->chunkno) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize object header chunk") -#endif /* H5_HAVE_PARALLEL */ - - /* Mark messages in chunk as clean */ - for(u = 0; u < chk_proxy->oh->nmesgs; u++) - if(chk_proxy->oh->mesg[u].chunkno == chk_proxy->chunkno) - chk_proxy->oh->mesg[u].dirty = FALSE; - - /* Mark as clean */ - chk_proxy->cache_info.is_dirty = FALSE; + /* Serialize messages for this chunk */ + if(H5O__chunk_serialize(f, chk_proxy->oh, chk_proxy->chunkno) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize object header continuation chunk") - if(destroy) - if(H5O_cache_chk_dest(f, chk_proxy) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header continuation chunk data") + /* copy the chunk into the image -- this is potentially expensive. + * Can we rework things so that the chunk and the cache share a buffer? + */ + HDmemcpy(image, chk_proxy->oh->chunk[chk_proxy->chunkno].image, len); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_cache_chk_clear() */ +} /* end H5O__cache_chk_serialize() */ /*------------------------------------------------------------------------- - * Function: H5O_cache_chk_notify + * Function: H5O__cache_chk_notify * * Purpose: Handle cache action notifications * @@ -1052,8 +1054,9 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5O_cache_chk_notify(H5AC_notify_action_t action, H5O_chunk_proxy_t *chk_proxy) +H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing) { + H5O_chunk_proxy_t *chk_proxy = (H5O_chunk_proxy_t *)_thing; void *parent = NULL; /* Chunk containing continuation message that points to this chunk */ H5O_chunk_proxy_t *cont_chk_proxy = NULL; /* Proxy for chunk containing continuation message that points to this chunk, if not chunk 0 */ herr_t ret_value = SUCCEED; /* Return value */ @@ -1069,6 +1072,7 @@ H5O_cache_chk_notify(H5AC_notify_action_t action, H5O_chunk_proxy_t *chk_proxy) if(chk_proxy->oh->swmr_write) { switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: /* Add flush dependency from chunk containing the continuation message * that points to this chunk (either oh or another chunk proxy object) */ @@ -1088,8 +1092,12 @@ H5O_cache_chk_notify(H5AC_notify_action_t action, H5O_chunk_proxy_t *chk_proxy) if(H5O_proxy_depend(chk_proxy->f, H5AC_ind_dxpl_id, chk_proxy->oh, chk_proxy) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "can't create flush dependency on object header proxy") + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: - /* Nothing to do */ + /* Nothing to do */ break; default: @@ -1107,38 +1115,105 @@ done: HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_cache_chk_notify() */ +} /* end H5O__cache_chk_notify() */ /*------------------------------------------------------------------------- - * Function: H5O_cache_chk_size + * Function: H5O__cache_chk_free_icr * - * Purpose: Compute the size in bytes of the specified instance of - * an object header continuation chunk on disk, and return it in - * *len_ptr. On failure, the value of *len_ptr is undefined. + * Purpose: Free the in core memory associated with the supplied object + * header continuation chunk. * - * Return: Non-negative on success/Negative on failure + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * July 12, 2008 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5O_cache_chk_size(const H5F_t H5_ATTR_UNUSED *f, const H5O_chunk_proxy_t *chk_proxy, size_t *size_ptr) +H5O__cache_chk_free_icr(void *_thing) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + H5O_chunk_proxy_t * chk_proxy = (H5O_chunk_proxy_t *)_thing; /* Object header chunk proxy to release */ + herr_t ret_value = SUCCEED; /* Return value */ - /* check args */ + FUNC_ENTER_STATIC + + /* Check arguments */ HDassert(chk_proxy); - HDassert(size_ptr); + HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK); - /* Report the object header continuation chunk's length */ - *size_ptr = chk_proxy->oh->chunk[chk_proxy->chunkno].size; + /* Destroy object header chunk proxy */ + if(H5O__chunk_proxy_dest(chk_proxy) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header chunk proxy") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__cache_chk_free_icr() */ + + +/*------------------------------------------------------------------------- + * Function: H5O__cache_chk_clear + * + * Purpose: Clear all dirty bits associated with this cache entry. + * + * This is ncessary as the object header cache client maintains + * its own dirty bits on individual messages. These dirty bits + * used to be cleared by the old V2 metadata cache flush callback, + * but now the metadata cache must clear them explicitly, as + * the serialize callback does not imply that the data has been + * written to disk. + * + * This callback is also necessary for the parallel case. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 9/22/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O__cache_chk_clear(const H5F_t *f, void *_thing, hbool_t about_to_destroy) +{ + H5O_chunk_proxy_t *chk_proxy = (H5O_chunk_proxy_t *)_thing; /* Object header chunk to reset */ + H5O_t *oh; /* Object header for chunk */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Check arguments */ + HDassert(chk_proxy); + HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK); + oh = chk_proxy->oh; + HDassert(oh); + HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(oh->cache_info.type == H5AC_OHDR); + +#ifdef H5_HAVE_PARALLEL + if((chk_proxy->oh->cache_info.is_dirty) && (!about_to_destroy)) + if(H5O__chunk_serialize(f, chk_proxy->oh, chk_proxy->chunkno) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize object header chunk") +#endif /* H5_HAVE_PARALLEL */ + + /* Mark messages in chunk as clean */ + for(u = 0; u < chk_proxy->oh->nmesgs; u++) + if(chk_proxy->oh->mesg[u].chunkno == chk_proxy->chunkno) + chk_proxy->oh->mesg[u].dirty = FALSE; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__cache_chk_clear() */ - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5O_cache_chk_size() */ /*------------------------------------------------------------------------- @@ -1208,7 +1283,7 @@ static herr_t H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image, H5O_common_cache_ud_t *udata, hbool_t *dirty) { - const uint8_t *p; /* Pointer into buffer to decode */ + const uint8_t *chunk_image; /* Pointer into buffer to decode */ uint8_t *eom_ptr; /* Pointer to end of messages for a chunk */ size_t curmesg; /* Current message being decoded in object header */ unsigned merged_null_msgs = 0; /* Number of null messages merged together */ @@ -1257,18 +1332,18 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image HDmemcpy(oh->chunk[chunkno].image, image, oh->chunk[chunkno].size); /* Point into chunk image to decode */ - p = oh->chunk[chunkno].image; + chunk_image = oh->chunk[chunkno].image; /* Handle chunk 0 as special case */ if(chunkno == 0) /* Skip over [already decoded] prefix */ - p += (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)); + chunk_image += (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)); /* Check for magic # on chunks > 0 in later versions of the format */ else if(chunkno > 0 && oh->version > H5O_VERSION_1) { /* Magic number */ - if(HDmemcmp(p, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(chunk_image, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "wrong object header chunk signature") - p += H5_SIZEOF_MAGIC; + chunk_image += H5_SIZEOF_MAGIC; } /* end if */ /* Save # of messages already inspected */ @@ -1279,7 +1354,7 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image #ifndef NDEBUG nullcnt = 0; #endif /* NDEBUG */ - while(p < eom_ptr) { + while(chunk_image < eom_ptr) { size_t mesgno; /* Current message to operate on */ size_t mesg_size; /* Size of message read in */ unsigned id; /* ID (type) of current message */ @@ -1290,20 +1365,20 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image /* Version # */ if(oh->version == H5O_VERSION_1) - UINT16DECODE(p, id) + UINT16DECODE(chunk_image, id) else - id = *p++; + id = *chunk_image++; /* Check for unknown message ID getting encoded in file */ if(id == H5O_UNKNOWN_ID) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "'unknown' message ID encoded in file?!?") /* Message size */ - UINT16DECODE(p, mesg_size); + UINT16DECODE(chunk_image, mesg_size); HDassert(mesg_size == H5O_ALIGN_OH(oh, mesg_size)); /* Message flags */ - flags = *p++; + flags = *chunk_image++; if(flags & ~H5O_MSG_FLAG_BITS) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unknown flag for message") if((flags & H5O_MSG_FLAG_SHARED) && (flags & H5O_MSG_FLAG_DONTSHARE)) @@ -1315,17 +1390,17 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image /* Reserved bytes/creation index */ if(oh->version == H5O_VERSION_1) - p += 3; /*reserved*/ + chunk_image += 3; /*reserved*/ else { /* Only decode creation index if they are being tracked */ if(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) - UINT16DECODE(p, crt_idx); + UINT16DECODE(chunk_image, crt_idx); } /* end else */ /* Try to detect invalidly formatted object header message that * extends past end of chunk. */ - if(p + mesg_size > eom_ptr) + if(chunk_image + mesg_size > eom_ptr) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "corrupt object header") #ifndef NDEBUG @@ -1361,7 +1436,7 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image oh->mesg[mesgno].flags = flags; oh->mesg[mesgno].crt_idx = crt_idx; oh->mesg[mesgno].native = NULL; - oh->mesg[mesgno].raw = (uint8_t *)p; /* Casting away const OK - QAK */ + oh->mesg[mesgno].raw = (uint8_t *)chunk_image; /* Casting away const OK - QAK */ oh->mesg[mesgno].raw_size = mesg_size; oh->mesg[mesgno].chunkno = chunkno; @@ -1417,10 +1492,10 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image } /* end else */ /* Advance decode pointer past message */ - p += mesg_size; + chunk_image += mesg_size; /* Check for 'gap' at end of chunk */ - if((eom_ptr - p) > 0 && (eom_ptr - p) < H5O_SIZEOF_MSGHDR_OH(oh)) { + if((eom_ptr - chunk_image) > 0 && (eom_ptr - chunk_image) < H5O_SIZEOF_MSGHDR_OH(oh)) { /* Gaps can only occur in later versions of the format */ HDassert(oh->version > H5O_VERSION_1); @@ -1428,31 +1503,26 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image HDassert(nullcnt == 0); /* Set gap information for chunk */ - oh->chunk[chunkno].gap = (size_t)(eom_ptr - p); + oh->chunk[chunkno].gap = (size_t)(eom_ptr - chunk_image); /* Increment location in chunk */ - p += oh->chunk[chunkno].gap; + chunk_image += oh->chunk[chunkno].gap; } /* end if */ } /* end while */ /* Check for correct checksum on chunks, in later versions of the format */ if(oh->version > H5O_VERSION_1) { uint32_t stored_chksum; /* Checksum from file */ - uint32_t computed_chksum; /* Checksum computed in memory */ - /* Metadata checksum */ - UINT32DECODE(p, stored_chksum); + /* checksum verification already done in verify_chksum cb */ - /* Compute checksum on chunk */ - computed_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0); + /* Metadata checksum */ + UINT32DECODE(chunk_image, stored_chksum); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "incorrect metadata checksum for object header chunk") } /* end if */ /* Sanity check */ - HDassert(p == oh->chunk[chunkno].image + oh->chunk[chunkno].size); + HDassert(chunk_image == oh->chunk[chunkno].image + oh->chunk[chunkno].size); /* Do some inspection/interpretation of new messages from this chunk */ /* (detect continuation messages, ref. count messages, etc.) */ @@ -1574,7 +1644,7 @@ H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno) /* Extra work, for later versions of the format */ if(oh->version > H5O_VERSION_1) { uint32_t metadata_chksum; /* Computed metadata checksum value */ - uint8_t *p; /* Pointer into object header chunk */ + uint8_t *chunk_image; /* Pointer into object header chunk */ /* Check for gap in chunk & zero it out */ if(oh->chunk[chunkno].gap) @@ -1585,8 +1655,8 @@ H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno) metadata_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0); /* Metadata checksum */ - p = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM); - UINT32ENCODE(p, metadata_chksum); + chunk_image = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM); + UINT32ENCODE(chunk_image, metadata_chksum); } /* end if */ done: @@ -1627,5 +1697,4 @@ H5O__chunk_proxy_dest(H5O_chunk_proxy_t *chk_proxy) done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_chunk_proxy_dest() */ - +} /* H5O__chunk_proxy_dest() */ diff --git a/src/H5Ochunk.c b/src/H5Ochunk.c index 8b380b2..2d025e7 100644 --- a/src/H5Ochunk.c +++ b/src/H5Ochunk.c @@ -189,7 +189,7 @@ H5O_chunk_protect(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx) chk_udata.size = oh->chunk[idx].size; /* Get the chunk proxy */ - if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, &chk_udata, H5AC_WRITE))) + if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, &chk_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header chunk") /* Sanity check */ @@ -342,7 +342,7 @@ H5O_chunk_update_idx(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx) chk_udata.size = oh->chunk[idx].size; /* Get the chunk proxy */ - if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, &chk_udata, H5AC_WRITE))) + if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, &chk_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") /* Update index for chunk proxy in cache */ @@ -395,7 +395,7 @@ H5O_chunk_delete(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx) chk_udata.size = oh->chunk[idx].size; /* Get the chunk proxy */ - if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, &chk_udata, H5AC_WRITE))) + if(NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, &chk_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") /* Sanity check */ diff --git a/src/H5Ocopy.c b/src/H5Ocopy.c index 1c8c301..a315842 100644 --- a/src/H5Ocopy.c +++ b/src/H5Ocopy.c @@ -392,7 +392,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/, } /* Get source object header */ - if(NULL == (oh_src = H5O_protect(oloc_src, dxpl_id, H5AC_READ))) + if(NULL == (oh_src = H5O_protect(oloc_src, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Retrieve user data for particular type of object to copy */ diff --git a/src/H5Odbg.c b/src/H5Odbg.c index 0531a90..0388cd5 100644 --- a/src/H5Odbg.c +++ b/src/H5Odbg.c @@ -566,7 +566,7 @@ H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int f loc.addr = addr; loc.holding_file = FALSE; - if(NULL == (oh = H5O_protect(&loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(&loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* debug */ diff --git a/src/H5Oefl.c b/src/H5Oefl.c index aa2b847..7337c75 100644 --- a/src/H5Oefl.c +++ b/src/H5Oefl.c @@ -128,7 +128,7 @@ H5O_efl_decode(H5F_t *f, hid_t dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh, #ifndef NDEBUG HDassert(H5F_addr_defined(mesg->heap_addr)); - if(NULL == (heap = H5HL_protect(f, dxpl_id, mesg->heap_addr, H5AC_READ))) + if(NULL == (heap = H5HL_protect(f, dxpl_id, mesg->heap_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "unable to read protect link value") s = (const char *)H5HL_offset_into(heap, 0); @@ -145,7 +145,7 @@ H5O_efl_decode(H5F_t *f, hid_t dxpl_id, H5O_t H5_ATTR_UNUSED *open_oh, if(NULL == mesg->slot) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - if(NULL == (heap = H5HL_protect(f, dxpl_id, mesg->heap_addr, H5AC_READ))) + if(NULL == (heap = H5HL_protect(f, dxpl_id, mesg->heap_addr, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, NULL, "unable to read protect link value") for(u = 0; u < mesg->nused; u++) { /* Name */ @@ -487,7 +487,7 @@ H5O_efl_copy_file(H5F_t H5_ATTR_UNUSED *file_src, void *mesg_src, H5F_t *file_ds HGOTO_ERROR(H5E_EFL, H5E_CANTINIT, NULL, "can't create heap") /* Pin the heap down in memory */ - if(NULL == (heap = H5HL_protect(file_dst, dxpl_id, efl_dst->heap_addr, H5AC_WRITE))) + if(NULL == (heap = H5HL_protect(file_dst, dxpl_id, efl_dst->heap_addr, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_EFL, H5E_PROTECT, NULL, "unable to protect EFL file name heap") /* Insert "empty" name first */ diff --git a/src/H5Oflush.c b/src/H5Oflush.c index ee2996e..b051b6a 100644 --- a/src/H5Oflush.c +++ b/src/H5Oflush.c @@ -159,7 +159,7 @@ H5O_oh_tag(const H5O_loc_t *oloc, hid_t dxpl_id, haddr_t *tag) HDassert(oloc); /* Get object header for object */ - if(NULL == (oh = H5O_protect(oloc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(oloc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object's object header") /* Get object header's address (i.e. the tag value for this object) */ diff --git a/src/H5Omessage.c b/src/H5Omessage.c index d361194..c2756ea 100644 --- a/src/H5Omessage.c +++ b/src/H5Omessage.c @@ -476,7 +476,7 @@ H5O_msg_read(const H5O_loc_t *loc, unsigned type_id, void *mesg, HDassert(type_id < NELMTS(H5O_msg_class_g)); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header") /* Call the "real" read routine */ @@ -802,7 +802,7 @@ H5O_msg_count(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id) HDassert(type); /* Load the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header") /* Count the messages of the correct type */ @@ -884,7 +884,7 @@ H5O_msg_exists(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id) HDassert(type_id < NELMTS(H5O_msg_class_g)); /* Load the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header") /* Call the "real" exists routine */ @@ -1224,7 +1224,7 @@ H5O_msg_iterate(const H5O_loc_t *loc, unsigned type_id, HDassert(op); /* Protect the object header to iterate over */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header") /* Call the "real" iterate routine */ @@ -2289,7 +2289,7 @@ H5O_msg_get_chunkno(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id) HDassert(type); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header") /* Locate message of correct type */ @@ -2344,7 +2344,7 @@ H5O_msg_lock(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id) HDassert(type); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header") /* Locate message of correct type */ @@ -2402,7 +2402,7 @@ H5O_msg_unlock(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id) HDassert(type); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header") /* Locate message of correct type */ diff --git a/src/H5Opkg.h b/src/H5Opkg.h index e6b7c03..af9c320 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -365,6 +365,9 @@ typedef struct H5O_common_cache_ud_t { typedef struct H5O_cache_ud_t { hbool_t made_attempt; /* Whether the deserialize routine was already attempted */ unsigned v1_pfx_nmesgs; /* Number of messages from v1 prefix header */ + uint8_t version; /* Version number obtained in get_load_size callback. + * It will be used later in verify_chksum callback + */ H5O_common_cache_ud_t common; /* Common object header cache callback info */ } H5O_cache_ud_t; @@ -396,6 +399,11 @@ struct H5O_proxy_t { H5O_t *oh; /* Object header */ }; +/* Callback information for loading object header proxy */ +typedef struct H5O_proxy_cache_ud_t { + H5F_t *f; /* Pointer to file for object header/chunk */ + H5O_t *oh; /* Object header for this chunk */ +} H5O_proxy_cache_ud_t; /* H5O object header inherits cache-like properties from H5AC */ H5_DLLVAR const H5AC_class_t H5AC_OHDR[1]; diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 1d79ab5..3fb1295 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -659,6 +659,8 @@ typedef struct H5O_btreek_t { * (Data structure in memory) */ typedef struct H5O_drvinfo_t { +/* Information for H5AC cache functions, _must_ be first field in structure */ + H5AC_info_t cache_info; char name[9]; /* Driver name */ size_t len; /* Length of encoded buffer */ uint8_t *buf; /* Buffer for encoded info */ @@ -754,7 +756,7 @@ H5_DLL herr_t H5O_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, H5_DLL herr_t H5O_open(H5O_loc_t *loc); H5_DLL herr_t H5O_close(H5O_loc_t *loc); H5_DLL int H5O_link(const H5O_loc_t *loc, int adjust, hid_t dxpl_id); -H5_DLL H5O_t *H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, H5AC_protect_t prot); +H5_DLL H5O_t *H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, unsigned prot_flags); H5_DLL H5O_t *H5O_pin(const H5O_loc_t *loc, hid_t dxpl_id); H5_DLL herr_t H5O_unpin(H5O_t *oh); H5_DLL herr_t H5O_dec_rc_by_loc(const H5O_loc_t *loc, hid_t dxpl_id); diff --git a/src/H5Oproxy.c b/src/H5Oproxy.c index 9e38524..3675ba3 100644 --- a/src/H5Oproxy.c +++ b/src/H5Oproxy.c @@ -71,32 +71,36 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static H5O_proxy_t *H5O_cache_proxy_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, - void *udata); -static herr_t H5O_cache_proxy_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, - haddr_t addr, H5O_proxy_t *proxy, unsigned *flags_ptr); -static herr_t H5O_cache_proxy_dest(H5F_t *f, H5O_proxy_t *proxy); -static herr_t H5O_cache_proxy_clear(H5F_t *f, H5O_proxy_t *proxy, - hbool_t destroy); -static herr_t H5O_cache_proxy_notify(H5AC_notify_action_t action, - H5O_proxy_t *proxy); -static herr_t H5O_cache_proxy_size(const H5F_t *f, const H5O_proxy_t *proxy, - size_t *size_ptr); +static herr_t H5O__cache_proxy_get_load_size(const void *image, const void *udata, + size_t *image_len, size_t *actual_len); +static void *H5O__cache_proxy_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); +static herr_t H5O__cache_proxy_image_len(const void *thing, size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5O__cache_proxy_serialize(const H5F_t *f, void *image, size_t len, void *thing); +static herr_t H5O__cache_proxy_notify(H5AC_notify_action_t action, void *thing); +static herr_t H5O__cache_proxy_free_icr(void *thing); +static herr_t H5O__cache_proxy_dest(H5O_proxy_t *proxy); /*********************/ /* Package Variables */ /*********************/ -/* H5O proxy inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_OHDR_PROXY[1] = {{ - H5AC_OHDR_PROXY_ID, - (H5AC_load_func_t)H5O_cache_proxy_load, - (H5AC_flush_func_t)H5O_cache_proxy_flush, - (H5AC_dest_func_t)H5O_cache_proxy_dest, - (H5AC_clear_func_t)H5O_cache_proxy_clear, - (H5AC_notify_func_t)H5O_cache_proxy_notify, - (H5AC_size_func_t)H5O_cache_proxy_size, + H5AC_OHDR_PROXY_ID, /* Metadata client ID */ + "Object header proxy", /* Metadata client name (for debugging) */ + H5FD_MEM_OHDR, /* File space memory type for client */ + H5AC__CLASS_SKIP_READS|H5AC__CLASS_SKIP_WRITES, /* Client class behavior flags */ + H5O__cache_proxy_get_load_size, /* 'get_load_size' callback */ + NULL, /* 'verify_chksum' callback */ + H5O__cache_proxy_deserialize, /* 'deserialize' callback */ + H5O__cache_proxy_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5O__cache_proxy_serialize, /* 'serialize' callback */ + H5O__cache_proxy_notify, /* 'notify' callback */ + H5O__cache_proxy_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -115,170 +119,166 @@ H5FL_DEFINE_STATIC(H5O_proxy_t); /*------------------------------------------------------------------------- - * Function: H5O_cache_proxy_load + * Function: H5O__cache_proxy_get_load_size * - * Purpose: Creates an object header proxy and creates flush - * dependencies from all object header chunks on this proxy. + * Purpose: Compute the size of the data structure on disk. * - * Return: Success: Pointer to a new object header proxy - * Failure: NULL + * Return: Non-negative on success/Negative on failure * - * Programmer: Neil Fortner - * Mar 15 2012 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * May 18, 2010 * *------------------------------------------------------------------------- */ -static H5O_proxy_t * -H5O_cache_proxy_load(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, void *udata) +static herr_t +H5O__cache_proxy_get_load_size(const void *_image, const void H5_ATTR_UNUSED *_udata, + size_t *image_len, size_t H5_ATTR_UNUSED *actual_len) { - H5O_t *oh = (H5O_t *)udata; /* Parent object header */ - H5O_proxy_t *proxy = NULL; /* Object header proxy */ - H5O_proxy_t *ret_value; /* Return value */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata); - HDassert(oh->proxy_addr == addr); + /* Check arguments */ + HDassert(image_len); - /* Create object header proxy object & initialize fields */ - if(NULL == (proxy = H5FL_CALLOC(H5O_proxy_t))) - HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "can't allocate object header proxy") - proxy->f = f; - proxy->oh = oh; + if(image == NULL) { + /* Set the image length size */ + /* Object header proxies are represented as 1 byte in cache */ + /* (would be 0 bytes, but cache won't allow it currently. See + * H5D_cache_proxy_size) */ + *image_len = 1; + } + /* Nothing to do for non-NULL image: no need to compute actual_len */ - /* Set return value */ - ret_value = proxy; - proxy = NULL; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_cache_proxy_load() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O__cache_proxy_get_load_size() */ /*------------------------------------------------------------------------- - * Function: H5O_cache_proxy_flush + * Function: H5O__cache_proxy_deserialize * - * Purpose: Flush callback for object header proxies. Does nothing - * except destroy the object if requested. + * Purpose: Creates an object header proxy and creates flush + * dependencies from all object header chunks on this proxy. * - * Return: Non-negative on success/Negative on failure + * Return: Success: Pointer to a new object header proxy + * Failure: NULL * * Programmer: Neil Fortner * Mar 15 2012 * *------------------------------------------------------------------------- */ -static herr_t -H5O_cache_proxy_flush(H5F_t *f, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t destroy, - haddr_t addr, H5O_proxy_t *proxy, unsigned H5_ATTR_UNUSED *flags_ptr) +static void * +H5O__cache_proxy_deserialize(const void H5_ATTR_UNUSED *_image, size_t H5_ATTR_UNUSED len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { - herr_t ret_value = SUCCEED; /* Return value */ + H5O_proxy_t *proxy = NULL; /* Object header proxy */ + H5O_proxy_cache_ud_t *udata = (H5O_proxy_cache_ud_t *)_udata; /* User data for callback */ + H5O_proxy_t *ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(proxy); + HDassert(udata); - /* The dirty flag should not be set */ - HDassert(!proxy->cache_info.is_dirty); + /* Create object header proxy object & initialize fields */ + if(NULL == (proxy = H5FL_MALLOC(H5O_proxy_t))) + HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "can't allocate object header proxy") + HDmemset(&proxy->cache_info, 0, sizeof(H5AC_info_t)); - if(destroy) - if(H5O_cache_proxy_dest(f, proxy) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header proxy") + proxy->f = udata->f; + proxy->oh = udata->oh; + + /* Set return value */ + ret_value = proxy; done: + if(!ret_value && proxy) + if(H5O__cache_proxy_dest(proxy) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, NULL, "unable to destroy object header proxy") + FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_cache_proxy_flush() */ +} /* end H5O__cache_proxy_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5O_cache_proxy_dest + * Function: H5B2__cache_hdr_image_len * - * Purpose: Destroys an object header proxy in memory. + * Purpose: Compute the size of the data structure on disk. * * Return: Non-negative on success/Negative on failure * - * Programmer: Neil Fortner - * Mar 15 2012 + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * May 20, 2010 * *------------------------------------------------------------------------- */ static herr_t -H5O_cache_proxy_dest(H5F_t H5_ATTR_UNUSED *f, H5O_proxy_t *proxy) +H5O__cache_proxy_image_len(const void H5_ATTR_UNUSED *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + FUNC_ENTER_STATIC_NOERR - FUNC_ENTER_NOAPI_NOINIT_NOERR + /* Check arguments */ + HDassert(image_len); - HDassert(proxy); - HDassert(proxy->oh); - - /* Free the object header proxy object */ - proxy = H5FL_FREE(H5O_proxy_t, proxy); + /* Set the image length size */ + /* Object header proxies are represented as 1 byte in cache */ + /* (would be 0 bytes, but cache won't allow it currently. See + * H5D_cache_proxy_size) */ + *image_len = 1; - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_cache_proxy_dest() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O__cache_proxy_image_len() */ /*------------------------------------------------------------------------- - * Function: H5O_cache_proxy_clear + * Function: H5O__cache_proxy_serialize * - * Purpose: Clear callback for object header proxies. Does nothing - * except destroy the object if requested. + * Purpose: A no-op * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Neil Fortner - * Mar 15 2012 + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Feb 2 2005 * *------------------------------------------------------------------------- */ static herr_t -H5O_cache_proxy_clear(H5F_t *f, H5O_proxy_t *proxy, hbool_t destroy) +H5O__cache_proxy_serialize(const H5F_t H5_ATTR_UNUSED *f, void H5_ATTR_UNUSED *_image, size_t H5_ATTR_UNUSED len, + void H5_ATTR_UNUSED *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT - - /* - * Check arguments. - */ - HDassert(proxy); + FUNC_ENTER_STATIC_NOERR - /* The dirty flag should not be set */ - HDassert(!proxy->cache_info.is_dirty); + /* A no-op */ - if(destroy) - if(H5O_cache_proxy_dest(f, proxy) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header proxy") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_cache_proxy_clear() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5O__cache_proxy_serialize() */ /*------------------------------------------------------------------------- - * Function: H5O_cache_proxy_notify + * Function: H5O__cache_proxy_notify * * Purpose: Handle cache action notifications * * Return: Non-negative on success/Negative on failure * * Programmer: Neil Fortner - * Mar 20 2012 + * nfortne2@hdfgroup.org + * Apr 25 2012 * *------------------------------------------------------------------------- */ static herr_t -H5O_cache_proxy_notify(H5AC_notify_action_t action, H5O_proxy_t *proxy) +H5O__cache_proxy_notify(H5AC_notify_action_t action, void *_thing) { - H5O_chunk_proxy_t *chk_proxy = NULL; /* Object header chunk proxy */ - unsigned i; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ + H5O_proxy_t *proxy = (H5O_proxy_t *)_thing; + H5O_chunk_proxy_t *chk_proxy = NULL; /* Object header chunk proxy */ + unsigned i; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT @@ -292,14 +292,16 @@ H5O_cache_proxy_notify(H5AC_notify_action_t action, H5O_proxy_t *proxy) switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: /* Create flush dependency on object header chunk 0 */ if(H5AC_create_flush_dependency(proxy->oh, proxy) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency") /* Create flush dependencies on all other object header chunks */ - for(i=1; i<proxy->oh->nchunks; i++) { + for(i = 1; i < proxy->oh->nchunks; i++) { if(NULL == (chk_proxy = H5O_chunk_protect(proxy->f, H5AC_ind_dxpl_id, proxy->oh, i))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") +/* same as before, but looks backward...need to check into that..(proxy, chk_proxy) */ if(H5AC_create_flush_dependency(chk_proxy, proxy) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency") if(H5O_chunk_unprotect(proxy->f, H5AC_ind_dxpl_id, chk_proxy, FALSE) < 0) @@ -312,6 +314,10 @@ H5O_cache_proxy_notify(H5AC_notify_action_t action, H5O_proxy_t *proxy) break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: /* Mark proxy as not present on the object header */ proxy->oh->proxy_present = FALSE; @@ -334,16 +340,17 @@ done: } /* end if */ FUNC_LEAVE_NOAPI(ret_value) -} /* end H5O_cache_proxy_notify() */ + +} /* end H5O__cache_proxy_notify() */ /*------------------------------------------------------------------------- - * Function: H5O_cache_proxy_size + * Function: H5O__cache_proxy_free_icr * - * Purpose: Compute the size in bytes of an object header proxy - * on disk, and return it in *size_ptr. + * Purpose: Destroy/release an "in core representation" of a data + * structure * - * Return: 0 (never fails) + * Return: Non-negative on success/Negative on failure * * Programmer: Neil Fortner * Mar 15 2012 @@ -351,21 +358,48 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5O_cache_proxy_size(const H5F_t H5_ATTR_UNUSED *f, - const H5O_proxy_t H5_ATTR_UNUSED *proxy, size_t *size_ptr) +H5O__cache_proxy_free_icr(void *_thing) { + H5O_proxy_t *proxy = (H5O_proxy_t *)_thing; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + if(H5O__cache_proxy_dest(proxy) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header proxy") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O__cache_proxy_free_icr() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_cache_proxy_dest + * + * Purpose: Destroys an object header proxy in memory. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner + * Mar 15 2012 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O__cache_proxy_dest(H5O_proxy_t *proxy) +{ + herr_t ret_value = SUCCEED; /* Return value */ + FUNC_ENTER_NOAPI_NOINIT_NOERR - /* check arguments */ - HDassert(size_ptr); + HDassert(proxy); + HDassert(proxy->oh); - /* Object header proxies are represented as 1 byte in cache */ - /* (would be 0 bytes, but cache won't allow it currently. See - * H5D_cache_proxy_size) */ - *size_ptr = 1; + /* Free the object header proxy object */ + proxy = H5FL_FREE(H5O_proxy_t, proxy); - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5O_cache_proxy_size() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__cache_proxy_dest() */ /*------------------------------------------------------------------------- @@ -425,6 +459,7 @@ H5O_proxy_t * H5O_proxy_pin(H5F_t *f, hid_t dxpl_id, H5O_t *oh) { H5O_proxy_t *proxy = NULL; /* Object header proxy */ + H5O_proxy_cache_ud_t udata; /* User-data for callback */ H5O_proxy_t *ret_value = NULL; /* Return value */ FUNC_ENTER_NOAPI_NOINIT @@ -433,8 +468,10 @@ H5O_proxy_pin(H5F_t *f, hid_t dxpl_id, H5O_t *oh) HDassert(oh); HDassert(H5F_addr_defined(oh->proxy_addr)); + udata.f = f; + udata.oh = oh; /* Protect the object header proxy */ - if(NULL == (proxy = (H5O_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_PROXY, oh->proxy_addr, oh, H5AC_READ))) + if(NULL == (proxy = (H5O_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_PROXY, oh->proxy_addr, &udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header proxy"); /* Unprotect the object header proxy and pin it */ @@ -503,6 +540,7 @@ herr_t H5O_proxy_depend(H5F_t *f, hid_t dxpl_id, H5O_t *oh, void *parent) { H5O_proxy_t *proxy = NULL; /* Object header proxy */ + H5O_proxy_cache_ud_t udata; /* User-data for callback */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT @@ -512,8 +550,10 @@ H5O_proxy_depend(H5F_t *f, hid_t dxpl_id, H5O_t *oh, void *parent) HDassert(H5F_addr_defined(oh->proxy_addr)); HDassert(parent); + udata.f = f; + udata.oh = oh; /* Protect the object header proxy */ - if(NULL == (proxy = (H5O_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_PROXY, oh->proxy_addr, oh, H5AC_READ))) + if(NULL == (proxy = (H5O_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_PROXY, oh->proxy_addr, &udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header proxy"); /* Add the flush dependency on the parent object */ @@ -553,6 +593,7 @@ herr_t H5O_proxy_undepend(H5F_t *f, hid_t dxpl_id, H5O_t *oh, void *parent) { H5O_proxy_t *proxy = NULL; /* Object header proxy */ + H5O_proxy_cache_ud_t udata; /* User-data for callback */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT @@ -562,8 +603,10 @@ H5O_proxy_undepend(H5F_t *f, hid_t dxpl_id, H5O_t *oh, void *parent) HDassert(H5F_addr_defined(oh->proxy_addr)); HDassert(parent); + udata.f = f; + udata.oh = oh; /* Protect the object header proxy */ - if(NULL == (proxy = (H5O_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_PROXY, oh->proxy_addr, oh, H5AC_READ))) + if(NULL == (proxy = (H5O_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_PROXY, oh->proxy_addr, &udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header proxy"); /* Add the flush dependency on the parent object */ diff --git a/src/H5Otest.c b/src/H5Otest.c index 9c1b9d8..66fd092 100644 --- a/src/H5Otest.c +++ b/src/H5Otest.c @@ -108,7 +108,7 @@ H5O_is_attr_dense_test(hid_t oid) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found") /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -174,7 +174,7 @@ H5O_is_attr_empty_test(hid_t oid) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found") /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -276,7 +276,7 @@ H5O_num_attrs_test(hid_t oid, hsize_t *nattrs) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found") /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -380,7 +380,7 @@ H5O_attr_dense_info_test(hid_t oid, hsize_t *name_count, hsize_t *corder_count) H5_BEGIN_TAG(H5AC_ind_dxpl_id, loc->addr, FAIL); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -479,7 +479,7 @@ H5O_check_msg_marked_test(hid_t oid, hbool_t flag_val) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found") /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Locate "unknown" message */ @@ -538,7 +538,7 @@ H5O_expunge_chunks_test(const H5O_loc_t *loc, hid_t dxpl_id) FUNC_ENTER_NOAPI(FAIL) /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_WRITE))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header") /* Safety check */ @@ -598,7 +598,7 @@ H5O_get_rc(const H5O_loc_t *loc, hid_t dxpl_id, unsigned *rc) HDassert(rc); /* Get the object header */ - if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header") /* Save the refcount for the object header */ @@ -358,7 +358,7 @@ H5SM_type_shared(H5F_t *f, unsigned type_id, hid_t dxpl_id) /* Set up user data for callback */ cache_udata.f = f; - if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC_READ))) + if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") } /* end if */ else @@ -412,7 +412,7 @@ H5SM_get_fheap_addr(H5F_t *f, hid_t dxpl_id, unsigned type_id, haddr_t *fheap_ad cache_udata.f = f; /* Look up the master SOHM table */ - if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC_READ))) + if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") /* Look up index for message type */ @@ -831,7 +831,7 @@ H5SM_convert_btree_to_list(H5F_t * f, H5SM_index_header_t * header, hid_t dxpl_i cache_udata.header = header; /* Protect the SOHM list */ - if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, H5AC_WRITE))) + if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM list index") /* Delete the B-tree and have messages copy themselves to the @@ -939,7 +939,7 @@ H5SM_can_share(H5F_t *f, hid_t dxpl_id, H5SM_master_table_t *table, /* Set up user data for callback */ cache_udata.f = f; - if(NULL == (my_table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC_READ))) + if(NULL == (my_table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") } /* end if */ @@ -1071,7 +1071,7 @@ H5SM_try_share(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, unsigned defer_flags, cache_udata.f = f; /* Look up the master SOHM table */ - if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC_WRITE))) + if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") /* "complex" sharing checks */ @@ -1277,7 +1277,7 @@ H5SM_write_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, cache_udata.header = header; /* The index is a list; get it from the cache */ - if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, defer ? H5AC_READ : H5AC_WRITE))) + if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, defer ? H5AC__READ_ONLY_FLAG : H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index") /* See if the message is already in the index and get its location. @@ -1530,7 +1530,7 @@ H5SM_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, H5O_shared_t *sh_mesg) cache_udata.f = f; /* Look up the master SOHM table */ - if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC_WRITE))) + if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") /* Find the correct index and try to delete from it */ @@ -1799,7 +1799,7 @@ H5SM_delete_from_index(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, cache_udata.header = header; /* If the index is stored as a list, get it from the cache */ - if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, H5AC_WRITE))) + if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index") /* Find the message in the list */ @@ -1970,7 +1970,7 @@ H5SM_get_info(const H5O_loc_t *ext_loc, H5P_genplist_t *fc_plist, hid_t dxpl_id) cache_udata.f = f; /* Read the rest of the SOHM table information from the cache */ - if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC_READ))) + if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") /* Get index conversion limits */ @@ -2133,7 +2133,7 @@ H5SM_get_refcount(H5F_t *f, hid_t dxpl_id, unsigned type_id, tbl_cache_udata.f = f; /* Look up the master SOHM table */ - if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &tbl_cache_udata, H5AC_READ))) + if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &tbl_cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") /* Find the correct index and find the message in it */ @@ -2172,7 +2172,7 @@ H5SM_get_refcount(H5F_t *f, hid_t dxpl_id, unsigned type_id, lst_cache_udata.header = header; /* If the index is stored as a list, get it from the cache */ - if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &lst_cache_udata, H5AC_READ))) + if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &lst_cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index") /* Find the message in the list */ @@ -2375,7 +2375,7 @@ H5SM_read_mesg(H5F_t *f, const H5SM_sohm_t *mesg, H5HF_t *fheap, HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, FAIL, "unable to open object header") /* Load the object header from the cache */ - if(NULL == (oh = H5O_protect(&oloc, dxpl_id, H5AC_READ))) + if(NULL == (oh = H5O_protect(&oloc, dxpl_id, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load object header") } /* end if */ else @@ -2530,7 +2530,7 @@ H5SM_table_debug(H5F_t *f, hid_t dxpl_id, haddr_t table_addr, cache_udata.f = f; /* Look up the master SOHM table */ - if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, &cache_udata, H5AC_READ))) + if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") HDfprintf(stream, "%*sShared Message Master Table...\n", indent, ""); @@ -2616,7 +2616,7 @@ H5SM_list_debug(H5F_t *f, hid_t dxpl_id, haddr_t list_addr, cache_udata.header = &header; /* Get the list from the cache */ - if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, list_addr, &cache_udata, H5AC_READ))) + if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, list_addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index") HDfprintf(stream, "%*sShared Message List Index...\n", indent, ""); @@ -2693,7 +2693,7 @@ H5SM_ih_size(H5F_t *f, hid_t dxpl_id, hsize_t *hdr_size, H5_ih_info_t *ih_info) cache_udata.f = f; /* Look up the master SOHM table */ - if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC_READ))) + if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") /* Get SOHM header size */ diff --git a/src/H5SMcache.c b/src/H5SMcache.c index 0a8921a..54c2b41 100644 --- a/src/H5SMcache.c +++ b/src/H5SMcache.c @@ -47,12 +47,6 @@ /* Local Macros */ /****************/ -/* Size of stack buffer for serialized tables */ -#define H5SM_TBL_BUF_SIZE 1024 - -/* Size of stack buffer for serialized list indices */ -#define H5SM_LST_BUF_SIZE 1024 - /******************/ /* Local Typedefs */ @@ -64,16 +58,29 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static H5SM_master_table_t *H5SM_table_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5SM_table_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5SM_master_table_t *table); -static herr_t H5SM_table_dest(H5F_t *f, H5SM_master_table_t* table); -static herr_t H5SM_table_clear(H5F_t *f, H5SM_master_table_t *table, hbool_t destroy); -static herr_t H5SM_table_size(const H5F_t *f, const H5SM_master_table_t *table, size_t *size_ptr); -static H5SM_list_t *H5SM_list_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5SM_list_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5SM_list_t *list); -static herr_t H5SM_list_dest(H5F_t *f, H5SM_list_t* list); -static herr_t H5SM_list_clear(H5F_t *f, H5SM_list_t *list, hbool_t destroy); -static herr_t H5SM_list_size(const H5F_t *f, const H5SM_list_t H5_ATTR_UNUSED *list, size_t *size_ptr); +static herr_t H5SM__cache_table_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5SM__cache_table_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5SM__cache_table_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5SM__cache_table_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5SM__cache_table_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5SM__cache_table_free_icr(void *thing); + +static herr_t H5SM__cache_list_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5SM__cache_list_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5SM__cache_list_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5SM__cache_list_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5SM__cache_list_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5SM__cache_list_free_icr(void *thing); /*********************/ @@ -82,23 +89,37 @@ static herr_t H5SM_list_size(const H5F_t *f, const H5SM_list_t H5_ATTR_UNUSED *l /* H5SM inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_SOHM_TABLE[1] = {{ - H5AC_SOHM_TABLE_ID, - (H5AC_load_func_t)H5SM_table_load, - (H5AC_flush_func_t)H5SM_table_flush, - (H5AC_dest_func_t)H5SM_table_dest, - (H5AC_clear_func_t)H5SM_table_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5SM_table_size, + H5AC_SOHM_TABLE_ID, /* Metadata client ID */ + "shared message table", /* Metadata client name (for debugging) */ + H5FD_MEM_SOHM_TABLE, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5SM__cache_table_get_load_size, /* 'get_load_size' callback */ + H5SM__cache_table_verify_chksum, /* 'verify_chksum' callback */ + H5SM__cache_table_deserialize, /* 'deserialize' callback */ + H5SM__cache_table_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5SM__cache_table_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5SM__cache_table_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; const H5AC_class_t H5AC_SOHM_LIST[1] = {{ - H5AC_SOHM_LIST_ID, - (H5AC_load_func_t)H5SM_list_load, - (H5AC_flush_func_t)H5SM_list_flush, - (H5AC_dest_func_t)H5SM_list_dest, - (H5AC_clear_func_t)H5SM_list_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5SM_list_size, + H5AC_SOHM_LIST_ID, /* Metadata client ID */ + "shared message list", /* Metadata client name (for debugging) */ + H5FD_MEM_SOHM_TABLE, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5SM__cache_list_get_load_size, /* 'get_load_size' callback */ + H5SM__cache_list_verify_chksum, /* 'verify_chksum' callback */ + H5SM__cache_list_deserialize, /* 'deserialize' callback */ + H5SM__cache_list_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5SM__cache_list_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5SM__cache_list_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -114,30 +135,119 @@ const H5AC_class_t H5AC_SOHM_LIST[1] = {{ /*------------------------------------------------------------------------- - * Function: H5SM_table_load + * Function: H5SM__cache_table_get_load_size() + * + * Purpose: Return the size of the master table of Shared Object Header + * Message indexes on disk. As this cache client doesn't use + * speculative reads, this value should be accurate. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 7/28/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5SM__cache_table_get_load_size(const void *_image, void *_udata, + size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + const H5SM_table_cache_ud_t *udata = (const H5SM_table_cache_ud_t *)_udata; /* User data for callback */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(udata); + HDassert(udata->f); + HDassert(image_len); + + if(image == NULL) + *image_len = H5SM_TABLE_SIZE(udata->f); + else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5SM__cache_table_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5SM__cache_table_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +htri_t +H5SM__cache_table_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5SM__cache_table_verify_chksum() */ + + +/*------------------------------------------------------------------------- + * Function: H5SM__cache_table_deserialize * - * Purpose: Loads the master table of Shared Object Header Message - * indexes. + * Purpose: Given a buffer containing the on disk representation of the + * master table of Shared Object Header Message indexes, deserialize + * the table, copy the contents into a newly allocated instance of + * H5SM_master_table_t, and return a pointer to the new instance. * - * Return: Non-negative on success/Negative on failure + * Return: Success: Pointer to in core representation + * Failure: NULL * - * Programmer: James Laird - * November 6, 2006 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ -static H5SM_master_table_t * -H5SM_table_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void H5_ATTR_UNUSED *udata) +static void * +H5SM__cache_table_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { - H5SM_master_table_t *table = NULL; - H5WB_t *wb = NULL; /* Wrapped buffer for table data */ - uint8_t tbl_buf[H5SM_TBL_BUF_SIZE]; /* Buffer for table */ - uint8_t *buf; /* Reading buffer */ - const uint8_t *p; /* Pointer into input buffer */ - size_t u; /* Counter variable for index headers */ - H5SM_master_table_t *ret_value; + H5F_t *f; /* File pointer -- from user data */ + H5SM_master_table_t *table = NULL; /* Shared message table that we deserializing */ + H5SM_table_cache_ud_t *udata = (H5SM_table_cache_ud_t *)_udata; /* Pointer to user data */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into input buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + size_t u; /* Counter variable for index headers */ + void * ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC + + /* Check arguments */ + HDassert(image); + HDassert(len > 0); + HDassert(udata); + HDassert(udata->f); + f = udata->f; + HDassert(dirty); /* Verify that we're reading version 0 of the table; this is the only * version defined so far. @@ -150,35 +260,18 @@ H5SM_table_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void H5_ATTR_UNUSED *udat /* Read number of indexes and version from file superblock */ table->num_indexes = H5F_SOHM_NINDEXES(f); - - HDassert(addr == H5F_SOHM_ADDR(f)); - HDassert(addr != HADDR_UNDEF); HDassert(table->num_indexes > 0); - /* Wrap the local buffer for serialized table info */ - if(NULL == (wb = H5WB_wrap(tbl_buf, sizeof(tbl_buf)))) - HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, NULL, "can't wrap buffer") - /* Compute the size of the SOHM table header on disk. This is the "table" * itself plus each index within the table */ table->table_size = H5SM_TABLE_SIZE(f); - - /* Get a pointer to a buffer that's large enough for serialized table */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, table->table_size))) - HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, NULL, "can't get actual buffer") - - /* Read and validate shared message table from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_SOHM_TABLE, H5AC_SOHM_TABLE_ID, addr, table->table_size, table->table_size, buf) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, NULL, "incorrect metadata checksum for shared message table") - - /* Get temporary pointer to serialized table */ - p = buf; + HDassert(table->table_size == len); /* Check magic number */ - if(HDmemcmp(p, H5SM_TABLE_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, NULL, "bad SOHM table signature") - p += H5_SIZEOF_MAGIC; + if(HDmemcmp(image, H5SM_TABLE_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, NULL, "bad SOHM table signature") + image += H5_SIZEOF_MAGIC; /* Allocate space for the index headers in memory*/ if(NULL == (table->indexes = (H5SM_index_header_t *)H5FL_ARR_MALLOC(H5SM_index_header_t, (size_t)table->num_indexes))) @@ -187,187 +280,213 @@ H5SM_table_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void H5_ATTR_UNUSED *udat /* Read in the index headers */ for(u = 0; u < table->num_indexes; ++u) { /* Verify correct version of index list */ - if(H5SM_LIST_VERSION != *p++) + if(H5SM_LIST_VERSION != *image++) HGOTO_ERROR(H5E_SOHM, H5E_VERSION, NULL, "bad shared message list version number") /* Type of the index (list or B-tree) */ - table->indexes[u].index_type= (H5SM_index_type_t)*p++; + table->indexes[u].index_type= (H5SM_index_type_t)*image++; /* Type of messages in the index */ - UINT16DECODE(p, table->indexes[u].mesg_types); + UINT16DECODE(image, table->indexes[u].mesg_types); /* Minimum size of message to share */ - UINT32DECODE(p, table->indexes[u].min_mesg_size); + UINT32DECODE(image, table->indexes[u].min_mesg_size); /* List cutoff; fewer than this number and index becomes a list */ - UINT16DECODE(p, table->indexes[u].list_max); + UINT16DECODE(image, table->indexes[u].list_max); /* B-tree cutoff; more than this number and index becomes a B-tree */ - UINT16DECODE(p, table->indexes[u].btree_min); + UINT16DECODE(image, table->indexes[u].btree_min); /* Number of messages shared */ - UINT16DECODE(p, table->indexes[u].num_messages); + UINT16DECODE(image, table->indexes[u].num_messages); /* Address of the actual index */ - H5F_addr_decode(f, &p, &(table->indexes[u].index_addr)); + H5F_addr_decode(f, &image, &(table->indexes[u].index_addr)); /* Address of the index's heap */ - H5F_addr_decode(f, &p, &(table->indexes[u].heap_addr)); + H5F_addr_decode(f, &image, &(table->indexes[u].heap_addr)); /* Compute the size of a list index for this SOHM index */ table->indexes[u].list_size = H5SM_LIST_SIZE(f, table->indexes[u].list_max); + table->indexes[u].list_size = H5SM_LIST_SIZE(f, table->indexes[u].list_max); } /* end for */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Read in checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - (const uint8_t *)buf) == (table->table_size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == table->table_size); /* Set return value */ ret_value = table; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_SOHM, H5E_CLOSEERROR, NULL, "can't close wrapped buffer") if(!ret_value && table) if(H5SM_table_free(table) < 0) HDONE_ERROR(H5E_SOHM, H5E_CANTFREE, NULL, "unable to destroy sohm table") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5SM_table_load() */ +} /* end H5SM__cache_table_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5SM_table_flush + * Function: H5SM__cache_table_image_len * - * Purpose: Flushes (and destroys) the table of Shared Object Header - * Message indexes. + * Purpose: Compute the size in bytes of the specified instance of + * H5SM_master_table_t on disk, and return it in *image_len. + * On failure, the value of *image_len is undefined. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: James Laird - * November 6, 2006 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5SM_table_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5SM_master_table_t *table) +H5SM__cache_table_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5WB_t *wb = NULL; /* Wrapped buffer for table data */ - uint8_t tbl_buf[H5SM_TBL_BUF_SIZE]; /* Buffer for table */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5SM_master_table_t *table = (const H5SM_master_table_t *)_thing; /* Shared message table to query */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(table); + HDassert(table->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(table->cache_info.type == H5AC_SOHM_TABLE); + HDassert(image_len); - if(table->cache_info.is_dirty) { - uint8_t *buf; /* Temporary buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - uint32_t computed_chksum; /* Computed metadata checksum value */ - size_t u; /* Counter variable */ + *image_len = table->table_size; - /* Verify that we're writing version 0 of the table; this is the only - * version defined so far. - */ - HDassert(H5F_SOHM_VERS(f) == HDF5_SHAREDHEADER_VERSION); + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5SM__cache_table_image_len() */ - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(tbl_buf, sizeof(tbl_buf)))) - HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "can't wrap buffer") +/***************************************/ +/* no H5SM_cache_table_pre_serialize() */ +/***************************************/ - /* Get a pointer to a buffer that's large enough for serialized table */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, table->table_size))) - HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "can't get actual buffer") + +/*------------------------------------------------------------------------- + * Function: H5SM__cache_table_serialize + * + * Purpose: Serialize the contents of the supplied shared message table, and + * load this data into the supplied buffer. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 7/28/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5SM__cache_table_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) +{ + H5SM_master_table_t *table = (H5SM_master_table_t *)_thing; /* Shared message table to encode */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + size_t u; /* Counter variable */ - /* Get temporary pointer to buffer for serialized table */ - p = buf; + FUNC_ENTER_STATIC_NOERR - /* Encode magic number */ - HDmemcpy(p, H5SM_TABLE_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; + /* Check arguments */ + HDassert(f); + HDassert(image); + HDassert(table); + HDassert(table->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(table->cache_info.type == H5AC_SOHM_TABLE); + HDassert(table->table_size == len); - /* Encode each index header */ - for(u = 0; u < table->num_indexes; ++u) { - /* Version for this list */ - *p++ = H5SM_LIST_VERSION; + /* Verify that we're writing version 0 of the table; this is the only + * version defined so far. + */ + HDassert(H5F_SOHM_VERS(f) == HDF5_SHAREDHEADER_VERSION); - /* Is message index a list or a B-tree? */ - *p++ = table->indexes[u].index_type; + /* Encode magic number */ + HDmemcpy(image, H5SM_TABLE_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Type of messages in the index */ - UINT16ENCODE(p, table->indexes[u].mesg_types); + /* Encode each index header */ + for(u = 0; u < table->num_indexes; ++u) { + /* Version for this list */ + *image++ = H5SM_LIST_VERSION; - /* Minimum size of message to share */ - UINT32ENCODE(p, table->indexes[u].min_mesg_size); + /* Is message index a list or a B-tree? */ + *image++ = table->indexes[u].index_type; - /* List cutoff; fewer than this number and index becomes a list */ - UINT16ENCODE(p, table->indexes[u].list_max); + /* Type of messages in the index */ + UINT16ENCODE(image, table->indexes[u].mesg_types); - /* B-tree cutoff; more than this number and index becomes a B-tree */ - UINT16ENCODE(p, table->indexes[u].btree_min); + /* Minimum size of message to share */ + UINT32ENCODE(image, table->indexes[u].min_mesg_size); - /* Number of messages shared */ - UINT16ENCODE(p, table->indexes[u].num_messages); + /* List cutoff; fewer than this number and index becomes a list */ + UINT16ENCODE(image, table->indexes[u].list_max); - /* Address of the actual index */ - H5F_addr_encode(f, &p, table->indexes[u].index_addr); + /* B-tree cutoff; more than this number and index becomes a B-tree */ + UINT16ENCODE(image, table->indexes[u].btree_min); - /* Address of the index's heap */ - H5F_addr_encode(f, &p, table->indexes[u].heap_addr); - } /* end for */ + /* Number of messages shared */ + UINT16ENCODE(image, table->indexes[u].num_messages); - /* Compute checksum on buffer */ - computed_chksum = H5_checksum_metadata(buf, (table->table_size - H5SM_SIZEOF_CHECKSUM), 0); - UINT32ENCODE(p, computed_chksum); + /* Address of the actual index */ + H5F_addr_encode(f, &image, table->indexes[u].index_addr); - /* Write the table to disk */ - HDassert((size_t)(p - buf) == table->table_size); - if(H5F_block_write(f, H5FD_MEM_SOHM_TABLE, addr, table->table_size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_CANTFLUSH, FAIL, "unable to save sohm table to disk") + /* Address of the index's heap */ + H5F_addr_encode(f, &image, table->indexes[u].heap_addr); + } /* end for */ - table->cache_info.is_dirty = FALSE; - } /* end if */ + /* Compute checksum on buffer */ + computed_chksum = H5_checksum_metadata(_image, (table->table_size - H5SM_SIZEOF_CHECKSUM), 0); + UINT32ENCODE(image, computed_chksum); - if(destroy) - if(H5SM_table_dest(f, table) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_CANTFREE, FAIL, "unable to destroy sohm table") + /* sanity check */ + HDassert((size_t)(image - ((uint8_t *)_image)) == table->table_size); -done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_SOHM, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5SM__cache_table_serialize() */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5SM_table_flush() */ +/*****************************************/ +/* no H5SM_cache_table_notify() function */ +/*****************************************/ /*------------------------------------------------------------------------- - * Function: H5SM_table_dest + * Function: H5SM__cache_table_free_icr + * + * Purpose: Free memory used by the SOHM table. * - * Purpose: Frees memory used by the SOHM table. + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: James Laird - * November 6, 2006 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5SM_table_dest(H5F_t H5_ATTR_UNUSED *f, H5SM_master_table_t* table) +H5SM__cache_table_free_icr(void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5SM_master_table_t *table = (H5SM_master_table_t *)_thing; /* Shared message table to release */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check arguments */ HDassert(table); - HDassert(table->indexes); + HDassert(table->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(table->cache_info.type == H5AC_SOHM_TABLE); /* Destroy Shared Object Header Message table */ if(H5SM_table_free(table) < 0) @@ -375,104 +494,129 @@ H5SM_table_dest(H5F_t H5_ATTR_UNUSED *f, H5SM_master_table_t* table) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5SM_table_dest() */ +} /* end H5SM_cache_table_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5SM_table_clear + * Function: H5SM__cache_list_get_load_size() * - * Purpose: Mark this table as no longer being dirty. + * Purpose: Return the on disk size of list of SOHM messages. In this case, + * we simply look up the size in the user data, and return that value + * in *image_len. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: James Laird - * November 6, 2006 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5SM_table_clear(H5F_t *f, H5SM_master_table_t *table, hbool_t destroy) +H5SM__cache_list_get_load_size(const void *_image, void *_udata, + size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + const H5SM_list_cache_ud_t *udata = (const H5SM_list_cache_ud_t *)_udata; /* User data for callback */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* - * Check arguments. - */ - HDassert(table); - - /* Reset the dirty flag. */ - table->cache_info.is_dirty = FALSE; + /* Check arguments */ + HDassert(udata); + HDassert(udata->header); + HDassert(udata->header->list_size > 0); + HDassert(image_len); - if(destroy) - if(H5SM_table_dest(f, table) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_CANTFREE, FAIL, "unable to delete SOHM master table") + if(image == NULL) + *image_len = udata->header->list_size; + else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5SM_table_clear() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5SM__cache_list_get_load_size() */ /*------------------------------------------------------------------------- - * Function: H5SM_table_size + * Function: H5SM__cache_list_verify_chksum * - * Purpose: Returns the size of the table encoded on disk. + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. * - * Return: Non-negative on success/Negative on failure + * Return: Success: TRUE/FALSE + * Failure: Negative * - * Programmer: James Laird - * November 6, 2006 + * Programmer: Vailin Choi; Aug 2015 * *------------------------------------------------------------------------- */ -static herr_t -H5SM_table_size(const H5F_t H5_ATTR_UNUSED *f, const H5SM_master_table_t *table, size_t *size_ptr) +htri_t +H5SM__cache_list_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5SM_list_cache_ud_t *udata = (H5SM_list_cache_ud_t *)_udata; /* User data for callback */ + size_t chk_size; /* Exact size of the node with checksum at the end */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR /* Check arguments */ - HDassert(f); - HDassert(table); - HDassert(size_ptr); + HDassert(image); + HDassert(udata); - /* Set size value */ - *size_ptr = table->table_size; + /* Exact size with checksum at the end */ + chk_size = H5SM_LIST_SIZE(udata->f, udata->header->num_messages); - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5SM_table_size() */ + /* Get stored and computed checksums */ + H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5SM__cache_list_verify_chksum() */ /*------------------------------------------------------------------------- - * Function: H5SM_list_load + * Function: H5SM__cache_list_deserialize * - * Purpose: Loads a list of SOHM messages. + * Purpose: Given a buffer containing the on disk image of a list of + * SOHM message, deserialize the list, load it into a newly allocated + * instance of H5SM_list_t, and return a pointer to same. * - * Return: Non-negative on success/Negative on failure + * Return: Success: Pointer to in core representation + * Failure: NULL * - * Programmer: James Laird - * November 6, 2006 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ -static H5SM_list_t * -H5SM_list_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5SM__cache_list_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { - H5SM_list_t *list; /* The SOHM list being read in */ - H5SM_list_cache_ud_t *udata = (H5SM_list_cache_ud_t *)_udata; /* User data for callback */ - H5SM_bt2_ctx_t ctx; /* Message encoding context */ - H5WB_t *wb = NULL; /* Wrapped buffer for list index data */ - uint8_t lst_buf[H5SM_LST_BUF_SIZE]; /* Buffer for list index */ - uint8_t *buf; /* Reading buffer */ - uint8_t *p; /* Pointer into input buffer */ - size_t u; /* Counter variable for messages in list */ - size_t chk_size; /* Exact size with checksum at the end */ - H5SM_list_t *ret_value; /* Return value */ + H5SM_list_t *list = NULL; /* The SOHM list being read in */ + H5SM_list_cache_ud_t *udata = (H5SM_list_cache_ud_t *)_udata; /* User data for callback */ + H5SM_bt2_ctx_t ctx; /* Message encoding context */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into input buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + size_t u; /* Counter variable for messages in list */ + void * ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check arguments */ + HDassert(image); + HDassert(len > 0); + HDassert(udata); HDassert(udata->header); + HDassert(udata->header->list_size == len); + HDassert(dirty); /* Allocate space for the SOHM list data structure */ if(NULL == (list = H5FL_MALLOC(H5SM_list_t))) @@ -484,41 +628,27 @@ H5SM_list_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, NULL, "file allocation failed for SOHM list") list->header = udata->header; - /* Wrap the local buffer for serialized list index info */ - if(NULL == (wb = H5WB_wrap(lst_buf, sizeof(lst_buf)))) - HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, NULL, "can't wrap buffer") - - /* Get a pointer to a buffer that's large enough for serialized list index */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, udata->header->list_size))) - HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, NULL, "can't get actual buffer") - - /* Exact size with checksum at the end */ - chk_size = H5SM_LIST_SIZE(udata->f, udata->header->num_messages); - - /* Read and validate shared message list from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_SOHM_INDEX, H5AC_SOHM_LIST_ID, addr, udata->header->list_size, chk_size, buf) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, NULL, "incorrect metadata checksum for shared message list") - - /* Get temporary pointer to serialized list index */ - p = buf; - /* Check magic number */ - if(HDmemcmp(p, H5SM_LIST_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + if(HDmemcmp(image, H5SM_LIST_MAGIC, (size_t)H5_SIZEOF_MAGIC)) HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, NULL, "bad SOHM list signature") - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Read messages into the list array */ ctx.sizeof_addr = H5F_SIZEOF_ADDR(udata->f); for(u = 0; u < udata->header->num_messages; u++) { - if(H5SM_message_decode(p, &(list->messages[u]), &ctx) < 0) + if(H5SM_message_decode(image, &(list->messages[u]), &ctx) < 0) HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, NULL, "can't decode shared message") - p += H5SM_SOHM_ENTRY_SIZE(udata->f); + + image += H5SM_SOHM_ENTRY_SIZE(udata->f); } /* end for */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done in verify_chksum cb */ + + /* Read in checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - buf) <= (udata->header->list_size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) <= udata->header->list_size); /* Initialize the rest of the array */ for(u = udata->header->num_messages; u < udata->header->list_max; u++) @@ -528,9 +658,6 @@ H5SM_list_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) ret_value = list; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_SOHM, H5E_CLOSEERROR, NULL, "can't close wrapped buffer") if(!ret_value && list) { if(list->messages) list->messages = H5FL_ARR_FREE(H5SM_sohm_t, list->messages); @@ -538,205 +665,158 @@ done: } /* end if */ FUNC_LEAVE_NOAPI(ret_value) -} /* end H5SM_list_load() */ +} /* end H5SM__cache_list_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5SM_list_flush + * Function: H5SM__cache_list_image_len * - * Purpose: Flush this list index. + * Purpose: Get the size of the shared message list on disk. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: James Laird - * November 6, 2006 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5SM_list_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5SM_list_t *list) +H5SM__cache_list_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5WB_t *wb = NULL; /* Wrapped buffer for list index data */ - uint8_t lst_buf[H5SM_LST_BUF_SIZE]; /* Buffer for list index */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5SM_list_t *list = (const H5SM_list_t *)_thing; /* Shared message list to query */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Check arguments */ HDassert(list); + HDassert(list->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(list->cache_info.type == H5AC_SOHM_LIST); HDassert(list->header); + HDassert(image_len); - if(list->cache_info.is_dirty) { - H5SM_bt2_ctx_t ctx; /* Message encoding context */ - uint8_t *buf; /* Temporary buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - uint32_t computed_chksum; /* Computed metadata checksum value */ - size_t mesgs_written; /* Number of messages written to list */ - size_t u; /* Local index variable */ - - /* Wrap the local buffer for serialized list index info */ - if(NULL == (wb = H5WB_wrap(lst_buf, sizeof(lst_buf)))) - HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "can't wrap buffer") - - /* Get a pointer to a buffer that's large enough for serialized list index */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, list->header->list_size))) - HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "can't get actual buffer") - - /* Get temporary pointer to buffer for serialized list index */ - p = buf; - - /* Encode magic number */ - HDmemcpy(p, H5SM_LIST_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Write messages from the messages array to disk */ - mesgs_written = 0; - ctx.sizeof_addr = H5F_SIZEOF_ADDR(f); - for(u = 0; u < list->header->list_max && mesgs_written < list->header->num_messages; u++) { - if(list->messages[u].location != H5SM_NO_LOC) { - if(H5SM_message_encode(p, &(list->messages[u]), &ctx) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_CANTFLUSH, FAIL, "unable to write shared message to disk") - - p += H5SM_SOHM_ENTRY_SIZE(f); - ++mesgs_written; - } /* end if */ - } /* end for */ - HDassert(mesgs_written == list->header->num_messages); - - /* Compute checksum on buffer */ - computed_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); - UINT32ENCODE(p, computed_chksum); -#ifdef H5_CLEAR_MEMORY -HDmemset(p, 0, (list->header->list_size - (size_t)(p - buf))); -#endif /* H5_CLEAR_MEMORY */ + *image_len = list->header->list_size; - /* Write the list to disk */ - HDassert((size_t)(p - buf) <= list->header->list_size); - if(H5F_block_write(f, H5FD_MEM_SOHM_INDEX, addr, list->header->list_size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_CANTFLUSH, FAIL, "unable to save sohm table to disk") - - list->cache_info.is_dirty = FALSE; - } /* end if */ - - if(destroy) - if(H5SM_list_dest(f, list) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_CANTFREE, FAIL, "unable to destroy list") + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5SM__cache_list_image_len() */ -done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_SOHM, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5SM_list_flush() */ +/**************************************/ +/* no H5SM_cache_list_pre_serialize() */ +/**************************************/ /*------------------------------------------------------------------------- - * Function: H5SM_list_dest + * Function: H5SM__cache_list_serialize * - * Purpose: Frees all memory used by the list. + * Purpose: Serialize the contents of the supplied shared message list, and + * load this data into the supplied buffer. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: James Laird - * November 6, 2006 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5SM_list_dest(H5F_t *f, H5SM_list_t* list) +H5SM__cache_list_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5SM_list_t *list = (H5SM_list_t *)_thing ; /* Instance being serialized */ + H5SM_bt2_ctx_t ctx; /* Message encoding context */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + size_t mesgs_serialized; /* Number of messages serialized */ + size_t u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* Sanity check */ + /* Check arguments */ + HDassert(f); + HDassert(image); HDassert(list); + HDassert(list->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(list->cache_info.type == H5AC_SOHM_LIST); HDassert(list->header); - HDassert(list->messages); + HDassert(list->header->list_size == len); + + /* Encode magic number */ + HDmemcpy(image, H5SM_LIST_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; + + /* serialize messages from the messages array */ + mesgs_serialized = 0; + ctx.sizeof_addr = H5F_SIZEOF_ADDR(f); + for(u = 0; ((u < list->header->list_max) && (mesgs_serialized < list->header->num_messages)); u++) { + if(list->messages[u].location != H5SM_NO_LOC) { + if(H5SM_message_encode(image, &(list->messages[u]), &ctx) < 0) + HGOTO_ERROR(H5E_SOHM, H5E_CANTFLUSH, FAIL, "unable to serialize shared message") + + image += H5SM_SOHM_ENTRY_SIZE(f); + ++mesgs_serialized; + } /* end if */ + } /* end for */ - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!list->cache_info.free_file_space_on_destroy || H5F_addr_defined(list->cache_info.addr)); + HDassert(mesgs_serialized == list->header->num_messages); - /* Check for freeing file space for shared message index list */ - if(list->cache_info.free_file_space_on_destroy) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_SOHM_INDEX, H5AC_dxpl_id, list->cache_info.addr, (hsize_t)list->header->list_size) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "unable to free shared message list") - } /* end if */ + /* Compute checksum on buffer */ + computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); + UINT32ENCODE(image, computed_chksum); - /* Destroy Shared Object Header Message list */ - if(H5SM_list_free(list) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_CANTRELEASE, FAIL, "unable to free shared message list") +#ifdef H5_CLEAR_MEMORY + HDmemset(image, 0, (list->header->list_size - (size_t)(image - (uint8_t *)_image))); +#endif /* H5_CLEAR_MEMORY */ + + /* sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) <= list->header->list_size); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5SM_list_dest() */ +} /* end H5SM__cache_list_serialize() */ + +/****************************************/ +/* no H5SM_cache_list_notify() function */ +/****************************************/ /*------------------------------------------------------------------------- - * Function: H5SM_list_clear + * Function: H5SM__cache_list_free_icr + * + * Purpose: Free all memory used by the list. * - * Purpose: Marks a list as not dirty. + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: James Laird - * November 6, 2006 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5SM_list_clear(H5F_t *f, H5SM_list_t *list, hbool_t destroy) +H5SM__cache_list_free_icr(void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5SM_list_t *list = (H5SM_list_t *)_thing; /* Shared message list to release */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check arguments */ HDassert(list); + HDassert(list->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(list->cache_info.type == H5AC_SOHM_LIST); - /* Reset the dirty flag. */ - list->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5SM_list_dest(f, list) < 0) - HGOTO_ERROR(H5E_SOHM, H5E_CANTFREE, FAIL, "unable to destroy SOHM list") + /* Destroy Shared Object Header Message list */ + if(H5SM_list_free(list) < 0) + HGOTO_ERROR(H5E_SOHM, H5E_CANTRELEASE, FAIL, "unable to free shared message list") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end of H5SM_list_clear() */ - - -/*------------------------------------------------------------------------- - * Function: H5SM_list_size - * - * Purpose: Gets the size of a list on disk. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: James Laird - * November 6, 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5SM_list_size(const H5F_t H5_ATTR_UNUSED *f, const H5SM_list_t *list, size_t *size_ptr) -{ - FUNC_ENTER_NOAPI_NOINIT_NOERR - - /* check arguments */ - HDassert(f); - HDassert(list); - HDassert(list->header); - HDassert(size_ptr); - - /* Set size value */ - *size_ptr = list->header->list_size; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5SM_list_size() */ +} /* end H5O_cache_list_free_icr() */ diff --git a/src/H5SMtest.c b/src/H5SMtest.c index 12ed766..c4e02bc 100644 --- a/src/H5SMtest.c +++ b/src/H5SMtest.c @@ -98,7 +98,7 @@ H5SM_get_mesg_count_test(H5F_t *f, hid_t dxpl_id, unsigned type_id, cache_udata.f = f; /* Look up the master SOHM table */ - if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC_READ))) + if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table") /* Find the correct index for this message type */ |