diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2010-04-15 20:30:48 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2010-04-15 20:30:48 (GMT) |
commit | 80d5ae2fc16e800fbc30008d7771408a40cfdcbf (patch) | |
tree | 8345fd40909d129b14146a027684db235cd28988 | |
parent | 4fa6fd807dddf42e14d2c4c1c40caf11674bb849 (diff) | |
download | hdf5-80d5ae2fc16e800fbc30008d7771408a40cfdcbf.zip hdf5-80d5ae2fc16e800fbc30008d7771408a40cfdcbf.tar.gz hdf5-80d5ae2fc16e800fbc30008d7771408a40cfdcbf.tar.bz2 |
[svn-r18574] Description:
Bring r18571 from trunk to 1.8 branch:
Bring r18542 from metadata journaling "merging" branch to trunk:
Bring new object header pin/unpin & protect/unprotect routines and
split-out object header chunk proxy changes from metadata_journaling branch to
"merging" branch, along with some other minor tweaks to clean up compiler
warnings, etc.
Also: clean up chunk protect/unprotect calls when allocating or freeing
space in a chunk, optimize metadata accumulator code to avoid some re-reading
of information from the file, refactor H5O_pin/H5O_unpin from way they are done
on the merging branch back to way they were previously done on trunk, other
minor code cleanups, etc.
Tested on:
FreeBSD/32 6.3 (duty) in debug mode
FreeBSD/64 6.3 (liberty) w/C++ & FORTRAN, in debug mode
Linux/64-amd64 2.6 (abe) w/parallel, w/FORTRAN, in production mode
(h5committested on trunk)
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | src/H5AC.c | 5 | ||||
-rw-r--r-- | src/H5ACprivate.h | 1 | ||||
-rw-r--r-- | src/H5C.c | 3 | ||||
-rw-r--r-- | src/H5Cpkg.h | 228 | ||||
-rw-r--r-- | src/H5Dint.c | 5 | ||||
-rw-r--r-- | src/H5Doh.c | 2 | ||||
-rw-r--r-- | src/H5FL.c | 2 | ||||
-rw-r--r-- | src/H5Faccum.c | 121 | ||||
-rw-r--r-- | src/H5Ffake.c | 4 | ||||
-rw-r--r-- | src/H5Fsfile.c | 2 | ||||
-rw-r--r-- | src/H5G.c | 7 | ||||
-rw-r--r-- | src/H5Gobj.c | 2 | ||||
-rw-r--r-- | src/H5O.c | 509 | ||||
-rw-r--r-- | src/H5Oalloc.c | 649 | ||||
-rw-r--r-- | src/H5Oattribute.c | 143 | ||||
-rw-r--r-- | src/H5Ocache.c | 1310 | ||||
-rw-r--r-- | src/H5Ochunk.c | 359 | ||||
-rw-r--r-- | src/H5Ocont.c | 9 | ||||
-rw-r--r-- | src/H5Ocopy.c | 5 | ||||
-rw-r--r-- | src/H5Odbg.c | 14 | ||||
-rw-r--r-- | src/H5Omessage.c | 87 | ||||
-rw-r--r-- | src/H5Opkg.h | 72 | ||||
-rw-r--r-- | src/H5Oprivate.h | 7 | ||||
-rw-r--r-- | src/H5Oshared.c | 6 | ||||
-rw-r--r-- | src/H5Otest.c | 81 | ||||
-rw-r--r-- | src/H5R.c | 22 | ||||
-rwxr-xr-x | src/H5SM.c | 5 | ||||
-rwxr-xr-x | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/Makefile.in | 5 | ||||
-rw-r--r-- | test/ohdr.c | 2 |
31 files changed, 2606 insertions, 1064 deletions
@@ -634,6 +634,7 @@ ./src/H5Obogus.c ./src/H5Obtreek.c ./src/H5Ocache.c +./src/H5Ochunk.c ./src/H5Ocont.c ./src/H5Ocopy.c ./src/H5Odbg.c @@ -154,7 +154,7 @@ static herr_t H5AC_log_deleted_entry(H5AC_t * cache_ptr, haddr_t addr, unsigned int flags); -static herr_t H5AC_log_dirtied_entry(const H5C_cache_entry_t *entry_ptr, +static herr_t H5AC_log_dirtied_entry(const H5AC_info_t * entry_ptr, haddr_t addr, hbool_t size_changed, size_t new_size); @@ -482,6 +482,7 @@ static const char * H5AC_entry_type_names[H5AC_NTYPES] = "local heap data blocks", "global heaps", "object headers", + "object header chunks", "v2 B-tree headers", "v2 B-tree internal nodes", "v2 B-tree leaf nodes", @@ -2702,7 +2703,6 @@ herr_t H5AC_validate_config(H5AC_cache_config_t * config_ptr) { herr_t result; - int name_len; H5C_auto_size_ctl_t internal_config; herr_t ret_value = SUCCEED; /* Return value */ @@ -2741,6 +2741,7 @@ H5AC_validate_config(H5AC_cache_config_t * config_ptr) /* don't bother to test trace_file_name unless open_trace_file is TRUE */ if ( config_ptr->open_trace_file ) { + size_t name_len; /* Can't really test the trace_file_name field without trying to * open the file, so we will content ourselves with a couple of diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h index e477416..43a512d 100644 --- a/src/H5ACprivate.h +++ b/src/H5ACprivate.h @@ -49,6 +49,7 @@ typedef enum { H5AC_LHEAP_DBLK_ID, /*local heap data block */ H5AC_GHEAP_ID, /*global heap */ H5AC_OHDR_ID, /*object header */ + H5AC_OHDR_CHK_ID, /*object header chunk */ H5AC_BT2_HDR_ID, /*v2 B-tree header */ H5AC_BT2_INT_ID, /*v2 B-tree internal node */ H5AC_BT2_LEAF_ID, /*v2 B-tree leaf node */ @@ -635,8 +635,7 @@ done: H5SL_close(cache_ptr->slist_ptr); cache_ptr->magic = 0; - (void)H5FL_FREE(H5C_t, cache_ptr); - cache_ptr = NULL; + cache_ptr = H5FL_FREE(H5C_t, cache_ptr); } /* end if */ diff --git a/src/H5Cpkg.h b/src/H5Cpkg.h index f2e023c..d8bf718 100644 --- a/src/H5Cpkg.h +++ b/src/H5Cpkg.h @@ -96,11 +96,11 @@ * * JRM - 9/26/05 * - * magic: Unsigned 32 bit integer always set to H5C__H5C_T_MAGIC. - * This field is used to validate pointers to instances of + * magic: Unsigned 32 bit integer always set to H5C__H5C_T_MAGIC. + * This field is used to validate pointers to instances of * H5C_t. * - * flush_in_progress: Boolean flag indicating whether a flush is in + * flush_in_progress: Boolean flag indicating whether a flush is in * progress. * * trace_file_ptr: File pointer pointing to the trace file, which is used @@ -109,7 +109,7 @@ * no trace file should be recorded. * * Since much of the code supporting the parallel metadata - * cache is in H5AC, we don't write the trace file from + * cache is in H5AC, we don't write the trace file from * H5C. Instead, H5AC reads the trace_file_ptr as needed. * * When we get to using H5C in other places, we may add @@ -182,7 +182,7 @@ * writes. The following field is used to implement this. * * evictions_enabled: Boolean flag that is initialized to TRUE. When - * this flag is set to FALSE, the metadata cache will not + * this flag is set to FALSE, the metadata cache will not * attempt to evict entries to make space for newly protected * entries, and instead the will grow without limit. * @@ -288,7 +288,7 @@ * following two fields have been added. They are only compiled in when * H5C_DO_SANITY_CHECKS is TRUE. * - * slist_len_increase: Number of entries that have been added to the + * slist_len_increase: Number of entries that have been added to the * slist since the last time this field was set to zero. * * slist_size_increase: Total size of all entries that have been added @@ -625,23 +625,23 @@ * equal to the array index has not been in cache when * requested in the current epoch. * - * write_protects: 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 write protected + * write_protects: 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 write protected * in the current epoch. * * Observe that (hits + misses) = (write_protects + read_protects). * - * read_protects: 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 read protected in + * read_protects: 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 read protected in * the current epoch. * * Observe that (hits + misses) = (write_protects + read_protects). * - * max_read_protects: Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1. - * The cells are used to maximum number of simultaneous read - * protects on any entry with type id equal to the array index + * max_read_protects: Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1. + * The cells are used to maximum number of simultaneous read + * protects on any entry with type id equal to the array index * in the current epoch. * * insertions: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells @@ -649,9 +649,9 @@ * id equal to the array index has been inserted into the * cache in the current epoch. * - * pinned_insertions: 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 inserted + * pinned_insertions: 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 inserted * pinned into the cache in the current epoch. * * clears: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. The cells @@ -674,13 +674,13 @@ * id equal to the array index has been renamed in the current * epoch. * - * entry_flush_renames: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. - * The cells are used to record the number of times an entry + * entry_flush_renames: 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 renamed * during its flush callback in the current epoch. * - * cache_flush_renames: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1. - * The cells are used to record the number of times an entry + * cache_flush_renames: 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 renamed * during a cache flush in the current epoch. * @@ -719,14 +719,14 @@ * with type id equal to the array index has decreased in * size in the current epoch. * - * 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 + * 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. * - * cache_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 + * cache_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 during a cache flush * * total_ht_insertions: Number of times entries have been inserted into the @@ -860,7 +860,7 @@ #define H5C__HASH_TABLE_LEN (64 * 1024) /* must be a power of 2 */ #define H5C__H5C_T_MAGIC 0x005CAC0E -#define H5C__MAX_NUM_TYPE_IDS 18 +#define H5C__MAX_NUM_TYPE_IDS 19 #define H5C__PREFIX_LEN 32 struct H5C_t @@ -1449,7 +1449,7 @@ if ( ( (entry_ptr) == NULL ) || \ * More pinned entry stats related updates. * * JRM -- 3/31/07 - * Updated H5C__UPDATE_STATS_FOR_PROTECT() to keep stats on + * Updated H5C__UPDATE_STATS_FOR_PROTECT() to keep stats on * read and write protects. * * MAM -- 1/15/09 @@ -2877,7 +2877,7 @@ if ( (cache_ptr)->index_size != \ (cache_ptr)->pel_tail_ptr, \ (cache_ptr)->pel_len, \ (cache_ptr)->pel_size, (fail_val)) \ - \ + \ } else { \ \ /* modified LRU specific code */ \ @@ -3122,62 +3122,70 @@ if ( (cache_ptr)->index_size != \ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ HDassert( (entry_ptr)->size > 0 ); \ \ - if ( ! ((entry_ptr)->is_pinned) ) { \ - \ + if ( ! ( (entry_ptr)->is_pinned ) ) { \ + \ /* modified LRU specific code */ \ \ /* remove the entry from the LRU list, and re-insert it at the head. \ */ \ \ - H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \ - (cache_ptr)->LRU_tail_ptr, \ - (cache_ptr)->LRU_list_len, \ - (cache_ptr)->LRU_list_size, (fail_val)) \ + H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \ + (cache_ptr)->LRU_tail_ptr, \ + (cache_ptr)->LRU_list_len, \ + (cache_ptr)->LRU_list_size, (fail_val)) \ \ H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \ (cache_ptr)->LRU_tail_ptr, \ (cache_ptr)->LRU_list_len, \ (cache_ptr)->LRU_list_size, (fail_val)) \ \ - /* remove the entry from either the clean or dirty LUR list as \ - * indicated by the was_dirty parameter \ - */ \ - if ( was_dirty ) { \ + /* remove the entry from either the clean or dirty LUR list as \ + * indicated by the was_dirty parameter \ + */ \ + if ( was_dirty ) { \ \ - H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr, \ - (cache_ptr)->dLRU_tail_ptr, \ - (cache_ptr)->dLRU_list_len, \ - (cache_ptr)->dLRU_list_size, (fail_val)) \ + H5C__AUX_DLL_REMOVE((entry_ptr), \ + (cache_ptr)->dLRU_head_ptr, \ + (cache_ptr)->dLRU_tail_ptr, \ + (cache_ptr)->dLRU_list_len, \ + (cache_ptr)->dLRU_list_size, \ + (fail_val)) \ \ - } else { \ + } else { \ \ - H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr, \ - (cache_ptr)->cLRU_tail_ptr, \ - (cache_ptr)->cLRU_list_len, \ - (cache_ptr)->cLRU_list_size, (fail_val)) \ - } \ + H5C__AUX_DLL_REMOVE((entry_ptr), \ + (cache_ptr)->cLRU_head_ptr, \ + (cache_ptr)->cLRU_tail_ptr, \ + (cache_ptr)->cLRU_list_len, \ + (cache_ptr)->cLRU_list_size, \ + (fail_val)) \ + } \ \ - /* insert the entry at the head of either the clean or dirty LRU \ - * list as appropriate. \ - */ \ + /* insert the entry at the head of either the clean or dirty \ + * LRU list as appropriate. \ + */ \ \ - if ( (entry_ptr)->is_dirty ) { \ + if ( (entry_ptr)->is_dirty ) { \ \ - H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr, \ - (cache_ptr)->dLRU_tail_ptr, \ - (cache_ptr)->dLRU_list_len, \ - (cache_ptr)->dLRU_list_size, (fail_val)) \ + H5C__AUX_DLL_PREPEND((entry_ptr), \ + (cache_ptr)->dLRU_head_ptr, \ + (cache_ptr)->dLRU_tail_ptr, \ + (cache_ptr)->dLRU_list_len, \ + (cache_ptr)->dLRU_list_size, \ + (fail_val)) \ \ - } else { \ + } else { \ \ - H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \ - (cache_ptr)->cLRU_tail_ptr, \ - (cache_ptr)->cLRU_list_len, \ - (cache_ptr)->cLRU_list_size, (fail_val)) \ - } \ + H5C__AUX_DLL_PREPEND((entry_ptr), \ + (cache_ptr)->cLRU_head_ptr, \ + (cache_ptr)->cLRU_tail_ptr, \ + (cache_ptr)->cLRU_list_len, \ + (cache_ptr)->cLRU_list_size, \ + (fail_val)) \ + } \ \ - /* End modified LRU specific code. */ \ - } \ + /* End modified LRU specific code. */ \ + } \ } /* H5C__UPDATE_RP_FOR_RENAME */ #else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ @@ -3192,25 +3200,25 @@ if ( (cache_ptr)->index_size != \ HDassert( ((entry_ptr)->ro_ref_count) == 0 ); \ HDassert( (entry_ptr)->size > 0 ); \ \ - if ( ! ((entry_ptr)->is_pinned) ) { \ - \ + if ( ! ( (entry_ptr)->is_pinned ) ) { \ + \ /* modified LRU specific code */ \ \ /* remove the entry from the LRU list, and re-insert it at the head. \ */ \ \ - H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \ - (cache_ptr)->LRU_tail_ptr, \ - (cache_ptr)->LRU_list_len, \ - (cache_ptr)->LRU_list_size, (fail_val)) \ + H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr, \ + (cache_ptr)->LRU_tail_ptr, \ + (cache_ptr)->LRU_list_len, \ + (cache_ptr)->LRU_list_size, (fail_val)) \ \ - H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \ - (cache_ptr)->LRU_tail_ptr, \ - (cache_ptr)->LRU_list_len, \ - (cache_ptr)->LRU_list_size, (fail_val)) \ + H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \ + (cache_ptr)->LRU_tail_ptr, \ + (cache_ptr)->LRU_list_len, \ + (cache_ptr)->LRU_list_size, (fail_val)) \ \ - /* End modified LRU specific code. */ \ - } \ + /* End modified LRU specific code. */ \ + } \ } /* H5C__UPDATE_RP_FOR_RENAME */ #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ @@ -3267,7 +3275,7 @@ if ( (cache_ptr)->index_size != \ (cache_ptr)->pel_size, \ (entry_ptr)->size, \ (new_size)); \ - \ + \ } else { \ \ /* modified LRU specific code */ \ @@ -3393,35 +3401,39 @@ if ( (cache_ptr)->index_size != \ (cache_ptr)->pel_size, (fail_val)) \ HDassert( (cache_ptr)->pel_len >= 0 ); \ \ - /* modified LRU specific code */ \ + /* modified LRU specific code */ \ \ - /* insert the entry at the head of the LRU list. */ \ + /* insert the entry at the head of the LRU list. */ \ \ - H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \ - (cache_ptr)->LRU_tail_ptr, \ - (cache_ptr)->LRU_list_len, \ - (cache_ptr)->LRU_list_size, (fail_val)) \ + H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \ + (cache_ptr)->LRU_tail_ptr, \ + (cache_ptr)->LRU_list_len, \ + (cache_ptr)->LRU_list_size, (fail_val)) \ \ - /* Similarly, insert the entry at the head of either the clean or \ - * dirty LRU list as appropriate. \ - */ \ + /* Similarly, insert the entry at the head of either the clean \ + * or dirty LRU list as appropriate. \ + */ \ \ - if ( (entry_ptr)->is_dirty ) { \ + if ( (entry_ptr)->is_dirty ) { \ \ - H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr, \ - (cache_ptr)->dLRU_tail_ptr, \ - (cache_ptr)->dLRU_list_len, \ - (cache_ptr)->dLRU_list_size, (fail_val)) \ + H5C__AUX_DLL_PREPEND((entry_ptr), \ + (cache_ptr)->dLRU_head_ptr, \ + (cache_ptr)->dLRU_tail_ptr, \ + (cache_ptr)->dLRU_list_len, \ + (cache_ptr)->dLRU_list_size, \ + (fail_val)) \ \ - } else { \ + } else { \ \ - H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr, \ - (cache_ptr)->cLRU_tail_ptr, \ - (cache_ptr)->cLRU_list_len, \ - (cache_ptr)->cLRU_list_size, (fail_val)) \ - } \ + H5C__AUX_DLL_PREPEND((entry_ptr), \ + (cache_ptr)->cLRU_head_ptr, \ + (cache_ptr)->cLRU_tail_ptr, \ + (cache_ptr)->cLRU_list_len, \ + (cache_ptr)->cLRU_list_size, \ + (fail_val)) \ + } \ \ - /* End modified LRU specific code. */ \ + /* End modified LRU specific code. */ \ \ } /* H5C__UPDATE_RP_FOR_UNPIN */ @@ -3446,16 +3458,16 @@ if ( (cache_ptr)->index_size != \ (cache_ptr)->pel_size, (fail_val)) \ HDassert( (cache_ptr)->pel_len >= 0 ); \ \ - /* modified LRU specific code */ \ + /* modified LRU specific code */ \ \ - /* insert the entry at the head of the LRU list. */ \ + /* insert the entry at the head of the LRU list. */ \ \ - H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \ - (cache_ptr)->LRU_tail_ptr, \ - (cache_ptr)->LRU_list_len, \ - (cache_ptr)->LRU_list_size, (fail_val)) \ + H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr, \ + (cache_ptr)->LRU_tail_ptr, \ + (cache_ptr)->LRU_list_len, \ + (cache_ptr)->LRU_list_size, (fail_val)) \ \ - /* End modified LRU specific code. */ \ + /* End modified LRU specific code. */ \ \ } /* H5C__UPDATE_RP_FOR_UNPIN */ diff --git a/src/H5Dint.c b/src/H5Dint.c index d3800e8..72c9079 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -27,7 +27,6 @@ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ -#include "H5ACprivate.h" /* Metadata cache */ #include "H5Dpkg.h" /* Datasets */ #include "H5Eprivate.h" /* Error handling */ #include "H5FLprivate.h" /* Free Lists */ @@ -794,7 +793,7 @@ H5D_update_oh_info(H5F_t *file, hid_t dxpl_id, H5D_t *dset, hid_t dapl_id) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create dataset object header") HDassert(file == dset->oloc.file); - /* Get a pointer to the object header itself */ + /* Pin the object header */ if(NULL == (oh = H5O_pin(oloc, dxpl_id))) HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header") @@ -2261,7 +2260,7 @@ H5D_flush_real(H5D_t *dataset, hid_t dxpl_id) if(dataset->shared->layout_dirty || dataset->shared->space_dirty) { unsigned update_flags = H5O_UPDATE_TIME; /* Modification time flag */ - /* Get a pointer to the dataset's object header */ + /* Pin the object header */ if(NULL == (oh = H5O_pin(&dataset->oloc, dxpl_id))) HGOTO_ERROR(H5E_DATASET, H5E_CANTPIN, FAIL, "unable to pin dataset object header") diff --git a/src/H5Doh.c b/src/H5Doh.c index a6e93da..2585955 100644 --- a/src/H5Doh.c +++ b/src/H5Doh.c @@ -159,7 +159,7 @@ H5O_dset_free_copy_file_udata(void *_udata) H5O_msg_free(H5O_PLINE_ID, udata->common.src_pline); /* Release space for 'copy file' user data */ - (void)H5FL_FREE(H5D_copy_file_ud_t, udata); + udata = H5FL_FREE(H5D_copy_file_ud_t, udata); FUNC_LEAVE_NOAPI_VOID } /* end H5O_dset_free_copy_file_udata() */ @@ -2352,7 +2352,7 @@ H5FL_fac_term(H5FL_fac_head_t *factory) } /* end else */ /* Free factory info */ - (void)H5FL_FREE(H5FL_fac_head_t, factory); + factory = H5FL_FREE(H5FL_fac_head_t, factory); done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Faccum.c b/src/H5Faccum.c index e525a08..426a639 100644 --- a/src/H5Faccum.c +++ b/src/H5Faccum.c @@ -126,68 +126,68 @@ H5F_accum_read(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, /* Check if this information is in the metadata accumulator */ if((f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && type != H5FD_MEM_DRAW && size < H5F_ACCUM_MAX_SIZE) { - /* Current read overlaps with metadata accumulator */ - if(H5F_addr_overlap(addr, size, f->shared->accum.loc, f->shared->accum.size)) { - unsigned char *read_buf = (unsigned char *)buf; /* Pointer to the buffer being read in */ - size_t amount_read; /* Amount to read at a time */ - hsize_t read_off; /* Offset to read from */ + /* Sanity check */ + HDassert(!f->shared->accum.buf || (f->shared->accum.alloc_size >= f->shared->accum.size)); + + /* Current read adjoins or overlaps with metadata accumulator */ + if(H5F_addr_overlap(addr, size, f->shared->accum.loc, f->shared->accum.size) + || ((addr + size) == f->shared->accum.loc) + || (f->shared->accum.loc + f->shared->accum.size) == addr) { + size_t amount_before; /* Amount to read before current accumulator */ + haddr_t new_addr; /* New address of the accumulator buffer */ + size_t new_size; /* New size of the accumulator buffer */ + + /* Compute new values for accumulator */ + new_addr = MIN(addr, f->shared->accum.loc); + new_size = (size_t)(MAX((addr + size), (f->shared->accum.loc + f->shared->accum.size)) + - new_addr); + + /* Check if we need more buffer space */ + if(new_size > f->shared->accum.size) { + /* Adjust the buffer size, by doubling it */ + f->shared->accum.alloc_size = MAX(f->shared->accum.alloc_size * 2, new_size); + + /* Reallocate the metadata accumulator buffer */ + if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, f->shared->accum.alloc_size))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate metadata accumulator buffer") +#ifdef H5_CLEAR_MEMORY +HDmemset(f->shared->accum.buf + f->shared->accum.size, 0, (f->shared->accum.alloc_size - f->shared->accum.size)); +#endif /* H5_CLEAR_MEMORY */ + } /* end if */ /* Read the part before the metadata accumulator */ if(addr < f->shared->accum.loc) { /* Set the amount to read */ - H5_ASSIGN_OVERFLOW(amount_read, (f->shared->accum.loc - addr), hsize_t, size_t); + H5_ASSIGN_OVERFLOW(amount_before, (f->shared->accum.loc - addr), hsize_t, size_t); + + /* Make room for the metadata to read in */ + HDmemmove(f->shared->accum.buf + amount_before, f->shared->accum.buf, f->shared->accum.size); /* Dispatch to driver */ - if(H5FD_read(f->shared->lf, dxpl_id, type, addr, amount_read, read_buf) < 0) + if(H5FD_read(f->shared->lf, dxpl_id, type, addr, amount_before, f->shared->accum.buf) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed") - - /* Adjust the buffer, address & size */ - read_buf += amount_read; - addr += amount_read; - size -= amount_read; } /* end if */ + else + amount_before = 0; - /* Copy the part overlapping the metadata accumulator */ - if(size > 0 && (addr >= f->shared->accum.loc && addr < (f->shared->accum.loc + f->shared->accum.size))) { - /* Set the offset to "read" from */ - read_off = addr - f->shared->accum.loc; - - /* Set the amount to "read" */ -#ifndef NDEBUG -{ - hsize_t tempamount_read; /* Amount to read at a time */ - - tempamount_read = f->shared->accum.size - read_off; - H5_CHECK_OVERFLOW(tempamount_read, hsize_t, size_t); - amount_read = MIN(size, (size_t)tempamount_read); -} -#else /* NDEBUG */ - amount_read = MIN(size, (size_t)(f->shared->accum.size - read_off)); -#endif /* NDEBUG */ - - /* Copy the data out of the buffer */ - HDmemcpy(read_buf, f->shared->accum.buf + read_off, amount_read); + /* Read the part after the metadata accumulator */ + if((addr + size) > (f->shared->accum.loc + f->shared->accum.size)) { + size_t amount_after; /* Amount to read at a time */ - /* Adjust the buffer, address & size */ - read_buf += amount_read; - addr += amount_read; - size -= amount_read; - } /* end if */ + /* Set the amount to read */ + H5_ASSIGN_OVERFLOW(amount_after, ((addr + size) - (f->shared->accum.loc + f->shared->accum.size)), hsize_t, size_t); - /* Read the part after the metadata accumulator */ - if(size > 0 && addr >= (f->shared->accum.loc + f->shared->accum.size)) { /* Dispatch to driver */ - if(H5FD_read(f->shared->lf, dxpl_id, type, addr, size, read_buf) < 0) + if(H5FD_read(f->shared->lf, dxpl_id, type, (f->shared->accum.loc + f->shared->accum.size), amount_after, (f->shared->accum.buf + f->shared->accum.size + amount_before)) < 0) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed") - - /* Adjust the buffer, address & size */ - read_buf += size; - addr += size; - size -= size; } /* end if */ - /* Make certain we've read it all */ - HDassert(size == 0); + /* Copy the data out of the buffer */ + HDmemcpy(buf, f->shared->accum.buf + (addr - new_addr), size); + + /* Adjust the accumulator address & size */ + f->shared->accum.loc = new_addr; + f->shared->accum.size = new_size; } /* end if */ /* Current read doesn't overlap with metadata accumulator, read it from file */ else { @@ -340,6 +340,9 @@ H5F_accum_write(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, /* Check for accumulating metadata */ if((f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && type != H5FD_MEM_DRAW && size < H5F_ACCUM_MAX_SIZE) { + /* Sanity check */ + HDassert(!f->shared->accum.buf || (f->shared->accum.alloc_size >= f->shared->accum.size)); + /* Check if there is already metadata in the accumulator */ if(f->shared->accum.size > 0) { /* Check if the new metadata adjoins the beginning of the current accumulator */ @@ -433,8 +436,30 @@ H5F_accum_write(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, /* Mark it as written to */ f->shared->accum.dirty = TRUE; } /* end if */ + /* New metadata overlaps both ends of the current accumulator */ else { - HDassert(0 && "New metadata overlapped both beginning and end of existing metadata accumulator!"); + /* Check if we need more buffer space */ + if(size > f->shared->accum.size) { + /* Adjust the buffer size, by doubling it */ + f->shared->accum.alloc_size = MAX(f->shared->accum.alloc_size * 2, size); + + /* Reallocate the metadata accumulator buffer */ + if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, f->shared->accum.alloc_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") +#ifdef H5_CLEAR_MEMORY +HDmemset(f->shared->accum.buf + size, 0, (f->shared->accum.alloc_size - size)); +#endif /* H5_CLEAR_MEMORY */ + } /* end if */ + + /* Copy the new metadata to the buffer */ + HDmemcpy(f->shared->accum.buf, buf, size); + + /* Set the new size & location of the metadata accumulator */ + f->shared->accum.loc = addr; + f->shared->accum.size = size; + + /* Mark it as written to */ + f->shared->accum.dirty = TRUE; } /* end else */ } /* end if */ /* New piece of metadata doesn't adjoin or overlap the existing accumulator */ diff --git a/src/H5Ffake.c b/src/H5Ffake.c index e96aedf..f71d373 100644 --- a/src/H5Ffake.c +++ b/src/H5Ffake.c @@ -120,8 +120,8 @@ H5F_fake_free(H5F_t *f) if(f) { /* Destroy shared file struct */ if(f->shared) - f->shared = (H5F_file_t *)H5FL_FREE(H5F_file_t, f->shared); - (void)H5FL_FREE(H5F_t, f); + f->shared = H5FL_FREE(H5F_file_t, f->shared); + f = H5FL_FREE(H5F_t, f); } /* end if */ FUNC_LEAVE_NOAPI(SUCCEED) diff --git a/src/H5Fsfile.c b/src/H5Fsfile.c index 708fbf7..8144986 100644 --- a/src/H5Fsfile.c +++ b/src/H5Fsfile.c @@ -219,7 +219,7 @@ H5F_sfile_remove(H5F_file_t *shared) /* Release the shared file node struct */ /* (the shared file info itself is freed elsewhere) */ - (void)H5FL_FREE(H5F_sfile_node_t, curr); + curr = H5FL_FREE(H5F_sfile_node_t, curr); done: FUNC_LEAVE_NOAPI(ret_value) @@ -1772,8 +1772,7 @@ H5G_visit(hid_t loc_id, const char *group_name, H5_index_t idx_type, H5G_t *grp = NULL; /* Group opened */ H5G_loc_t loc; /* Location of group passed in */ H5G_loc_t start_loc; /* Location of starting group */ - H5O_type_t otype; /* Basic object type (group, dataset, etc.) */ - unsigned rc; /* Reference count of object */ + unsigned rc; /* Reference count of object */ herr_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5G_visit, FAIL) @@ -1814,8 +1813,8 @@ H5G_visit(hid_t loc_id, const char *group_name, H5_index_t idx_type, if((udata.visited = H5SL_create(H5SL_TYPE_OBJ)) == NULL) HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create skip list for visited objects") - /* Get the group's reference count and type */ - if(H5O_get_rc_and_type(&grp->oloc, dxpl_id, &rc, &otype) < 0) + /* Get the group's reference count */ + if(H5O_get_rc_and_type(&grp->oloc, dxpl_id, &rc, NULL) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get object info") /* If its ref count is > 1, we add it to the list of visited objects */ diff --git a/src/H5Gobj.c b/src/H5Gobj.c index 7766280..daad6ae 100644 --- a/src/H5Gobj.c +++ b/src/H5Gobj.c @@ -901,7 +901,7 @@ H5G_obj_remove_update_linfo(H5O_loc_t *oloc, H5O_linfo_t *linfo, hid_t dxpl_id) if(H5G_dense_build_table(oloc->file, dxpl_id, linfo, H5_INDEX_NAME, H5_ITER_NATIVE, <able) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over links") - /* Get a pointer to the object header itself */ + /* Pin the object header */ if(NULL == (oh = H5O_pin(oloc, dxpl_id))) HGOTO_ERROR(H5E_SYM, H5E_CANTPIN, FAIL, "unable to pin group object header") @@ -140,6 +140,9 @@ H5FL_SEQ_DEFINE(H5O_chunk_t); /* Declare a free list to manage the chunk image information */ H5FL_BLK_DEFINE(chunk_image); +/* Declare external the free list for H5O_cont_t sequences */ +H5FL_SEQ_EXTERN(H5O_cont_t); + /*****************************/ /* Library Private Variables */ @@ -1172,7 +1175,7 @@ H5O_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, hid_t ocpl_id, /* Determine correct value for chunk #0 size bits */ /* Avoid compiler warning on 32-bit machines */ #if H5_SIZEOF_SIZE_T > H5_SIZEOF_INT32_T - if(size_hint > 4294967295) + if(size_hint > 4294967295UL) oh->flags |= H5O_HDR_CHUNK0_8; else #endif /* H5_SIZEOF_SIZE_T > H5_SIZEOF_INT32_T */ @@ -1188,7 +1191,7 @@ H5O_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, hid_t ocpl_id, /* Compute total size of initial object header */ /* (i.e. object header prefix and first chunk) */ - oh_size = H5O_SIZEOF_HDR(oh) + size_hint; + oh_size = (size_t)H5O_SIZEOF_HDR(oh) + size_hint; /* Allocate disk space for header and first chunk */ if(HADDR_UNDEF == (oh_addr = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)oh_size))) @@ -1200,7 +1203,6 @@ H5O_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, hid_t ocpl_id, HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Initialize the first chunk */ - oh->chunk[0].dirty = TRUE; oh->chunk[0].addr = oh_addr; oh->chunk[0].size = oh_size; oh->chunk[0].gap = 0; @@ -1456,13 +1458,18 @@ done: *------------------------------------------------------------------------- */ int -H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, unsigned *oh_flags) +H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, hbool_t *deleted) { haddr_t addr = H5O_OH_GET_ADDR(oh); /* Object header address */ int ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_link_oh, FAIL) + /* check args */ + HDassert(f); + HDassert(oh); + HDassert(deleted); + /* Check for adjusting link count */ if(adjust) { if(adjust < 0) { @@ -1474,7 +1481,8 @@ H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, unsigned *oh_flags) oh->nlink += adjust; /* Mark object header as dirty in cache */ - *oh_flags |= H5AC__DIRTIED_FLAG; + if(H5AC_mark_pinned_or_protected_entry_dirty(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty") /* Check if the object should be deleted */ if(oh->nlink == 0) { @@ -1485,12 +1493,8 @@ H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, unsigned *oh_flags) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't mark object for deletion") } /* end if */ else { - /* Delete object right now */ - if(H5O_delete_oh(f, dxpl_id, oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file") - /* Mark the object header for deletion */ - *oh_flags = H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; + *deleted = TRUE; } /* end else */ } /* end if */ } /* end if */ @@ -1509,7 +1513,8 @@ H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, unsigned *oh_flags) oh->nlink += adjust; /* Mark object header as dirty in cache */ - *oh_flags |= H5AC__DIRTIED_FLAG; + if(H5AC_mark_pinned_or_protected_entry_dirty(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty") } /* end if */ /* Check for operations on refcount message */ @@ -1519,7 +1524,7 @@ H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, unsigned *oh_flags) /* Check for removing refcount message */ if(oh->nlink <= 1) { if(H5O_msg_remove_real(f, oh, H5O_MSG_REFCOUNT, H5O_ALL, NULL, NULL, TRUE, dxpl_id) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete refcount message") + HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete refcount message") oh->has_refcount_msg = FALSE; } /* end if */ /* Update refcount message with new link count */ @@ -1527,7 +1532,7 @@ H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, unsigned *oh_flags) H5O_refcount_t refcount = oh->nlink; if(H5O_msg_write_real(f, dxpl_id, oh, H5O_MSG_REFCOUNT, H5O_MSG_FLAG_DONTSHARE, 0, &refcount) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update refcount message") + HGOTO_ERROR(H5E_OHDR, H5E_CANTUPDATE, FAIL, "unable to update refcount message") } /* end else */ } /* end if */ else { @@ -1536,7 +1541,7 @@ H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, unsigned *oh_flags) H5O_refcount_t refcount = oh->nlink; if(H5O_msg_append_real(f, dxpl_id, oh, H5O_MSG_REFCOUNT, H5O_MSG_FLAG_DONTSHARE, 0, &refcount) < 0) - HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new refcount message") + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to create new refcount message") oh->has_refcount_msg = TRUE; } /* end if */ } /* end else */ @@ -1547,7 +1552,7 @@ H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, unsigned *oh_flags) ret_value = (int)oh->nlink; done: - FUNC_LEAVE_NOAPI(ret_value); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_link_oh() */ @@ -1571,9 +1576,8 @@ int H5O_link(const H5O_loc_t *loc, int adjust, hid_t dxpl_id) { H5O_t *oh = NULL; - H5AC_protect_t oh_acc; /* Access mode for protecting object header */ - unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Whether the object was deleted */ - int ret_value; /* Return value */ + hbool_t deleted = FALSE; /* Whether the object was deleted */ + int ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_link, FAIL) @@ -1582,29 +1586,30 @@ H5O_link(const H5O_loc_t *loc, int adjust, hid_t dxpl_id) HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); - /* Get header */ - oh_acc = adjust ? H5AC_WRITE : H5AC_READ; - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, oh_acc))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") + /* Pin the object header */ + if(NULL == (oh = H5O_pin(loc, dxpl_id))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header") /* Call the "real" link routine */ - if((ret_value = H5O_link_oh(loc->file, adjust, dxpl_id, oh, &oh_flags)) < 0) + if((ret_value = H5O_link_oh(loc->file, adjust, dxpl_id, oh, &deleted)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust object link count") done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) - HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh && H5O_unpin(oh) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") + if(ret_value >= 0 && deleted && H5O_delete(loc->file, dxpl_id, loc->addr) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_link() */ /*------------------------------------------------------------------------- - * Function: H5O_pin + * Function: H5O_protect * - * Purpose: Pin an object header down for use during a sequence of message - * operations, which prevents the object header from being - * evicted from the cache. + * Purpose: Wrapper around H5AC_protect for use during a H5O_protect-> + * H5O_msg_append->...->H5O_msg_append->H5O_unprotect sequence of calls + * during an object's creation. * * Return: Success: Pointer to the object header structure for the * object. @@ -1617,12 +1622,15 @@ done: *------------------------------------------------------------------------- */ H5O_t * -H5O_pin(H5O_loc_t *loc, hid_t dxpl_id) +H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, H5AC_protect_t prot) { - H5O_t *oh = NULL; /* Object header */ - H5O_t *ret_value; /* Return value */ + H5O_t *oh = NULL; /* Object header protected */ + H5O_cache_ud_t udata; /* User data for protecting object header */ + H5O_cont_msgs_t cont_msg_info; /* Continuation message info */ + unsigned file_intent; /* R/W intent on file */ + H5O_t *ret_value; /* Return value */ - FUNC_ENTER_NOAPI(H5O_pin, NULL) + FUNC_ENTER_NOAPI(H5O_protect, NULL) /* check args */ HDassert(loc); @@ -1630,29 +1638,228 @@ H5O_pin(H5O_loc_t *loc, hid_t dxpl_id) HDassert(H5F_addr_defined(loc->addr)); /* Check for write access on the file */ - if(0 == (H5F_INTENT(loc->file) & H5F_ACC_RDWR)) + file_intent = H5F_INTENT(loc->file); + if((prot == H5AC_WRITE) && (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 */ + udata.made_attempt = FALSE; + udata.v1_pfx_nmesgs = 0; + udata.common.f = loc->file; + udata.common.dxpl_id = dxpl_id; + udata.common.file_intent = file_intent; + udata.common.merged_null_msgs = 0; + udata.common.mesgs_modified = FALSE; + HDmemset(&cont_msg_info, 0, sizeof(cont_msg_info)); + udata.common.cont_msg_info = &cont_msg_info; + /* Lock the object header into the cache */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) + if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, &udata, prot))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header") - /* Check if the object header needs to be pinned */ - if(0 == oh->npins) { - /* Mark object header as un-evictable */ - if(H5AC_pin_protected_entry(oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, NULL, "unable to pin object header") + /* Check if there are any continuation messages to process */ + if(cont_msg_info.nmsgs > 0) { + size_t curr_msg; /* Current continuation message to process */ + H5O_chk_cache_ud_t chk_udata; /* User data for loading chunk */ + + /* Sanity check - we should only have continuation messages to process + * when the object header is actually loaded from the file. + */ + HDassert(udata.made_attempt == TRUE); + + /* Construct the user data for protecting chunks */ + chk_udata.decoding = TRUE; + chk_udata.oh = oh; + chk_udata.chunkno = UINT_MAX; /* Set to invalid value, for better error detection */ + chk_udata.common.f = loc->file; + chk_udata.common.dxpl_id = dxpl_id; + chk_udata.common.file_intent = file_intent; + chk_udata.common.merged_null_msgs = udata.common.merged_null_msgs; + chk_udata.common.mesgs_modified = udata.common.mesgs_modified; + chk_udata.common.cont_msg_info = &cont_msg_info; + + /* Read in continuation messages, until there are no more */ + curr_msg = 0; + while(curr_msg < cont_msg_info.nmsgs) { + H5O_chunk_proxy_t *chk_proxy; /* Proxy for chunk, to bring it into memory */ +#ifndef NDEBUG + unsigned chkcnt = oh->nchunks; /* Count of chunks (for sanity checking) */ +#endif /* NDEBUG */ + + /* Bring the chunk into the cache */ + /* (which adds to the object header */ + chk_udata.chunk_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, NULL, &chk_udata, prot))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header chunk") + + /* Sanity check */ + HDassert(chk_proxy->oh == oh); + HDassert(chk_proxy->chunkno == chkcnt); + HDassert(oh->nchunks == (chkcnt + 1)); + + /* Release the chunk from the cache */ + if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR_CHK, cont_msg_info.msgs[curr_msg].addr, chk_proxy, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header chunk") + + /* Advance to next continuation message */ + curr_msg++; + } /* end while */ + + /* Release any continuation messages built up */ + if(cont_msg_info.msgs) + cont_msg_info.msgs = (H5O_cont_t *)H5FL_SEQ_FREE(H5O_cont_t, cont_msg_info.msgs); + + /* Pass back out some of the chunk's user data */ + udata.common.merged_null_msgs = chk_udata.common.merged_null_msgs; + udata.common.mesgs_modified = chk_udata.common.mesgs_modified; } /* end if */ - /* Increment the pin count */ - oh->npins++; + /* Check for incorrect # of object header messages, if we've just loaded + * this object header from the file + */ + if(udata.made_attempt) { + /* Check for incorrect # of messages in v1 object header */ + if(oh->version == H5O_VERSION_1 && + (oh->nmesgs + udata.common.merged_null_msgs) != udata.v1_pfx_nmesgs) { +/* Don't enforce the error on an incorrect # of object header messages bug + * unless strict format checking is enabled. This allows for older + * files, created with a version of the library that had a bug in tracking + * the correct # of header messages to be read in without the library + * erroring out here. -QAK + */ +#ifdef H5_STRICT_FORMAT_CHECKS + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - incorrect # of messages") +#else /* H5_STRICT_FORMAT_CHECKS */ + /* Mark object header prefix dirty later if we don't have write access */ + /* (object header will have been marked dirty during protect, if we + * have write access -QAK) + */ + if(prot != H5AC_WRITE) + oh->prefix_modified = TRUE; +#ifndef NDEBUG + else { + unsigned oh_status = 0; /* Object header entry cache status */ + + /* Check the object header's status in the metadata cache */ + if(H5AC_get_entry_status(loc->file, loc->addr, &oh_status) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to check metadata cache status for object header") + + /* Make certain that object header is not dirty */ + HDassert(!(oh_status & H5AC_ES__IS_DIRTY)); + } /* end else */ +#endif /* NDEBUG */ +#endif /* H5_STRICT_FORMAT_CHECKS */ + } /* end if */ + + /* Check for any messages that were modified while being read in */ + if(udata.common.mesgs_modified && prot != H5AC_WRITE) + oh->mesgs_modified = TRUE; + } /* end if */ + + /* Take care of loose ends for modifications made while bringing in the + * object header & chunks. + */ + if(prot == H5AC_WRITE) { + /* Check for the object header prefix being modified somehow */ + /* (usually through updating the # of object header messages) */ + if(oh->prefix_modified) { + /* Mark the header as dirty now */ + if(H5AC_mark_pinned_or_protected_entry_dirty(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, NULL, "unable to mark object header as dirty") + + /* Reset flag */ + oh->prefix_modified = FALSE; + } /* end if */ + + /* Check for deferred dirty messages */ + if(oh->mesgs_modified) { + unsigned u; /* Local index variable */ + + /* Loop through all messages, marking their chunks as dirty */ + /* (slightly inefficient, since we don't know exactly which messages + * were modified when the object header & chunks were brought in + * from the file, but this only can happen once per load -QAK) + */ + for(u = 0; u < oh->nmesgs; u++) { + /* Mark each chunk with a dirty message as dirty also */ + if(oh->mesg[u].dirty) { + H5O_chunk_proxy_t *chk_proxy; /* Chunk that message is in */ + + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(loc->file, dxpl_id, oh, oh->mesg[u].chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header chunk") + + /* Unprotect chunk, marking it dirty */ + if(H5O_chunk_unprotect(loc->file, dxpl_id, oh, chk_proxy, H5AC__DIRTIED_FLAG) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to unprotect object header chunk") + } /* end if */ + } /* end for */ + + /* Reset flag */ + oh->mesgs_modified = FALSE; + } /* end if */ + } /* end if */ + +#ifdef H5O_DEBUG +H5O_assert(oh); +#endif /* H5O_DEBUG */ + + /* Set return value */ + ret_value = oh; + +done: + if(ret_value == NULL && oh) { + if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header") + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_protect() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_pin + * + * Purpose: Pin an object header down for use during a sequence of message + * operations, which prevents the object header from being + * evicted from the cache. + * + * Return: Success: Pointer to the object header structure for the + * object. + * Failure: NULL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jul 13 2008 + * + *------------------------------------------------------------------------- + */ +H5O_t * +H5O_pin(const H5O_loc_t *loc, hid_t dxpl_id) +{ + H5O_t *oh = NULL; /* Object header */ + H5O_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_pin, NULL) + + /* check args */ + HDassert(loc); + + /* Get header */ + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_WRITE))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to protect object header") + + /* Increment the reference count on the object header */ + /* (which will pin it, if appropriate) */ + if(H5O_inc_rc(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "unable to increment reference count on object header") /* Set the return value */ ret_value = oh; done: /* Release the object header from the cache */ - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, ret_value, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -1669,8 +1876,8 @@ done: * Failure: Negative * * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Dec 31 2002 + * koziol@hdfgroup.org + * Jul 13 2008 * *------------------------------------------------------------------------- */ @@ -1684,15 +1891,10 @@ H5O_unpin(H5O_t *oh) /* check args */ HDassert(oh); - /* Check if this is the last unpin operation */ - if(1 == oh->npins) { - /* Mark object header as evictable again */ - if(H5AC_unpin_entry(oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") - } /* end if */ - - /* Decrement the pin count */ - oh->npins--; + /* Decrement the reference count on the object header */ + /* (which will unpin it, if appropriate) */ + if(H5O_dec_rc(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement reference count on object header") done: FUNC_LEAVE_NOAPI(ret_value) @@ -1700,6 +1902,42 @@ done: /*------------------------------------------------------------------------- + * Function: H5O_unprotect + * + * Purpose: Wrapper around H5AC_unprotect for use during a H5O_protect-> + * H5O_msg_append->...->H5O_msg_append->H5O_unprotect sequence of calls + * during an object's creation. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Dec 31 2002 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_unprotect(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh, unsigned oh_flags) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_unprotect, FAIL) + + /* check args */ + HDassert(loc); + HDassert(oh); + + /* Unprotect the object header */ + if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, oh->chunk[0].addr, oh, oh_flags) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_unprotect() */ + + +/*------------------------------------------------------------------------- * Function: H5O_touch_oh * * Purpose: If FORCE is non-zero then create a modification time message @@ -1716,6 +1954,8 @@ done: herr_t H5O_touch_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hbool_t force) { + H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */ + unsigned chk_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting chunk */ time_t now; /* Current time */ herr_t ret_value = SUCCEED; /* Return value */ @@ -1754,6 +1994,10 @@ H5O_touch_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hbool_t force) oh->mesg[idx].flags = (uint8_t)mesg_flags; } /* end if */ + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, oh->mesg[idx].chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + /* Allocate 'native' space, if necessary */ if(NULL == oh->mesg[idx].native) { if(NULL == (oh->mesg[idx].native = H5FL_MALLOC(time_t))) @@ -1765,19 +2009,24 @@ H5O_touch_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hbool_t force) /* Mark the message as dirty */ oh->mesg[idx].dirty = TRUE; + chk_flags |= H5AC__DIRTIED_FLAG; } /* end if */ else { /* XXX: For now, update access time & change fields in the object header */ /* (will need to add some code to update modification time appropriately) */ oh->atime = oh->ctime = now; - } /* end else */ - /* Mark object header as dirty in cache */ - if(H5AC_mark_pinned_or_protected_entry_dirty(oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty") + /* Mark object header as dirty in cache */ + if(H5AC_mark_pinned_or_protected_entry_dirty(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty") + } /* end else */ } /* end if */ done: + /* Release chunk */ + if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy, chk_flags) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_touch_oh() */ @@ -1808,13 +2057,9 @@ H5O_touch(const H5O_loc_t *loc, hbool_t force, hid_t dxpl_id) /* check args */ HDassert(loc); - HDassert(loc->file); - HDassert(H5F_addr_defined(loc->addr)); - if(0 == (H5F_INTENT(loc->file) & H5F_ACC_RDWR)) - HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file") /* Get the object header */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_WRITE))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Create/Update the modification time message */ @@ -1825,7 +2070,7 @@ H5O_touch(const H5O_loc_t *loc, hbool_t force, hid_t dxpl_id) oh_flags |= H5AC__DIRTIED_FLAG; done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, oh_flags) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -1914,6 +2159,8 @@ herr_t H5O_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr) { H5O_t *oh = NULL; /* Object header information */ + H5O_loc_t loc; /* Object location for object to delete */ + unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting object header */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5O_delete, FAIL) @@ -1922,16 +2169,24 @@ H5O_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr) HDassert(f); HDassert(H5F_addr_defined(addr)); + /* Set up the object location */ + loc.file = f; + loc.addr = addr; + loc.holding_file = FALSE; + /* Get the object header information */ - if(NULL == (oh = (H5O_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR, addr, NULL, NULL, H5AC_WRITE))) + if(NULL == (oh = H5O_protect(&loc, dxpl_id, H5AC_WRITE))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Delete object */ if(H5O_delete_oh(f, dxpl_id, oh) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file") + /* Mark object header as deleted */ + oh_flags = H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; + done: - if(oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0) + if(oh && H5O_unprotect(&loc, dxpl_id, oh, oh_flags) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -2004,7 +2259,7 @@ H5O_obj_type(const H5O_loc_t *loc, H5O_type_t *obj_type, hid_t dxpl_id) FUNC_ENTER_NOAPI(H5O_obj_type, FAIL) /* Load the object header */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Retrieve the type of the object */ @@ -2012,7 +2267,7 @@ H5O_obj_type(const H5O_loc_t *loc, H5O_type_t *obj_type, hid_t dxpl_id) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type") done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -2082,7 +2337,7 @@ H5O_obj_class(const H5O_loc_t *loc, hid_t dxpl_id) FUNC_ENTER_NOAPI_NOINIT(H5O_obj_class) /* Load the object header */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header") /* Test whether entry qualifies as a particular type of object */ @@ -2090,7 +2345,7 @@ H5O_obj_class(const H5O_loc_t *loc, hid_t dxpl_id) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to determine object type") done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -2353,7 +2608,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5O_get_hdr_info(const H5O_loc_t *oloc, hid_t dxpl_id, H5O_hdr_info_t *hdr) +H5O_get_hdr_info(const H5O_loc_t *loc, hid_t dxpl_id, H5O_hdr_info_t *hdr) { H5O_t *oh = NULL; /* Object header */ herr_t ret_value = SUCCEED; /* Return value */ @@ -2361,14 +2616,14 @@ H5O_get_hdr_info(const H5O_loc_t *oloc, hid_t dxpl_id, H5O_hdr_info_t *hdr) FUNC_ENTER_NOAPI(H5O_get_hdr_info, FAIL) /* Check args */ - HDassert(oloc); + HDassert(loc); HDassert(hdr); /* Reset the object header info structure */ HDmemset(hdr, 0, sizeof(*hdr)); /* Get the object header */ - if(NULL == (oh = (H5O_t *)H5AC_protect(oloc->file, dxpl_id, H5AC_OHDR, oloc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Get the information for the object header */ @@ -2376,7 +2631,7 @@ H5O_get_hdr_info(const H5O_loc_t *oloc, hid_t dxpl_id, H5O_hdr_info_t *hdr) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve object header info") done: - if(oh && H5AC_unprotect(oloc->file, dxpl_id, H5AC_OHDR, oloc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -2492,7 +2747,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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Reset the object info structure */ @@ -2580,7 +2835,7 @@ H5O_get_info(const H5O_loc_t *loc, hid_t dxpl_id, hbool_t want_ih_info, } /* end if */ done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -2613,7 +2868,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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Set property values, if they were used for the object */ @@ -2635,7 +2890,7 @@ H5O_get_create_plist(const H5O_loc_t *loc, hid_t dxpl_id, H5P_genplist_t *oc_pli } /* end if */ done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -2668,14 +2923,14 @@ 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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Retrieve the # of link messages seen when the object header was loaded */ *nlinks = oh->link_msgs_seen; done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -2783,22 +3038,22 @@ H5O_get_rc_and_type(const H5O_loc_t *loc, hid_t dxpl_id, unsigned *rc, H5O_type_ /* Check args */ HDassert(loc); - HDassert(rc); - HDassert(otype); /* Get the object header */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Set the object's reference count */ - *rc = oh->nlink; + if(rc) + *rc = oh->nlink; /* Retrieve the type of the object */ - if(H5O_obj_type_real(oh, otype) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type") + if(otype) + if(H5O_obj_type_real(oh, otype) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type") done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -2822,7 +3077,7 @@ H5O_free_visit_visited(void *item, void UNUSED *key, void UNUSED *operator_data/ { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_free_visit_visited) - (void)H5FL_FREE(H5_obj_t, item); + item = H5FL_FREE(H5_obj_t, item); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_free_visit_visited() */ @@ -3061,6 +3316,78 @@ done: /*------------------------------------------------------------------------- + * Function: H5O_inc_rc + * + * Purpose: Increments the reference count on an object header + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jul 13 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_inc_rc(H5O_t *oh) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_inc_rc, FAIL) + + /* check args */ + HDassert(oh); + + /* Pin the object header when the reference count goes above 0 */ + if(oh->rc == 0) + if(H5AC_pin_protected_entry(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header") + + /* Increment reference count */ + oh->rc++; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_inc_rc() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_dec_rc + * + * Purpose: Decrements the reference count on an object header + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jul 13 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_dec_rc(H5O_t *oh) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_dec_rc, FAIL) + + /* check args */ + HDassert(oh); + + /* Decrement reference count */ + oh->rc--; + + /* Unpin the object header when the reference count goes back to 0 */ + if(oh->rc == 0) + if(H5AC_unpin_entry(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_dec_rc() */ + + +/*------------------------------------------------------------------------- * Function: H5O_free * * Purpose: Destroys an object header. @@ -3085,12 +3412,8 @@ H5O_free(H5O_t *oh) /* Destroy chunks */ if(oh->chunk) { - for(u = 0; u < oh->nchunks; u++) { - /* Verify that chunk is clean */ - HDassert(oh->chunk[u].dirty == 0); - + for(u = 0; u < oh->nchunks; u++) oh->chunk[u].image = H5FL_BLK_FREE(chunk_image, oh->chunk[u].image); - } /* end for */ oh->chunk = (H5O_chunk_t *)H5FL_SEQ_FREE(H5O_chunk_t, oh->chunk); } /* end if */ diff --git a/src/H5Oalloc.c b/src/H5Oalloc.c index 31e6de7..66630ca 100644 --- a/src/H5Oalloc.c +++ b/src/H5Oalloc.c @@ -58,21 +58,24 @@ /* Local Prototypes */ /********************/ -static herr_t H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, - uint8_t *new_gap_loc, size_t new_gap_size); -static herr_t H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, - uint8_t *new_gap_loc, size_t new_gap_size); -static herr_t H5O_alloc_null(H5O_t *oh, unsigned null_idx, +static herr_t H5O_add_gap(H5F_t *f, hid_t dxpl_id, H5O_t *oh, + H5O_chunk_proxy_t *chk_proxy, unsigned *chk_flags, + unsigned idx, uint8_t *new_gap_loc, size_t new_gap_size); +static herr_t H5O_eliminate_gap(H5F_t *f, hid_t dxpl_id, H5O_t *oh, + H5O_chunk_proxy_t *chk_proxy, unsigned *chk_flags, + H5O_mesg_t *mesg, uint8_t *new_gap_loc, size_t new_gap_size); +static herr_t H5O_alloc_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, void *new_native, size_t new_size); static htri_t H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno, size_t size, unsigned * msg_idx); static unsigned H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size); -static htri_t H5O_move_cont(H5F_t *f, H5O_t *oh, unsigned cont_u, hid_t dxpl_id); -static htri_t H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id); -static htri_t H5O_merge_null(H5F_t *f, H5O_t *oh, hid_t dxpl_id); +static htri_t H5O_move_cont(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned cont_u); +static htri_t H5O_move_msgs_forward(H5F_t *f, hid_t dxpl_id, H5O_t *oh); +static htri_t H5O_merge_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh); static htri_t H5O_remove_empty_chunks(H5F_t *f, hid_t dxpl_id, H5O_t *oh); -static herr_t H5O_alloc_shrink_chunk(H5F_t *f, H5O_t *oh, hid_t dxpl_id, unsigned chunkno); +static herr_t H5O_alloc_shrink_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, + unsigned chunkno); /*********************/ @@ -108,8 +111,8 @@ H5FL_EXTERN(H5O_cont_t); *------------------------------------------------------------------------- */ static herr_t -H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, - uint8_t *new_gap_loc, size_t new_gap_size) +H5O_add_gap(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_chunk_proxy_t *chk_proxy, + unsigned *chk_flags, unsigned idx, uint8_t *new_gap_loc, size_t new_gap_size) { hbool_t merged_with_null; /* Whether the gap was merged with a null message */ unsigned u; /* Local index variable */ @@ -120,6 +123,8 @@ H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, /* check args */ HDassert(oh); HDassert(oh->version > H5O_VERSION_1); + HDassert(chk_proxy); + HDassert(chk_flags); HDassert(new_gap_loc); HDassert(new_gap_size); @@ -128,13 +133,13 @@ H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, for(u = 0; u < oh->nmesgs && !merged_with_null; u++) { /* Find a null message in the chunk with the new gap */ /* (a null message that's not the one we are eliminating) */ - if(H5O_NULL_ID == oh->mesg[u].type->id && oh->mesg[u].chunkno == chunkno + if(H5O_NULL_ID == oh->mesg[u].type->id && oh->mesg[u].chunkno == chk_proxy->chunkno && u != idx) { /* Sanity check - chunks with null messages shouldn't have a gap */ - HDassert(oh->chunk[chunkno].gap == 0); + HDassert(oh->chunk[chk_proxy->chunkno].gap == 0); /* Eliminate the gap in the chunk */ - if(H5O_eliminate_gap(oh, &oh->mesg[u], new_gap_loc, new_gap_size) < 0) + if(H5O_eliminate_gap(f, dxpl_id, oh, chk_proxy, chk_flags, &oh->mesg[u], new_gap_loc, new_gap_size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't eliminate gap in chunk") /* Set flag to indicate that the gap was handled */ @@ -146,15 +151,15 @@ H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, if(!merged_with_null) { /* Adjust message offsets after new gap forward in chunk */ for(u = 0; u < oh->nmesgs; u++) - if(oh->mesg[u].chunkno == chunkno && oh->mesg[u].raw > new_gap_loc) + if(oh->mesg[u].chunkno == chk_proxy->chunkno && oh->mesg[u].raw > new_gap_loc) oh->mesg[u].raw -= new_gap_size; /* Slide raw message info forward in chunk image */ HDmemmove(new_gap_loc, new_gap_loc + new_gap_size, - (size_t)((oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh))) - (new_gap_loc + new_gap_size))); + (size_t)((oh->chunk[chk_proxy->chunkno].image + (oh->chunk[chk_proxy->chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh))) - (new_gap_loc + new_gap_size))); /* Add existing gap size to new gap size */ - new_gap_size += oh->chunk[chunkno].gap; + new_gap_size += oh->chunk[chk_proxy->chunkno].gap; /* Merging with existing gap will allow for a new null message */ if(new_gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { @@ -166,16 +171,16 @@ H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") /* Increment new gap size */ - oh->chunk[chunkno].gap += new_gap_size; + oh->chunk[chk_proxy->chunkno].gap += new_gap_size; /* Create new null message, with the tail of the previous null message */ null_msg = &(oh->mesg[oh->nmesgs++]); null_msg->type = H5O_MSG_NULL; null_msg->native = NULL; null_msg->raw_size = new_gap_size - H5O_SIZEOF_MSGHDR_OH(oh); - null_msg->raw = (oh->chunk[chunkno].image + oh->chunk[chunkno].size) + null_msg->raw = (oh->chunk[chk_proxy->chunkno].image + oh->chunk[chk_proxy->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + null_msg->raw_size); - null_msg->chunkno = chunkno; + null_msg->chunkno = chk_proxy->chunkno; /* Zero out new null message's raw data */ if(null_msg->raw_size) @@ -185,10 +190,13 @@ H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, null_msg->dirty = TRUE; /* Reset size of gap in chunk */ - oh->chunk[chunkno].gap = 0; + oh->chunk[chk_proxy->chunkno].gap = 0; } /* end if */ else - oh->chunk[chunkno].gap = new_gap_size; + oh->chunk[chk_proxy->chunkno].gap = new_gap_size; + + /* Mark the chunk as modified */ + *chk_flags |= H5AC__DIRTIED_FLAG; } /* end if */ done: @@ -199,7 +207,14 @@ done: /*------------------------------------------------------------------------- * Function: H5O_eliminate_gap * - * Purpose: Eliminate a gap in a chunk with a null message + * Purpose: Eliminate a gap in a chunk with a null message. + * + * Note: Sometimes this happens as a result of converting an existing + * non-null message to a null message, so we zero out the gap + * here, even though it might already be zero (when we're adding + * a gap to a chunk with an existing null message). (Mostly, + * this just simplifies the code, esp. with the necessary chunk + * locking -QAK) * * Return: Non-negative on success/Negative on failure * @@ -210,16 +225,20 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, uint8_t *gap_loc, size_t gap_size) +H5O_eliminate_gap(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_chunk_proxy_t *chk_proxy, + unsigned *chk_flags, H5O_mesg_t *mesg, uint8_t *gap_loc, size_t gap_size) { uint8_t *move_start, *move_end; /* Pointers to area of messages to move */ hbool_t null_before_gap; /* Flag whether the null message is before the gap or not */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_eliminate_gap) + FUNC_ENTER_NOAPI_NOINIT(H5O_eliminate_gap) /* check args */ HDassert(oh); HDassert(oh->version > H5O_VERSION_1); + HDassert(chk_proxy); + HDassert(chk_flags); HDassert(mesg); HDassert(gap_loc); HDassert(gap_size); @@ -242,6 +261,7 @@ H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, uint8_t *gap_loc, size_t gap_size unsigned u; /* Local index variable */ /* Look for messages that need to move, to adjust raw pointers in chunk */ + /* (this doesn't change the moved messages 'dirty' state) */ for(u = 0; u < oh->nmesgs; u++) { uint8_t *msg_start; /* Start of encoded message in chunk */ @@ -282,10 +302,15 @@ H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, uint8_t *gap_loc, size_t gap_size /* Adjust size of null message */ mesg->raw_size += gap_size; + /* Set the gap size to zero for the chunk */ + oh->chunk[mesg->chunkno].gap = 0; + /* Mark null message as dirty */ mesg->dirty = TRUE; + *chk_flags |= H5AC__DIRTIED_FLAG; - FUNC_LEAVE_NOAPI(SUCCEED) +done: + FUNC_LEAVE_NOAPI(ret_value) } /* H5O_eliminate_gap() */ @@ -304,9 +329,11 @@ H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, uint8_t *gap_loc, size_t gap_size *------------------------------------------------------------------------- */ static herr_t -H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, - void *new_native, size_t new_size) +H5O_alloc_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned null_idx, + const H5O_msg_class_t *new_type, void *new_native, size_t new_size) { + H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */ + unsigned chk_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting chunk */ H5O_mesg_t *alloc_msg; /* Pointer to null message to allocate out of */ herr_t ret_value = SUCCEED; /* Return value */ @@ -320,6 +347,10 @@ H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, /* Point to null message to allocate out of */ alloc_msg = &oh->mesg[null_idx]; + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, alloc_msg->chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + /* Check if there's a need to split the null message */ if(alloc_msg->raw_size > new_size) { /* Check for producing a gap in the chunk */ @@ -330,7 +361,7 @@ H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, alloc_msg->raw_size = new_size; /* Add the gap to the chunk */ - if(H5O_add_gap(oh, alloc_msg->chunkno, null_idx, alloc_msg->raw + alloc_msg->raw_size, gap_size) < 0) + if(H5O_add_gap(f, dxpl_id, oh, chk_proxy, &chk_flags, null_idx, alloc_msg->raw + alloc_msg->raw_size, gap_size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk") } /* end if */ else { @@ -356,19 +387,17 @@ H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, /* Mark the message as dirty */ null_msg->dirty = TRUE; + chk_flags |= H5AC__DIRTIED_FLAG; /* Check for gap in new null message's chunk */ if(oh->chunk[null_msg->chunkno].gap > 0) { unsigned null_chunkno = null_msg->chunkno; /* Chunk w/gap */ /* Eliminate the gap in the chunk */ - if(H5O_eliminate_gap(oh, null_msg, + if(H5O_eliminate_gap(f, dxpl_id, oh, chk_proxy, &chk_flags, null_msg, ((oh->chunk[null_chunkno].image + oh->chunk[null_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[null_chunkno].gap)), oh->chunk[null_chunkno].gap) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") - - /* Set the gap size to zero for the chunk */ - oh->chunk[null_chunkno].gap = 0; } /* end if */ /* Set the size of the new "real" message */ @@ -382,8 +411,13 @@ H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, /* Mark the new message as dirty */ alloc_msg->dirty = TRUE; + chk_flags |= H5AC__DIRTIED_FLAG; done: + /* Release chunk */ + if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy, chk_flags) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + FUNC_LEAVE_NOAPI(ret_value) } /* H5O_alloc_null() */ @@ -467,6 +501,8 @@ static htri_t H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno, size_t size, unsigned * msg_idx) { + H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */ + unsigned chk_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting chunk */ size_t delta; /* Change in chunk's size */ size_t aligned_size = H5O_ALIGN_OH(oh, size); uint8_t *old_image; /* Old address of chunk's image in memory */ @@ -500,7 +536,7 @@ H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno, == ((oh->chunk[chunkno].image + oh->chunk[chunkno].size) - (oh->chunk[chunkno].gap + H5O_SIZEOF_CHKSUM_OH(oh))))) { - extend_msg = u; + extend_msg = (int)u; break; } /* end if */ } /* end for */ @@ -516,7 +552,10 @@ H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno, /* Check for changing the chunk #0 data size enough to need adjusting the flags */ if(oh->version > H5O_VERSION_1 && chunkno == 0) { - uint64_t chunk0_size = oh->chunk[0].size - H5O_SIZEOF_HDR(oh); /* Size of chunk 0's data */ + uint64_t chunk0_size; /* Size of chunk 0's data */ + + HDassert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh)); + chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh); /* Check for moving from a 1-byte to a 2-byte size encoding */ if(chunk0_size <= 255 && (chunk0_size + delta) > 255) { @@ -546,16 +585,23 @@ H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno, else if(extended == FALSE) /* can't extend -- we are done */ HGOTO_DONE(FALSE) + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + /* Adjust object header prefix flags */ if(adjust_size_flags) { - oh->flags &= ~H5O_HDR_CHUNK0_SIZE; + oh->flags &= (uint8_t)~H5O_HDR_CHUNK0_SIZE; oh->flags |= new_size_flags; + + /* Mark object header as dirty in cache */ + if(H5AC_mark_pinned_or_protected_entry_dirty(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty") } /* end if */ /* If we can extend an existing null message, take care of that */ if(extend_msg >= 0) { /* Adjust message size of existing null message */ - oh->mesg[extend_msg].dirty = TRUE; oh->mesg[extend_msg].raw_size += delta; } /* end if */ /* Create new null message for end of chunk */ @@ -566,11 +612,10 @@ H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno, HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") /* Set extension message */ - extend_msg = oh->nmesgs++; + extend_msg = (int)oh->nmesgs++; /* Initialize new null message */ oh->mesg[extend_msg].type = H5O_MSG_NULL; - oh->mesg[extend_msg].dirty = TRUE; oh->mesg[extend_msg].native = NULL; oh->mesg[extend_msg].raw = ((oh->chunk[chunkno].image + oh->chunk[chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[chunkno].gap)) @@ -579,13 +624,16 @@ H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno, oh->mesg[extend_msg].chunkno = chunkno; } /* end else */ + /* Mark the extended message as dirty */ + oh->mesg[extend_msg].dirty = TRUE; + chk_flags |= H5AC__DIRTIED_FLAG; + /* Allocate more memory space for chunk's image */ old_image = oh->chunk[chunkno].image; old_size = oh->chunk[chunkno].size; oh->chunk[chunkno].size += delta + extra_prfx_size; oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image, old_image, oh->chunk[chunkno].size); oh->chunk[chunkno].gap = 0; - oh->chunk[chunkno].dirty = TRUE; if(NULL == oh->chunk[chunkno].image) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") @@ -599,6 +647,7 @@ H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno, oh->mesg[u].raw = oh->chunk[chunkno].image + extra_prfx_size + (oh->mesg[u].raw - old_image); /* Flag message as dirty directly */ + /* (we mark the entire chunk dirty when we update its size) */ oh->mesg[u].dirty = TRUE; } /* endif */ @@ -607,19 +656,39 @@ H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno, * it's size is directly encoded in the object header) */ if(chunkno > 0 && (H5O_CONT_ID == oh->mesg[u].type->id) && (((H5O_cont_t *)(oh->mesg[u].native))->chunkno == chunkno)) { + H5O_chunk_proxy_t *chk_proxy2 = NULL; /* Chunk that continuation message is in */ + unsigned chk_flags2 = H5AC__NO_FLAGS_SET; /* Flags for unprotecting chunk */ + unsigned cont_chunkno = oh->mesg[u].chunkno; /* Chunk # for continuation message */ + + /* Protect chunk containing continuation message */ + if(NULL == (chk_proxy2 = H5O_chunk_protect(f, dxpl_id, oh, cont_chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + /* Adjust size in continuation message */ HDassert(((H5O_cont_t *)(oh->mesg[u].native))->size == old_size); ((H5O_cont_t *)(oh->mesg[u].native))->size = oh->chunk[chunkno].size; /* Flag continuation message as dirty */ oh->mesg[u].dirty = TRUE; + chk_flags2 |= H5AC__DIRTIED_FLAG; + + /* Release chunk containing continuation message */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy2, chk_flags2) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") } /* end if */ } /* end for */ + /* Mark the chunk size in the cache as changed */ + chk_flags |= H5AC__SIZE_CHANGED_FLAG; + /* Set return value */ - *msg_idx = extend_msg; + *msg_idx = (unsigned)extend_msg; done: + /* Release chunk */ + if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy, chk_flags) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + FUNC_LEAVE_NOAPI(ret_value) } /* H5O_alloc_extend_chunk() */ @@ -672,6 +741,7 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) } alloc_info; H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ + H5O_chunk_proxy_t *chk_proxy; /* Chunk that message is in */ size_t cont_size; /*continuation message size */ size_t multi_size = 0; /* Size of all the messages in the last chunk */ int found_null = (-1); /* Best fit null message */ @@ -707,12 +777,12 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { if(curr_msg->type->id == H5O_NULL_ID) { if(cont_size == curr_msg->raw_size) { - found_null = u; + found_null = (int)u; break; } /* end if */ else if(curr_msg->raw_size > cont_size && (found_null < 0 || curr_msg->raw_size < oh->mesg[found_null].raw_size)) - found_null = u; + found_null = (int)u; } /* end if */ else if(curr_msg->type->id == H5O_CONT_ID) { /* Don't consider continuation messages (for now) */ @@ -753,7 +823,7 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) if(total_size >= cont_size) { if(curr_msg->type->id == H5O_ATTR_ID) { if(found_attr.msgno < 0 || total_size < found_attr.total_size) { - found_attr.msgno = u; + found_attr.msgno = (int)u; found_attr.gap_size = gap_size; found_attr.null_size = null_size; found_attr.total_size = total_size; @@ -762,7 +832,7 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) } /* end if */ else { if(found_other.msgno < 0 || total_size < found_other.total_size) { - found_other.msgno = u; + found_other.msgno = (int)u; found_other.gap_size = gap_size; found_other.null_size = null_size; found_other.total_size = total_size; @@ -835,7 +905,6 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) } /* end if */ chunkno = oh->nchunks++; - oh->chunk[chunkno].dirty = TRUE; oh->chunk[chunkno].addr = new_chunk_addr; oh->chunk[chunkno].size = size; oh->chunk[chunkno].gap = 0; @@ -861,9 +930,14 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) if(multi_size > 0) { /* Move all non-null messages in the last chunk to the new chunk. This * should be extremely rare so we don't care too much about minimizing - * the space used */ + * the space used. + */ H5O_mesg_t *null_msg; /* Pointer to new null message */ + /* Protect last chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, chunkno - 1))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, UFAIL, "unable to load object header chunk") + /* Copy each message to the new location */ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) if(curr_msg->chunkno == chunkno - 1) { @@ -888,15 +962,15 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) } /* end if */ /* Create a null message spanning the entire last chunk */ - found_null = oh->nmesgs++; + found_null = (int)oh->nmesgs++; null_msg = &(oh->mesg[found_null]); null_msg->type = H5O_MSG_NULL; null_msg->dirty = TRUE; null_msg->native = NULL; - null_msg->raw = oh->chunk[chunkno-1].image + null_msg->raw = oh->chunk[chunkno - 1].image + ((chunkno == 1) ? H5O_SIZEOF_HDR(oh) : H5O_SIZEOF_CHKHDR_OH(oh)) - H5O_SIZEOF_CHKSUM_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh); - null_msg->raw_size = oh->chunk[chunkno-1].size + null_msg->raw_size = oh->chunk[chunkno - 1].size - ((chunkno == 1) ? H5O_SIZEOF_HDR(oh) : H5O_SIZEOF_CHKHDR_OH(oh)) - H5O_SIZEOF_MSGHDR_OH(oh); null_msg->chunkno = chunkno - 1; @@ -904,16 +978,23 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) HDassert(null_msg->raw_size >= cont_size); /* Remove any gap in the chunk */ - oh->chunk[chunkno-1].gap = 0; + oh->chunk[chunkno - 1].gap = 0; + /* Release chunk, marking it dirty */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy, H5AC__DIRTIED_FLAG) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, UFAIL, "unable to unprotect object header chunk") } else if(found_null < 0) { /* Move message (that will be replaced with continuation message) - * to new chunk, if necessary. - */ + * to new chunk, if necessary. + */ H5O_mesg_t *null_msg; /* Pointer to new null message */ + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, oh->mesg[found_other.msgno].chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, UFAIL, "unable to load object header chunk") + /* Create null message for space that message to copy currently occupies */ - found_null = oh->nmesgs++; + found_null = (int)oh->nmesgs++; null_msg = &(oh->mesg[found_null]); null_msg->type = H5O_MSG_NULL; null_msg->native = NULL; @@ -922,7 +1003,6 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) null_msg->chunkno = oh->mesg[found_other.msgno].chunkno; /* Copy the message to move (& its prefix) to its new location */ - /* (Chunk is already dirty, no need to mark it) */ HDmemcpy(p, oh->mesg[found_other.msgno].raw - H5O_SIZEOF_MSGHDR_OH(oh), oh->mesg[found_other.msgno].raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); @@ -965,6 +1045,10 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) /* Mark the new null message as dirty */ null_msg->dirty = TRUE; + + /* Release chunk, marking it dirty */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy, H5AC__DIRTIED_FLAG) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, UFAIL, "unable to unprotect object header chunk") } /* end if */ HDassert(found_null >= 0); @@ -975,9 +1059,13 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) oh->mesg[idx].dirty = TRUE; oh->mesg[idx].native = NULL; oh->mesg[idx].raw = p + H5O_SIZEOF_MSGHDR_OH(oh); - oh->mesg[idx].raw_size = size - (H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh)); + oh->mesg[idx].raw_size = size - (size_t)(H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh)); oh->mesg[idx].chunkno = chunkno; + /* Insert the new chunk into the cache */ + if(H5O_chunk_add(f, dxpl_id, oh, chunkno) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't add new chunk to cache") + /* Initialize the continuation information */ if(NULL == (cont = H5FL_MALLOC(H5O_cont_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed") @@ -986,7 +1074,7 @@ H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) cont->chunkno = chunkno; /* Split the null message and point at continuation message */ - if(H5O_alloc_null(oh, (unsigned)found_null, H5O_MSG_CONT, cont, cont_size) < 0) + if(H5O_alloc_null(f, dxpl_id, oh, (unsigned)found_null, H5O_MSG_CONT, cont, cont_size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't split null message") /* Set return value */ @@ -1071,7 +1159,7 @@ H5O_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type, } /* end if */ /* Split the null message and point at continuation message */ - if(H5O_alloc_null(oh, idx, type, NULL, aligned_size) < 0) + if(H5O_alloc_null(f, dxpl_id, oh, idx, type, NULL, aligned_size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't split null message") /* Mark object header as dirty in cache */ @@ -1104,6 +1192,8 @@ herr_t H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg, hbool_t adj_link) { + H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */ + unsigned chk_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting chunk */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5O_release_mesg, FAIL) @@ -1120,6 +1210,10 @@ H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg, HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message") } /* end if */ + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, mesg->chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk") + /* Free any native information */ H5O_msg_free_mesg(mesg); @@ -1133,20 +1227,22 @@ H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg, /* Mark the message as modified */ mesg->dirty = TRUE; + chk_flags |= H5AC__DIRTIED_FLAG; /* Check if chunk has a gap currently */ if(oh->chunk[mesg->chunkno].gap) { /* Eliminate the gap in the chunk */ - if(H5O_eliminate_gap(oh, mesg, + if(H5O_eliminate_gap(f, dxpl_id, oh, chk_proxy, &chk_flags, mesg, ((oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap)), oh->chunk[mesg->chunkno].gap) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") - - /* Set the gap size to zero for the chunk */ - oh->chunk[mesg->chunkno].gap = 0; } /* end if */ done: + /* Release chunk, if not already done */ + if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy, chk_flags) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + FUNC_LEAVE_NOAPI(ret_value) } /* H5O_release_mesg() */ @@ -1165,18 +1261,13 @@ done: *------------------------------------------------------------------------- */ static htri_t -H5O_move_cont(H5F_t *f, H5O_t *oh, unsigned cont_u, hid_t dxpl_id) +H5O_move_cont(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned cont_u) { - unsigned v; /* local index variable */ - H5O_mesg_t *cont_msg; /* pointer to the continuation message */ - H5O_mesg_t *nonnull_msg; /* pointer to the current message to operate on */ - H5O_mesg_t *null_msg; /* pointer to the current message to operate on */ - size_t total_size=0; /* total size of nonnull messages in the chunk pointed to by cont message */ - size_t move_size=0; /* size of the message to be moved */ - uint8_t *move_start, *move_end; /* pointers to area of messages to move */ - size_t gap_size; /* size of gap produced */ + H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that continuation message is in */ + H5O_mesg_t *cont_msg; /* Pointer to the continuation message */ unsigned deleted_chunkno; /* Chunk # to delete */ - htri_t ret_value = FALSE; /* Return value */ + unsigned chk_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting chunk */ + htri_t ret_value = TRUE; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_move_cont) @@ -1184,81 +1275,133 @@ H5O_move_cont(H5F_t *f, H5O_t *oh, unsigned cont_u, hid_t dxpl_id) HDassert(f); HDassert(oh); + /* Get initial information */ cont_msg = &oh->mesg[cont_u]; H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, cont_msg, FAIL) deleted_chunkno = ((H5O_cont_t *)(cont_msg->native))->chunkno; - /* proceed further only if continuation message is pointing to the last chunk */ - if(deleted_chunkno != (oh->nchunks - 1)) - HGOTO_DONE(FALSE) - - /* find size of all nonnull messages in the chunk pointed to by the continuation message */ - for(v = 0, nonnull_msg = &oh->mesg[0]; v < oh->nmesgs; v++, nonnull_msg++) - if(nonnull_msg->chunkno == deleted_chunkno && nonnull_msg->type->id != H5O_NULL_ID) { - HDassert(nonnull_msg->type->id != H5O_CONT_ID); - total_size += nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); - } - - /* check if messages can fit into the continuation message */ - if(total_size && total_size <= (cont_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh))) { - - /* convert continuation message into a null message */ - if(H5O_release_mesg(f, dxpl_id, oh, cont_msg, TRUE) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to convert into null message") - - move_start = cont_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh); - move_end = cont_msg->raw + cont_msg->raw_size; - - /* move message(s) forward into continuation message */ - for(v = 0, nonnull_msg = &oh->mesg[0]; v < oh->nmesgs; v++, nonnull_msg++) - if(nonnull_msg->chunkno == deleted_chunkno && nonnull_msg->type->id != H5O_NULL_ID) { - move_size = nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); - HDmemcpy(move_start, nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), move_size); - nonnull_msg->raw = move_start + H5O_SIZEOF_MSGHDR_OH(oh); - nonnull_msg->chunkno = cont_msg->chunkno; - nonnull_msg->dirty = TRUE; - move_start += move_size; - } - - HDassert(move_start <= move_end); - - /* check if there is space remaining in the continuation message */ - /* the remaining space can be gap or a null message */ - gap_size = move_end - move_start; - if(gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { - cont_msg->raw_size = gap_size - H5O_SIZEOF_MSGHDR_OH(oh); - cont_msg->raw = move_start + H5O_SIZEOF_MSGHDR_OH(oh); - cont_msg->dirty = TRUE; - } else { - if(gap_size && (H5O_add_gap(oh, cont_msg->chunkno, cont_u, move_start, gap_size) < 0)) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk") - /* Release any information/memory for continuation message */ - H5O_msg_free_mesg(cont_msg); - if(cont_u < (oh->nmesgs - 1)) - HDmemmove(&oh->mesg[cont_u], &oh->mesg[cont_u + 1], ((oh->nmesgs - 1) - cont_u) * sizeof(H5O_mesg_t)); - oh->nmesgs--; - } - - /* remove all null messages in deleted chunk from list of messages */ - /* Note: unsigned v wrapping around at the end */ - for (v = oh->nmesgs - 1, null_msg = &oh->mesg[v]; v < oh->nmesgs; v--, null_msg--) - if(null_msg->type->id == H5O_NULL_ID && null_msg->chunkno == deleted_chunkno) { + /* Check if continuation message is pointing to the last chunk */ + if(deleted_chunkno == (oh->nchunks - 1)) { + size_t nonnull_size; /* Total size of nonnull messages in the chunk pointed to by cont message */ + H5O_mesg_t *curr_msg; /* Pointer to the current message to operate on */ + size_t gap_size; /* Size of gap produced */ + unsigned v; /* Local index variable */ + + /* Find size of all nonnull messages in the chunk pointed to by the continuation message */ + nonnull_size = 0; + for(v = 0, curr_msg = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg++) + if(curr_msg->chunkno == deleted_chunkno && curr_msg->type->id != H5O_NULL_ID) { + HDassert(curr_msg->type->id != H5O_CONT_ID); + nonnull_size += curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); + } /* end if */ - /* Release any information/memory for message */ - H5O_msg_free_mesg(null_msg); + /* Size of gap in chunk w/continuation message */ + gap_size = oh->chunk[cont_msg->chunkno].gap; + + /* Check if messages can fit into the continuation message + gap size */ + /* (Could count any null messages in the chunk w/the continuation + * message also, but that is pretty complex. -QAK) + */ + if(nonnull_size && nonnull_size <= (gap_size + cont_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh))) { + uint8_t *move_start, *move_end; /* Pointers to area of messages to move */ + unsigned cont_chunkno; /* Chunk number for continuation message */ + + /* Get continuation info */ + move_start = cont_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh); + move_end = cont_msg->raw + cont_msg->raw_size; + cont_chunkno = cont_msg->chunkno; + + /* Convert continuation message into a null message */ + if(H5O_release_mesg(f, dxpl_id, oh, cont_msg, TRUE) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to convert into null message") + + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, cont_chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk") + + /* Move message(s) forward into continuation message */ + for(v = 0, curr_msg = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg++) + /* Look for messages in chunk to delete */ + if(curr_msg->chunkno == deleted_chunkno) { + /* Move messages out of chunk to delete */ + if(curr_msg->type->id != H5O_NULL_ID) { + size_t move_size; /* Size of the message to be moved */ + + /* Compute size of message to move */ + move_size = curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); + + /* Move message out of deleted chunk */ + HDmemcpy(move_start, curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), move_size); + curr_msg->raw = move_start + H5O_SIZEOF_MSGHDR_OH(oh); + curr_msg->chunkno = cont_chunkno; + curr_msg->dirty = TRUE; + chk_flags |= H5AC__DIRTIED_FLAG; + + /* Adjust location to move messages to */ + move_start += move_size; + } /* end else */ + } /* end if */ + + HDassert(move_start <= (move_end + gap_size)); + + /* Check if there is space remaining in the continuation message */ + /* (The remaining space can be gap or a null message) */ + gap_size += (size_t)(move_end - move_start); + if(gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { + /* Adjust size of null (was continuation) message */ + cont_msg->raw_size = gap_size - H5O_SIZEOF_MSGHDR_OH(oh); + cont_msg->raw = move_start + H5O_SIZEOF_MSGHDR_OH(oh); + cont_msg->dirty = TRUE; + chk_flags |= H5AC__DIRTIED_FLAG; + } /* end if */ + else { + /* Check if there is space that should be a gap */ + if(gap_size > 0) { + /* Convert remnant into gap in chunk */ + if(H5O_add_gap(f, dxpl_id, oh, chk_proxy, &chk_flags, cont_u, move_start, gap_size) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk") + } /* end if */ - if(v < (oh->nmesgs - 1)) - HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t)); - oh->nmesgs--; - } /* end if */ + /* Release any information/memory for continuation message */ + H5O_msg_free_mesg(cont_msg); + if(cont_u < (oh->nmesgs - 1)) + HDmemmove(&oh->mesg[cont_u], &oh->mesg[cont_u + 1], ((oh->nmesgs - 1) - cont_u) * sizeof(H5O_mesg_t)); + oh->nmesgs--; + } /* end else */ - (void)H5FL_BLK_FREE(chunk_image, oh->chunk[deleted_chunkno].image); + /* Move message(s) forward into continuation message */ + /* Note: unsigned v wrapping around at the end */ + for(v = oh->nmesgs - 1, curr_msg = &oh->mesg[v]; v < oh->nmesgs; v--, curr_msg--) + /* Look for messages in chunk to delete */ + if(curr_msg->chunkno == deleted_chunkno) { + /* Remove all null messages in deleted chunk from list of messages */ + if(curr_msg->type->id == H5O_NULL_ID) { + /* Release any information/memory for message */ + H5O_msg_free_mesg(curr_msg); + chk_flags |= H5AC__DIRTIED_FLAG; + + /* Remove from message list */ + if(v < (oh->nmesgs - 1)) + HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t)); + oh->nmesgs--; + } /* end if */ + } /* end if */ - oh->nchunks--; - ret_value = TRUE; + /* Remove chunk from list of chunks */ + oh->chunk[deleted_chunkno].image = H5FL_BLK_FREE(chunk_image, oh->chunk[deleted_chunkno].image); + oh->nchunks--; + } /* end if */ + else + ret_value = FALSE; } /* end if */ + else + ret_value = FALSE; done: + /* Release chunk, if not already done */ + if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy, chk_flags) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + FUNC_LEAVE_NOAPI(ret_value) } /* H5O_move_cont() */ @@ -1274,14 +1417,11 @@ done: * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Oct 17 2005 - * Modifications: - * Feb. 2009: Vailin Choi - * Add changes to move messages forward into "continuation" message * *------------------------------------------------------------------------- */ static htri_t -H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) +H5O_move_msgs_forward(H5F_t *f, hid_t dxpl_id, H5O_t *oh) { hbool_t packed_msg; /* Flag to indicate that messages were packed */ hbool_t did_packing = FALSE; /* Whether any messages were packed */ @@ -1323,6 +1463,12 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* Don't swap messages if the second message is also a null message */ /* (We'll merge them together later, in another routine) */ if(H5O_NULL_ID != nonnull_msg->type->id) { + H5O_chunk_proxy_t *null_chk_proxy; /* Chunk that message is in */ + + /* Protect chunk */ + if(NULL == (null_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + /* Copy raw data for non-null message to new location */ HDmemmove(curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); @@ -1336,11 +1482,12 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* Mark null message dirty */ /* (since we need to re-encode its message header) */ - /* (also, marking this message dirty means we - * don't have to mark chunk as dirty) - */ curr_msg->dirty = TRUE; + /* Release chunk, marking it dirty */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, null_chk_proxy, H5AC__DIRTIED_FLAG) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + /* Set the flag to indicate that the null message * was packed - if its not at the end its chunk, * we'll move it again on the next pass. @@ -1357,23 +1504,29 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) } /* end if */ } /* end if */ else { - H5O_mesg_t *null_msg; /* Pointer to current message to operate on */ - unsigned v; /* Local index variable */ - htri_t status; + H5O_mesg_t *null_msg; /* Pointer to current message to operate on */ + unsigned v; /* Local index variable */ + /* Check if messages in chunk pointed to can replace continuation message */ if(H5O_CONT_ID == curr_msg->type->id) { - if((status = H5O_move_cont(f, oh, u, dxpl_id)) < 0) + htri_t status; /* Status from moving messages */ + + if((status = H5O_move_cont(f, dxpl_id, oh, u)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "Error in moving messages into cont message") - else if(status > 0) { /* message(s) got moved into "continuation" message */ + else if(status > 0) { /* Message(s) got moved into "continuation" message */ packed_msg = TRUE; break; - } - } + } /* end else-if */ + } /* end if */ /* Loop over messages again, looking for large enough null message in earlier chunk */ for(v = 0, null_msg = &oh->mesg[0]; v < oh->nmesgs; v++, null_msg++) { if(H5O_NULL_ID == null_msg->type->id && curr_msg->chunkno > null_msg->chunkno && curr_msg->raw_size <= null_msg->raw_size) { + H5O_chunk_proxy_t *null_chk_proxy; /* Chunk that null message is in */ + H5O_chunk_proxy_t *curr_chk_proxy; /* Chunk that message is in */ + unsigned null_chk_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting null chunk */ + unsigned curr_chk_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting curr chunk */ unsigned old_chunkno; /* Old message information */ uint8_t *old_raw; @@ -1381,15 +1534,19 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) old_chunkno = curr_msg->chunkno; old_raw = curr_msg->raw; + /* Protect chunks */ + if(NULL == (null_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, null_msg->chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + if(NULL == (curr_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + /* Copy raw data for non-null message to new chunk */ HDmemcpy(null_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); - /* Mark null message's chunk as dirty, since the raw data image changed */ - oh->chunk[null_msg->chunkno].dirty = TRUE; - /* Point non-null message at null message's space */ curr_msg->chunkno = null_msg->chunkno; curr_msg->raw = null_msg->raw; + curr_chk_flags |= H5AC__DIRTIED_FLAG; /* Change information for null message */ if(curr_msg->raw_size == null_msg->raw_size) { @@ -1400,18 +1557,24 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* Mark null message dirty */ null_msg->dirty = TRUE; + null_chk_flags |= H5AC__DIRTIED_FLAG; + + /* Release current chunk, marking it dirty */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, curr_chk_proxy, curr_chk_flags) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") /* Check for gap in null message's chunk */ if(oh->chunk[old_chunkno].gap > 0) { /* Eliminate the gap in the chunk */ - if(H5O_eliminate_gap(oh, null_msg, + if(H5O_eliminate_gap(f, dxpl_id, oh, null_chk_proxy, &null_chk_flags, null_msg, ((oh->chunk[old_chunkno].image + oh->chunk[old_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[old_chunkno].gap)), oh->chunk[old_chunkno].gap) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") - - /* Set the gap size to zero for the chunk */ - oh->chunk[old_chunkno].gap = 0; } /* end if */ + + /* Release null chunk, marking it dirty */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, null_chk_proxy, null_chk_flags) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") } /* end if */ else { unsigned new_null_msg; /* Message index for new null message */ @@ -1423,8 +1586,12 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* Adjust the size of the null message being eliminated */ null_msg->raw_size = curr_msg->raw_size; + /* Mark null message dirty */ + null_msg->dirty = TRUE; + null_chk_flags |= H5AC__DIRTIED_FLAG; + /* Add the gap to the chunk */ - if(H5O_add_gap(oh, null_msg->chunkno, v, null_msg->raw + null_msg->raw_size, gap_size) < 0) + if(H5O_add_gap(f, dxpl_id, oh, null_chk_proxy, &null_chk_flags, v, null_msg->raw + null_msg->raw_size, gap_size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk") /* Re-use message # for new null message taking place of non-null message */ @@ -1437,6 +1604,7 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* Mark null message dirty */ null_msg->dirty = TRUE; + null_chk_flags |= H5AC__DIRTIED_FLAG; /* Create new null message for previous location of non-null message */ if(oh->nmesgs >= oh->alloc_nmesgs) { @@ -1451,6 +1619,10 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) new_null_msg = oh->nmesgs++; } /* end else */ + /* Release null message's chunk, marking it dirty */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, null_chk_proxy, null_chk_flags) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + /* Initialize new null message to take over non-null message's location */ oh->mesg[new_null_msg].type = H5O_MSG_NULL; oh->mesg[new_null_msg].native = NULL; @@ -1460,18 +1632,20 @@ H5O_move_msgs_forward(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* Mark new null message dirty */ oh->mesg[new_null_msg].dirty = TRUE; + curr_chk_flags |= H5AC__DIRTIED_FLAG; /* Check for gap in new null message's chunk */ if(oh->chunk[old_chunkno].gap > 0) { /* Eliminate the gap in the chunk */ - if(H5O_eliminate_gap(oh, &oh->mesg[new_null_msg], + if(H5O_eliminate_gap(f, dxpl_id, oh, curr_chk_proxy, &curr_chk_flags, &oh->mesg[new_null_msg], ((oh->chunk[old_chunkno].image + oh->chunk[old_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[old_chunkno].gap)), oh->chunk[old_chunkno].gap) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") - - /* Set the gap size to zero for the chunk */ - oh->chunk[old_chunkno].gap = 0; } /* end if */ + + /* Release new null message's chunk, marking it dirty */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, curr_chk_proxy, curr_chk_flags) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") } /* end else */ /* Indicate that we packed messages */ @@ -1520,7 +1694,7 @@ done: *------------------------------------------------------------------------- */ static htri_t -H5O_merge_null(H5F_t *f, H5O_t *oh, hid_t dxpl_id) +H5O_merge_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh) { hbool_t merged_msg; /* Flag to indicate that messages were merged */ hbool_t did_merging = FALSE; /* Whether any messages were merged */ @@ -1554,11 +1728,14 @@ H5O_merge_null(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* Loop over messages again, looking for null message in same chunk */ for(v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++) { if(u != v && H5O_NULL_ID == curr_msg2->type->id && curr_msg->chunkno == curr_msg2->chunkno) { + ssize_t adj_raw; /* Amount to adjust raw message pointer */ + size_t adj_raw_size; /* Amount to adjust raw message size */ /* Check for second message after first message */ if((curr_msg->raw + curr_msg->raw_size) == (curr_msg2->raw - H5O_SIZEOF_MSGHDR_OH(oh))) { /* Extend first null message length to cover second null message */ - curr_msg->raw_size += (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); + adj_raw = 0; + adj_raw_size = H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size; /* Message has been merged */ merged_msg = TRUE; @@ -1566,8 +1743,8 @@ H5O_merge_null(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* Check for second message before first message */ else if((curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == (curr_msg2->raw + curr_msg2->raw_size)) { /* Adjust first message address and extend length to cover second message */ - curr_msg->raw -= (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); - curr_msg->raw_size += (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); + adj_raw = -((ssize_t)(H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size)); + adj_raw_size = H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size; /* Message has been merged */ merged_msg = TRUE; @@ -1575,12 +1752,26 @@ H5O_merge_null(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* Second message has been merged, delete it */ if(merged_msg) { + H5O_chunk_proxy_t *curr_chk_proxy; /* Chunk that message is in */ + /* Release any information/memory for second message */ H5O_msg_free_mesg(curr_msg2); + /* Protect chunk */ + if(NULL == (curr_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + + /* Adjust first message address and extend length to cover second message */ + curr_msg->raw += adj_raw; + curr_msg->raw_size += adj_raw_size; + /* Mark first message as dirty */ curr_msg->dirty = TRUE; + /* Release new null message's chunk, marking it dirty */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, curr_chk_proxy, H5AC__DIRTIED_FLAG) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + /* Remove second message from list of messages */ if(v < (oh->nmesgs - 1)) HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t)); @@ -1591,7 +1782,7 @@ H5O_merge_null(H5F_t *f, H5O_t *oh, hid_t dxpl_id) /* If the merged message is too large, shrink the chunk */ if(curr_msg->raw_size >= H5O_MESG_MAX_SIZE) - if(H5O_alloc_shrink_chunk(f, oh, dxpl_id, curr_msg->chunkno) < 0) + if(H5O_alloc_shrink_chunk(f, dxpl_id, oh, curr_msg->chunkno) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "unable to shrink chunk") /* Get out of loop */ @@ -1676,6 +1867,20 @@ H5O_remove_empty_chunks(H5F_t *f, hid_t dxpl_id, H5O_t *oh) /* Decode current continuation message if necessary */ H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, cont_msg, FAIL) + /* Check if the chunkno needs to be set */ + /* (should only occur when the continuation message is first decoded) */ + if(0 == ((H5O_cont_t *)(cont_msg->native))->chunkno) { + unsigned w; /* Local index variable */ + + /* Find chunk that this continuation message points to */ + for(w = 0; w < oh->nchunks; w++) + if(oh->chunk[w].addr == ((H5O_cont_t *)(cont_msg->native))->addr) { + ((H5O_cont_t *)(cont_msg->native))->chunkno = w; + break; + } /* end if */ + HDassert(((H5O_cont_t *)(cont_msg->native))->chunkno > 0); + } /* end if */ + /* Check for correct chunk to delete */ if(oh->chunk[null_msg->chunkno].addr == ((H5O_cont_t *)(cont_msg->native))->addr) break; @@ -1684,6 +1889,7 @@ H5O_remove_empty_chunks(H5F_t *f, hid_t dxpl_id, H5O_t *oh) /* Must be a continuation message that points to chunk containing null message */ HDassert(v < oh->nmesgs); HDassert(cont_msg); + HDassert(((H5O_cont_t *)(cont_msg->native))->chunkno == null_msg->chunkno); /* Initialize information about null message */ null_msg_no = u; @@ -1698,12 +1904,28 @@ H5O_remove_empty_chunks(H5F_t *f, hid_t dxpl_id, H5O_t *oh) */ /* Free memory for chunk image */ - (void)H5FL_BLK_FREE(chunk_image, oh->chunk[null_msg->chunkno].image); + oh->chunk[null_msg->chunkno].image = H5FL_BLK_FREE(chunk_image, oh->chunk[null_msg->chunkno].image); /* Remove chunk from list of chunks */ - if(null_msg->chunkno < (oh->nchunks - 1)) + if(null_msg->chunkno < (oh->nchunks - 1)) { HDmemmove(&oh->chunk[null_msg->chunkno], &oh->chunk[null_msg->chunkno + 1], ((oh->nchunks - 1) - null_msg->chunkno) * sizeof(H5O_chunk_t)); + /* Adjust chunk number for any chunk proxies that are in the cache */ + for(u = null_msg->chunkno; u < (oh->nchunks - 1); u++) { + unsigned chk_proxy_status = 0; /* Metadata cache status of chunk proxy for chunk */ + + /* Check the chunk proxy's status in the metadata cache */ + if(H5AC_get_entry_status(f, oh->chunk[u].addr, &chk_proxy_status) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to check metadata cache status for chunk proxy") + + /* If the entry is in the cache, update its chunk index */ + if(chk_proxy_status & H5AC_ES__IN_CACHE) { + if(H5O_chunk_update_idx(f, dxpl_id, oh, u) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to update index for chunk proxy") + } /* end if */ + } /* end for */ + } /* end if */ + /* Decrement # of chunks */ /* (Don't bother reducing size of chunk array for now -QAK) */ oh->nchunks--; @@ -1737,9 +1959,24 @@ H5O_remove_empty_chunks(H5F_t *f, hid_t dxpl_id, H5O_t *oh) /* Decode current continuation message if necessary */ H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, curr_msg, FAIL) - /* Check for pointer to chunk after deleted chunk */ - if(((H5O_cont_t *)(curr_msg->native))->chunkno > deleted_chunkno) - ((H5O_cont_t *)(curr_msg->native))->chunkno--; + /* Check if the chunkno needs to be set */ + /* (should only occur when the continuation message is first decoded) */ + if(0 == ((H5O_cont_t *)(curr_msg->native))->chunkno) { + unsigned w; /* Local index variable */ + + /* Find chunk that this continuation message points to */ + for(w = 0; w < oh->nchunks; w++) + if(oh->chunk[w].addr == ((H5O_cont_t *)(curr_msg->native))->addr) { + ((H5O_cont_t *)(curr_msg->native))->chunkno = w; + break; + } /* end if */ + HDassert(((H5O_cont_t *)(curr_msg->native))->chunkno > 0); + } /* end if */ + else { + /* Check for pointer to chunk after deleted chunk */ + if(((H5O_cont_t *)(curr_msg->native))->chunkno > deleted_chunkno) + ((H5O_cont_t *)(curr_msg->native))->chunkno--; + } /* end else */ } /* end if */ } /* end for */ @@ -1799,14 +2036,14 @@ H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id) rescan_header = FALSE; /* Scan for messages that can be moved earlier in chunks */ - result = H5O_move_msgs_forward(f, oh, dxpl_id); + result = H5O_move_msgs_forward(f, dxpl_id, oh); if(result < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't move header messages forward") if(result > 0) rescan_header = TRUE; /* Scan for adjacent null messages & merge them */ - result = H5O_merge_null(f, oh, dxpl_id); + result = H5O_merge_null(f, dxpl_id, oh); if(result < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack null header messages") if(result > 0) @@ -1843,13 +2080,11 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5O_alloc_shrink_chunk(H5F_t *f, - H5O_t *oh, - hid_t dxpl_id, - unsigned chunkno) +H5O_alloc_shrink_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno) { H5O_chunk_t *chunk = &oh->chunk[chunkno]; /* Chunk to shrink */ - H5O_mesg_t *curr_msg; + H5O_chunk_proxy_t *chk_proxy = NULL; /* Metadata cache proxy for chunk to shrink */ + H5O_mesg_t *curr_msg; /* Current message to examine */ uint8_t *old_image = chunk->image; /* Old address of chunk's image in memory */ size_t old_size = chunk->size; /* Old size of chunk */ size_t new_size = chunk->size - chunk->gap; /* Size of shrunk chunk */ @@ -1866,20 +2101,25 @@ H5O_alloc_shrink_chunk(H5F_t *f, FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_shrink_chunk) /* check args */ - HDassert(f != NULL); + HDassert(f); + HDassert(oh); + + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk") /* Loop backwards to increase the chance of seeing more null messages at the * end of the chunk. Note that we rely on unsigned u wrapping around at the * end. */ - for (u = oh->nmesgs - 1, curr_msg = &oh->mesg[u]; u < oh->nmesgs; u--, curr_msg--) { - if ((H5O_NULL_ID == curr_msg->type->id) && (chunkno == curr_msg->chunkno)) { + for(u = oh->nmesgs - 1, curr_msg = &oh->mesg[u]; u < oh->nmesgs; u--, curr_msg--) { + if((H5O_NULL_ID == curr_msg->type->id) && (chunkno == curr_msg->chunkno)) { size_t shrink_size = curr_msg->raw_size + sizeof_msghdr; /* Amount to shrink the chunk by */ /* If the current message is not at the end of the chunk, copy the * data after it (except the checksum). */ - if (curr_msg->raw + curr_msg->raw_size + if(curr_msg->raw + curr_msg->raw_size < old_image + new_size - sizeof_chksum) { unsigned v; /* Index */ H5O_mesg_t *curr_msg2; @@ -1890,8 +2130,8 @@ H5O_alloc_shrink_chunk(H5F_t *f, (size_t)(old_image + new_size - sizeof_chksum - src)); /* Update the raw data pointers for messages after this one */ - for (v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++) - if ((chunkno == curr_msg2->chunkno) && (curr_msg2->raw > curr_msg->raw)) + for(v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++) + if((chunkno == curr_msg2->chunkno) && (curr_msg2->raw > curr_msg->raw)) curr_msg2->raw -= shrink_size; } /* end if */ @@ -1902,7 +2142,7 @@ H5O_alloc_shrink_chunk(H5F_t *f, H5O_msg_free_mesg(curr_msg); /* Remove the deleted null message from list of messages */ - if (u < (oh->nmesgs - 1)) + if(u < (oh->nmesgs - 1)) HDmemmove(&oh->mesg[u], &oh->mesg[u+1], ((oh->nmesgs - 1) - u) * sizeof(H5O_mesg_t)); /* Decrement # of messages */ @@ -1928,7 +2168,7 @@ H5O_alloc_shrink_chunk(H5F_t *f, /* update the new chunk size */ new_size += oh->mesg[oh->nmesgs].raw_size + sizeof_msghdr; - } + } /* end if */ /* Check for changing the chunk #0 data size enough to need adjusting the flags */ if(oh->version > H5O_VERSION_1 && chunkno == 0) { @@ -1936,19 +2176,19 @@ H5O_alloc_shrink_chunk(H5F_t *f, size_t orig_prfx_size = 1 << (oh->flags & H5O_HDR_CHUNK0_SIZE); /* Original prefix size */ /* Check for moving to a 1-byte size encoding */ - if (orig_prfx_size > 1 && chunk0_newsize <= 255) { + if(orig_prfx_size > 1 && chunk0_newsize <= 255) { less_prfx_size = orig_prfx_size - 1; new_size_flags = H5O_HDR_CHUNK0_1; adjust_size_flags = TRUE; } /* end if */ /* Check for moving to a 2-byte size encoding */ - else if (orig_prfx_size > 2 && chunk0_newsize <= 65535) { + else if(orig_prfx_size > 2 && chunk0_newsize <= 65535) { less_prfx_size = orig_prfx_size - 2; new_size_flags = H5O_HDR_CHUNK0_2; adjust_size_flags = TRUE; } /* end if */ /* Check for moving to a 4-byte size encoding */ - else if (orig_prfx_size > 4 && chunk0_newsize <= 4294967295) { + else if(orig_prfx_size > 4 && chunk0_newsize <= 4294967295) { less_prfx_size = orig_prfx_size - 4; new_size_flags = H5O_HDR_CHUNK0_4; adjust_size_flags = TRUE; @@ -1973,38 +2213,51 @@ H5O_alloc_shrink_chunk(H5F_t *f, chunk->size = new_size; chunk->image = H5FL_BLK_REALLOC(chunk_image, old_image, chunk->size); chunk->gap = 0; - chunk->dirty = TRUE; - if (NULL == oh->chunk[chunkno].image) + if(NULL == oh->chunk[chunkno].image) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Spin through existing messages, adjusting them */ - for (u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { - if (adjust_size_flags || (chunk->image != old_image)) + for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { + if(adjust_size_flags || (chunk->image != old_image)) /* Adjust raw addresses for messages in this chunk to reflect new 'image' address */ - if (curr_msg->chunkno == chunkno) + if(curr_msg->chunkno == chunkno) curr_msg->raw = chunk->image - less_prfx_size + (curr_msg->raw - old_image); /* Find continuation message which points to this chunk and adjust chunk's size */ /* (Chunk 0 doesn't have a continuation message that points to it and * its size is directly encoded in the object header) */ - if (chunkno > 0 && (H5O_CONT_ID == curr_msg->type->id) && - (((H5O_cont_t *)(curr_msg->native))->chunkno == chunkno)) { + if(chunkno > 0 && (H5O_CONT_ID == curr_msg->type->id) && + (((H5O_cont_t *)(curr_msg->native))->chunkno == chunkno)) { + H5O_chunk_proxy_t *cont_chk_proxy; /* Chunk that message is in */ + + /* Protect chunk */ + if(NULL == (cont_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk") + /* Adjust size of continuation message */ HDassert(((H5O_cont_t *)(curr_msg->native))->size == old_size); ((H5O_cont_t *)(curr_msg->native))->size = chunk->size; /* Flag continuation message as dirty */ curr_msg->dirty = TRUE; + + /* Release chunk, marking it dirty */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, cont_chk_proxy, H5AC__DIRTIED_FLAG) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") } /* end if */ } /* end for */ HDassert(new_size <= old_size); /* Free the unused space in the file */ - if (H5MF_xfree(f, H5FD_MEM_OHDR, dxpl_id, chunk->addr + new_size, (hsize_t)(old_size - new_size)) < 0) + if(H5MF_xfree(f, H5FD_MEM_OHDR, dxpl_id, chunk->addr + new_size, (hsize_t)(old_size - new_size)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to shrink object header chunk") done: + /* Release chunk, marking it dirty */ + if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy, H5AC__DIRTIED_FLAG) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + FUNC_LEAVE_NOAPI(ret_value) } /* H5O_alloc_shrink_chunk() */ diff --git a/src/H5Oattribute.c b/src/H5Oattribute.c index 89aeaa0..d1ae64c 100644 --- a/src/H5Oattribute.c +++ b/src/H5Oattribute.c @@ -223,7 +223,6 @@ H5O_attr_create(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr) { H5O_t *oh = NULL; /* Pointer to actual object header */ H5O_ainfo_t ainfo; /* Attribute information for object */ - unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */ htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */ herr_t ret_value = SUCCEED; /* Return value */ @@ -233,9 +232,9 @@ H5O_attr_create(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr) HDassert(loc); HDassert(attr); - /* Protect the object header to iterate over */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) - HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") + /* Pin the object header */ + if(NULL == (oh = H5O_pin(loc, dxpl_id))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header") /* Check if this object already has attribute information */ if(oh->version > H5O_VERSION_1) { @@ -396,12 +395,9 @@ H5O_attr_create(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr) if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") - /* Indicate that the object header was modified */ - oh_flags |= H5AC__DIRTIED_FLAG; - done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) - HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh && H5O_unpin(oh) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_attr_create() */ @@ -487,7 +483,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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, NULL, "unable to load object header") /* Check for attribute info stored */ @@ -544,7 +540,7 @@ H5O_attr_open_by_name(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) } /* end else */ done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, NULL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -628,7 +624,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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) 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 @@ -654,7 +650,7 @@ H5O_attr_open_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, } /* end if */ done: - if(oh && H5AC_unprotect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, NULL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -836,6 +832,8 @@ H5O_attr_write_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, unsigned UNUSED sequence, hbool_t *oh_modified, void *_udata/*in,out*/) { H5O_iter_wrt_t *udata = (H5O_iter_wrt_t *)_udata; /* Operator user data */ + H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */ + unsigned chk_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting chunk */ herr_t ret_value = H5_ITER_CONT; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_write_cb) @@ -847,14 +845,35 @@ H5O_attr_write_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, /* Check for correct attribute message to modify */ if(0 == HDstrcmp(((H5A_t *)mesg->native)->shared->name, udata->attr->shared->name)) { + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(udata->f, udata->dxpl_id, oh, mesg->chunkno))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load object header chunk") + + /* Allocate storage for the message's data, if necessary */ + if(NULL == ((H5A_t *)mesg->native)->shared->data) + if(NULL == (((H5A_t *)mesg->native)->shared->data = H5FL_BLK_MALLOC(attr_buf, udata->attr->shared->data_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR, "memory allocation failed") + + /* Copy the data into the header message */ + /* (Needs to occur before updating the shared message, or the hash + * value on the old & new messages will be the same) + */ + HDmemcpy(((H5A_t *)mesg->native)->shared->data, udata->attr->shared->data, udata->attr->shared->data_size); + + /* Mark the message as modified */ + mesg->dirty = TRUE; + chk_flags |= H5AC__DIRTIED_FLAG; + + /* Release chunk */ + if(H5O_chunk_unprotect(udata->f, udata->dxpl_id, oh, chk_proxy, chk_flags) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk") + chk_proxy = NULL; + /* Update the shared attribute in the SOHM storage */ if(mesg->flags & H5O_MSG_FLAG_SHARED) if(H5O_attr_update_shared(udata->f, udata->dxpl_id, oh, udata->attr, (H5O_shared_t *)mesg->native) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, H5_ITER_ERROR, "unable to update attribute in shared storage") - /* Mark message as dirty */ - mesg->dirty = TRUE; - /* Indicate that the object header was modified */ *oh_modified = TRUE; @@ -866,6 +885,10 @@ H5O_attr_write_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, } /* end if */ done: + /* Release chunk, if not already done */ + if(chk_proxy && H5O_chunk_unprotect(udata->f, udata->dxpl_id, oh, chk_proxy, chk_flags) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk") + FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_attr_write_cb() */ @@ -887,7 +910,6 @@ H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr) { H5O_t *oh = NULL; /* Pointer to actual object header */ H5O_ainfo_t ainfo; /* Attribute information for object */ - unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_write) @@ -896,9 +918,9 @@ H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr) HDassert(loc); HDassert(attr); - /* Protect the object header to iterate over */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) - HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") + /* Pin the object header */ + if(NULL == (oh = H5O_pin(loc, dxpl_id))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header") /* Check for attribute info stored */ ainfo.fheap_addr = HADDR_UNDEF; @@ -939,12 +961,9 @@ H5O_attr_write(const H5O_loc_t *loc, hid_t dxpl_id, H5A_t *attr) if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") - /* Indicate that the object header was modified */ - oh_flags |= H5AC__DIRTIED_FLAG; - done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) - HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh && H5O_unpin(oh) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_attr_write */ @@ -1015,6 +1034,8 @@ H5O_attr_rename_mod_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, unsigned UNUSED sequence, hbool_t *oh_modified, void *_udata/*in,out*/) { H5O_iter_ren_t *udata = (H5O_iter_ren_t *)_udata; /* Operator user data */ + H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */ + unsigned chk_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting chunk */ herr_t ret_value = H5_ITER_CONT; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_rename_mod_cb) @@ -1028,6 +1049,10 @@ H5O_attr_rename_mod_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, if(HDstrcmp(((H5A_t *)mesg->native)->shared->name, udata->old_name) == 0) { unsigned old_version = ((H5A_t *)mesg->native)->shared->version; /* Old version of the attribute */ + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(udata->f, udata->dxpl_id, oh, mesg->chunkno))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load object header chunk") + /* Change the name for the attribute */ H5MM_xfree(((H5A_t *)mesg->native)->shared->name); ((H5A_t *)mesg->native)->shared->name = H5MM_xstrdup(udata->new_name); @@ -1038,6 +1063,12 @@ H5O_attr_rename_mod_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, /* Mark the message as modified */ mesg->dirty = TRUE; + chk_flags |= H5AC__DIRTIED_FLAG; + + /* Release chunk */ + if(H5O_chunk_unprotect(udata->f, udata->dxpl_id, oh, chk_proxy, chk_flags) < 0) + HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk") + chk_proxy = NULL; /* Check for shared message */ if(mesg->flags & H5O_MSG_FLAG_SHARED) { @@ -1098,6 +1129,10 @@ H5O_attr_rename_mod_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, } /* end if */ done: + /* Release chunk, if not already done */ + if(chk_proxy && H5O_chunk_unprotect(udata->f, udata->dxpl_id, oh, chk_proxy, chk_flags) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to unprotect object header chunk") + FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_attr_rename_mod_cb() */ @@ -1120,7 +1155,6 @@ H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id, const char *old_name, { H5O_t *oh = NULL; /* Pointer to actual object header */ H5O_ainfo_t ainfo; /* Attribute information for object */ - unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_rename) @@ -1130,9 +1164,9 @@ H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id, const char *old_name, HDassert(old_name); HDassert(new_name); - /* Protect the object header to iterate over */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) - HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") + /* Pin the object header */ + if(NULL == (oh = H5O_pin(loc, dxpl_id))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header") /* Check for attribute info stored */ ainfo.fheap_addr = HADDR_UNDEF; @@ -1184,12 +1218,9 @@ H5O_attr_rename(const H5O_loc_t *loc, hid_t dxpl_id, const char *old_name, if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") - /* Indicate that the object header was modified */ - oh_flags |= H5AC__DIRTIED_FLAG; - done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) - HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh && H5O_unpin(oh) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_attr_rename */ @@ -1226,7 +1257,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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -1244,7 +1275,7 @@ H5O_attr_iterate_real(hid_t loc_id, const H5O_loc_t *loc, hid_t dxpl_id, HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified") /* Release the object header */ - if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") oh = NULL; @@ -1258,7 +1289,7 @@ H5O_attr_iterate_real(hid_t loc_id, const H5O_loc_t *loc, hid_t dxpl_id, HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "error building attribute table") /* Release the object header */ - if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") oh = NULL; @@ -1273,7 +1304,7 @@ H5O_attr_iterate_real(hid_t loc_id, const H5O_loc_t *loc, hid_t dxpl_id, done: /* Release resources */ - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") if(atable.attrs && H5A_attr_release_table(&atable) < 0) HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table") @@ -1511,7 +1542,6 @@ H5O_attr_remove(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) H5O_t *oh = NULL; /* Pointer to actual object header */ H5O_ainfo_t ainfo; /* Attribute information for object */ htri_t ainfo_exists = FALSE; /* Whether the attribute info exists in the file */ - unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_attr_remove) @@ -1520,9 +1550,9 @@ H5O_attr_remove(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) HDassert(loc); HDassert(name); - /* Protect the object header to iterate over */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) - HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") + /* Pin the object header */ + if(NULL == (oh = H5O_pin(loc, dxpl_id))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header") /* Check for attribute info stored */ ainfo.fheap_addr = HADDR_UNDEF; @@ -1568,12 +1598,9 @@ H5O_attr_remove(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") - /* Indicate that the object header was modified */ - oh_flags |= H5AC__DIRTIED_FLAG; - done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) - HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh && H5O_unpin(oh) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_attr_remove() */ @@ -1599,7 +1626,6 @@ H5O_attr_remove_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, H5O_t *oh = NULL; /* Pointer to actual object header */ H5O_ainfo_t ainfo; /* Attribute information for object */ htri_t ainfo_exists = FALSE; /* Whether the attribute info exists in the file */ - unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Metadata cache flags for object header */ H5A_attr_table_t atable = {0, NULL}; /* Table of attributes */ herr_t ret_value = SUCCEED; /* Return value */ @@ -1608,9 +1634,9 @@ H5O_attr_remove_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, /* Check arguments */ HDassert(loc); - /* Protect the object header to iterate over */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) - HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") + /* Pin the object header */ + if(NULL == (oh = H5O_pin(loc, dxpl_id))) + HGOTO_ERROR(H5E_ATTR, H5E_CANTPIN, FAIL, "unable to pin object header") /* Check for attribute info stored */ ainfo.fheap_addr = HADDR_UNDEF; @@ -1664,12 +1690,9 @@ H5O_attr_remove_by_idx(const H5O_loc_t *loc, H5_index_t idx_type, if(H5O_touch_oh(loc->file, dxpl_id, oh, FALSE) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update time on object") - /* Indicate that the object header was modified */ - oh_flags |= H5AC__DIRTIED_FLAG; - done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) - HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh && H5O_unpin(oh) < 0) + HDONE_ERROR(H5E_ATTR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") if(atable.attrs && H5A_attr_release_table(&atable) < 0) HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table") @@ -1797,7 +1820,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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -1835,7 +1858,7 @@ H5O_attr_exists(const H5O_loc_t *loc, const char *name, hid_t dxpl_id) } /* end else */ done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -1951,7 +1974,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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_ATTR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Retrieve # of attributes on object */ @@ -1962,7 +1985,7 @@ H5O_attr_count(const H5O_loc_t *loc, hid_t dxpl_id) ret_value = (int)nattrs; done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_ATTR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Ocache.c b/src/H5Ocache.c index d3e736e..8fe3cf5 100644 --- a/src/H5Ocache.c +++ b/src/H5Ocache.c @@ -39,6 +39,7 @@ #include "H5FLprivate.h" /* Free lists */ #include "H5MFprivate.h" /* File memory management */ #include "H5Opkg.h" /* Object headers */ +#include "H5WBprivate.h" /* Wrapped Buffers */ /****************/ @@ -74,33 +75,69 @@ 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, const void *_udata1, + void *_udata2); +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 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_size(const H5F_t *f, const H5O_chunk_proxy_t *chk_proxy, size_t *size_ptr); + +/* Chunk proxy routines */ +static herr_t H5O_chunk_proxy_dest(H5O_chunk_proxy_t *chunk_proxy); + +/* Chunk routines */ +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); +static herr_t H5O_chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno); + +/* Misc. routines */ +static herr_t H5O_add_cont_msg(H5O_cont_msgs_t *cont_msg_info, + const H5O_cont_t *cont); + /*********************/ /* Package Variables */ /*********************/ +/* 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_size_func_t)H5O_size, +}}; + +/* 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_size_func_t)H5O_cache_chk_size, +}}; + +/* Declare external the free list for H5O_unknown_t's */ +H5FL_EXTERN(H5O_unknown_t); + +/* Declare extern the free list for H5O_chunk_proxy_t's */ +H5FL_EXTERN(H5O_chunk_proxy_t); + +/* Declare the free list for H5O_cont_t sequences */ +H5FL_SEQ_DEFINE(H5O_cont_t); + /*****************************/ /* Library Private Variables */ /*****************************/ -/* Declare external the free list for H5O_unknown_t's */ -H5FL_EXTERN(H5O_unknown_t); - /*******************/ /* Local Variables */ /*******************/ -/* H5O 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_size_func_t)H5O_size, -}}; /*------------------------------------------------------------------------- @@ -120,18 +157,17 @@ const H5AC_class_t H5AC_OHDR[1] = {{ */ static H5O_t * H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, - void UNUSED * _udata2) + void *_udata2) { H5O_t *oh = NULL; /* Object header read in */ + H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata2; /* User data for callback */ + H5WB_t *wb = NULL; /* Wrapped buffer for prefix data */ uint8_t read_buf[H5O_SPEC_READ_SIZE]; /* Buffer for speculative read */ const uint8_t *p; /* Pointer into buffer to decode */ + uint8_t *buf; /* Buffer to decode */ size_t spec_read_size; /* Size of buffer to speculatively read in */ size_t prefix_size; /* Size of object header prefix */ - unsigned nmesgs; /* Total # of messages in this object header */ - unsigned curmesg = 0; /* Current message being decoded in object header */ - unsigned merged_null_msgs = 0; /* Number of null messages merged together */ - haddr_t chunk_addr; /* Address of first chunk */ - size_t chunk_size; /* Size of first chunk */ + size_t buf_size; /* Size of prefix+chunk #0 buffer */ haddr_t eoa; /* Relative end of file address */ H5O_t *ret_value; /* Return value */ @@ -141,7 +177,9 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, HDassert(f); HDassert(H5F_addr_defined(addr)); HDassert(!_udata1); - HDassert(!_udata2); + 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))) @@ -160,8 +198,8 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") /* File-specific, non-stored information */ - oh->sizeof_size = H5F_SIZEOF_SIZE(f); - oh->sizeof_addr = H5F_SIZEOF_ADDR(f); + oh->sizeof_size = H5F_SIZEOF_SIZE(udata->common.f); + oh->sizeof_addr = H5F_SIZEOF_ADDR(udata->common.f); /* Check for presence of magic number */ /* (indicates version 2 or later) */ @@ -179,9 +217,6 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, if(oh->flags & ~H5O_HDR_ALL_FLAGS) HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "unknown object header status flag(s)") - /* Number of messages (to allocate initially) */ - nmesgs = 1; - /* Number of links to object (unless overridden by refcount message) */ oh->nlink = 1; @@ -206,7 +241,7 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, UINT16DECODE(p, oh->max_compact); UINT16DECODE(p, oh->min_dense); if(oh->max_compact < oh->min_dense) - HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header attribute phase change values") + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "bad object header attribute phase change values") } /* end if */ else { oh->max_compact = H5O_CRT_ATTR_MAX_COMPACT_DEF; @@ -216,26 +251,26 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, /* First chunk size */ switch(oh->flags & H5O_HDR_CHUNK0_SIZE) { case 0: /* 1 byte size */ - chunk_size = *p++; + oh->chunk0_size = *p++; break; case 1: /* 2 byte size */ - UINT16DECODE(p, chunk_size); + UINT16DECODE(p, oh->chunk0_size); break; case 2: /* 4 byte size */ - UINT32DECODE(p, chunk_size); + UINT32DECODE(p, oh->chunk0_size); break; case 3: /* 8 byte size */ - UINT64DECODE(p, chunk_size); + UINT64DECODE(p, oh->chunk0_size); break; default: HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "bad size for chunk 0") } /* end switch */ - if(chunk_size > 0 && chunk_size < H5O_SIZEOF_MSGHDR_OH(oh)) - HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header chunk size") + if(oh->chunk0_size > 0 && oh->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "bad object header chunk size") } /* end if */ else { /* Version */ @@ -250,7 +285,7 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, p++; /* Number of messages */ - UINT16DECODE(p, nmesgs); + UINT16DECODE(p, udata->v1_pfx_nmesgs); /* Link count */ UINT32DECODE(p, oh->nlink); @@ -263,10 +298,10 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, oh->min_dense = 0; /* First chunk size */ - UINT32DECODE(p, chunk_size); - if((nmesgs > 0 && chunk_size < H5O_SIZEOF_MSGHDR_OH(oh)) || - (nmesgs == 0 && chunk_size > 0)) - HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header chunk size") + UINT32DECODE(p, oh->chunk0_size); + if((udata->v1_pfx_nmesgs > 0 && oh->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) || + (udata->v1_pfx_nmesgs == 0 && oh->chunk0_size > 0)) + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "bad object header chunk size") /* Reserved, in version 1 (for 8-byte alignment padding) */ p += 4; @@ -276,356 +311,44 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, prefix_size = (size_t)(p - (const uint8_t *)read_buf); HDassert((size_t)prefix_size == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); - /* Compute first chunk address */ - chunk_addr = addr + (hsize_t)prefix_size; - - /* Allocate the message array */ - oh->alloc_nmesgs = (nmesgs > 0) ? nmesgs : 1; - if(NULL == (oh->mesg = H5FL_SEQ_MALLOC(H5O_mesg_t, oh->alloc_nmesgs))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed") - - /* Read each chunk from disk */ - while(H5F_addr_defined(chunk_addr)) { - unsigned chunkno; /* Current chunk's index */ -#ifndef NDEBUG - unsigned nullcnt; /* Count of null messages (for sanity checking gaps in chunks) */ -#endif /* NDEBUG */ - uint8_t *eom_ptr; /* Pointer to end of messages for a chunk */ - - /* Increase chunk array size, if necessary */ - if(oh->nchunks >= oh->alloc_nchunks) { - unsigned na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */ - H5O_chunk_t *x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, (size_t)na); - - if(!x) - HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed") - oh->alloc_nchunks = na; - oh->chunk = x; - } /* end if */ - - /* Init the chunk data info */ - chunkno = oh->nchunks++; - oh->chunk[chunkno].dirty = FALSE; - oh->chunk[chunkno].gap = 0; - if(chunkno == 0) { - /* First chunk's 'image' includes room for the object header prefix */ - oh->chunk[0].addr = addr; - oh->chunk[0].size = chunk_size + H5O_SIZEOF_HDR(oh); - } /* end if */ - else { - oh->chunk[chunkno].addr = chunk_addr; - oh->chunk[chunkno].size = chunk_size; - } /* end else */ - if(NULL == (oh->chunk[chunkno].image = H5FL_BLK_MALLOC(chunk_image, oh->chunk[chunkno].size))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed") - - /* Handle chunk 0 as special case */ - if(chunkno == 0) { - /* Check for speculative read of first chunk containing all the data needed */ - if(spec_read_size >= oh->chunk[0].size) - HDmemcpy(oh->chunk[0].image, read_buf, oh->chunk[0].size); - else { - /* Copy the object header prefix into chunk 0's image */ - HDmemcpy(oh->chunk[0].image, read_buf, prefix_size); - - /* Read the chunk raw data */ - /* (probably re-reads some data we already retrieved, but since - * we have to do the I/O operation anyway, we might as - * well avoid memcpy()ing the data in our buffer already) - */ - if(H5F_block_read(f, H5FD_MEM_OHDR, chunk_addr, (oh->chunk[0].size - prefix_size), - dxpl_id, (oh->chunk[0].image + prefix_size)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header data") - } /* end else */ - - /* Point into chunk image to decode */ - p = oh->chunk[0].image + prefix_size; - } /* end if */ - else { - /* Read the chunk raw data */ - if(H5F_block_read(f, H5FD_MEM_OHDR, chunk_addr, chunk_size, dxpl_id, oh->chunk[chunkno].image) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header data") - - /* Point into chunk image to decode */ - p = oh->chunk[chunkno].image; - } /* end else */ - - /* Check for magic # on chunks > 0 in later versions of the format */ - if(chunkno > 0 && oh->version > H5O_VERSION_1) { - /* Magic number */ - if(HDmemcmp(p, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "wrong object header chunk signature") - p += H5_SIZEOF_MAGIC; - } /* end if */ - - /* Decode messages from this chunk */ - eom_ptr = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh)); -#ifndef NDEBUG - nullcnt = 0; -#endif /* NDEBUG */ - while(p < eom_ptr) { - unsigned mesgno; /* Current message to operate on */ - size_t mesg_size; /* Size of message read in */ - unsigned id; /* ID (type) of current message */ - uint8_t flags; /* Flags for current message */ - H5O_msg_crt_idx_t crt_idx = 0; /* Creation index for current message */ - - /* Decode message prefix info */ - - /* Version # */ - if(oh->version == H5O_VERSION_1) - UINT16DECODE(p, id) - else - id = *p++; - - /* Check for unknown message ID getting encoded in file */ - if(id == H5O_UNKNOWN_ID) - HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "'unknown' message ID encoded in file?!?") - - /* Message size */ - UINT16DECODE(p, mesg_size); - HDassert(mesg_size == H5O_ALIGN_OH(oh, mesg_size)); - - /* Message flags */ - flags = *p++; - if(flags & ~H5O_MSG_FLAG_BITS) - HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unknown flag for message") - if((flags & H5O_MSG_FLAG_SHARED) && (flags & H5O_MSG_FLAG_DONTSHARE)) - HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag combination for message") - if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN)) - HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag combination for message") - if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && !(flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN)) - HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag combination for message") - - /* Reserved bytes/creation index */ - if(oh->version == H5O_VERSION_1) - p += 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); - } /* end else */ - - /* Try to detect invalidly formatted object header message that - * extends past end of chunk. - */ - if(p + mesg_size > eom_ptr) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "corrupt object header") - -#ifndef NDEBUG - /* Increment count of null messages */ - if(H5O_NULL_ID == id) - nullcnt++; -#endif /* NDEBUG */ - - /* Check for combining two adjacent 'null' messages */ - if((H5F_INTENT(f) & H5F_ACC_RDWR) && - H5O_NULL_ID == id && oh->nmesgs > 0 && - H5O_NULL_ID == oh->mesg[oh->nmesgs - 1].type->id && - oh->mesg[oh->nmesgs - 1].chunkno == chunkno) { - - /* Combine adjacent null messages */ - mesgno = oh->nmesgs - 1; - oh->mesg[mesgno].raw_size += H5O_SIZEOF_MSGHDR_OH(oh) + mesg_size; - oh->mesg[mesgno].dirty = TRUE; - merged_null_msgs++; - } /* end if */ - else { - /* Check if we need to extend message table to hold the new message */ - if(oh->nmesgs >= oh->alloc_nmesgs) - if(H5O_alloc_msgs(oh, (size_t)1) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "can't allocate more space for messages") - - /* Get index for message */ - mesgno = oh->nmesgs++; - - /* Initialize information about message */ - oh->mesg[mesgno].dirty = FALSE; - 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_size = mesg_size; - oh->mesg[mesgno].chunkno = chunkno; - - /* Point unknown messages at 'unknown' message class */ - /* (Usually from future versions of the library) */ - if(id >= NELMTS(H5O_msg_class_g) || NULL == H5O_msg_class_g[id]) { - H5O_unknown_t *unknown; /* Pointer to "unknown" message info */ - - /* Allocate "unknown" message info */ - if(NULL == (unknown = H5FL_MALLOC(H5O_unknown_t))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed") - - /* Save the original message type ID */ - *unknown = id; - - /* Save 'native' form of unknown message */ - oh->mesg[mesgno].native = unknown; - - /* Set message to "unknown" class */ - oh->mesg[mesgno].type = H5O_msg_class_g[H5O_UNKNOWN_ID]; - - /* Check for "fail if unknown" message flag */ - if(flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN) - HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, NULL, "unknown message with 'fail if unknown' flag found") - /* Check for "mark if unknown" message flag, etc. */ - else if((flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN) && - !(flags & H5O_MSG_FLAG_WAS_UNKNOWN) && - (H5F_INTENT(f) & H5F_ACC_RDWR)) { - - /* Mark the message as "unknown" */ - /* This is a bit aggressive, since the application may - * never change anything about the object (metadata or - * raw data), but we can sort out the finer details - * when/if we start using the flag - QAK - */ - /* Also, it's possible that this functionality may not - * get invoked if the object header is brought into - * the metadata cache in some other "weird" way, like - * using H5Ocopy() - QAK - */ - oh->mesg[mesgno].flags |= H5O_MSG_FLAG_WAS_UNKNOWN; - - /* Mark the message and object header as dirty */ - oh->mesg[mesgno].dirty = TRUE; - oh->cache_info.is_dirty = TRUE; - } /* end if */ - } /* end if */ - else - /* Set message class for "known" messages */ - oh->mesg[mesgno].type = H5O_msg_class_g[id]; - } /* end else */ - - /* Advance decode pointer past message */ - p += mesg_size; + /* Compute the size of the buffer used */ + buf_size = oh->chunk0_size + (size_t)H5O_SIZEOF_HDR(oh); - /* Check for 'gap' at end of chunk */ - if((eom_ptr - p) > 0 && (eom_ptr - p) < H5O_SIZEOF_MSGHDR_OH(oh)) { - /* Gaps can only occur in later versions of the format */ - HDassert(oh->version > H5O_VERSION_1); + /* Check if the speculative read was large enough to parse the first chunk */ + if(spec_read_size < buf_size) { + /* Wrap the local buffer for serialized header info */ + if(NULL == (wb = H5WB_wrap(read_buf, sizeof(read_buf)))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't wrap buffer") - /* Gaps should only occur in chunks with no null messages */ - HDassert(nullcnt == 0); + /* Get a pointer to a buffer that's large enough for serialized header */ + if(NULL == (buf = (uint8_t *)H5WB_actual(wb, buf_size))) + HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "can't get actual buffer") - /* Set gap information for chunk */ - oh->chunk[chunkno].gap = (size_t)(eom_ptr - p); + /* Copy existing raw data into new buffer */ + HDmemcpy(buf, read_buf, spec_read_size); - /* Increment location in chunk */ - p += 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); - - /* Compute checksum on chunk */ - computed_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0); - - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "incorrect metadata checksum for object header chunk") - } /* end if */ - - /* Sanity check */ - HDassert(p == oh->chunk[chunkno].image + oh->chunk[chunkno].size); - - /* Check for another chunk to read in & parse */ - for(chunk_addr = HADDR_UNDEF; !H5F_addr_defined(chunk_addr) && curmesg < oh->nmesgs; ++curmesg) { - /* Check if next message to examine is a continuation message */ - if(H5O_CONT_ID == oh->mesg[curmesg].type->id) { - H5O_cont_t *cont; - unsigned ioflags = 0; /* Flags for decode routine */ - - /* Decode continuation message */ - cont = (H5O_cont_t *)(H5O_MSG_CONT->decode)(f, dxpl_id, NULL, 0, &ioflags, oh->mesg[curmesg].raw); - cont->chunkno = oh->nchunks; /*the next chunk to allocate */ - - /* Save 'native' form of continuation message */ - oh->mesg[curmesg].native = cont; - - /* Set up to read in next chunk */ - chunk_addr = cont->addr; - chunk_size = cont->size; - - /* Mark the object header as dirty if the message was changed by decoding */ - if((ioflags & H5O_DECODEIO_DIRTY) && (H5F_get_intent(f) & H5F_ACC_RDWR)) { - oh->mesg[curmesg].dirty = TRUE; - oh->cache_info.is_dirty = TRUE; - } - } /* end if */ - /* Check if next message to examine is a ref. count message */ - else if(H5O_REFCOUNT_ID == oh->mesg[curmesg].type->id) { - H5O_refcount_t *refcount; - unsigned ioflags = 0; /* Flags for decode routine */ - - /* Decode ref. count message */ - HDassert(oh->version > H5O_VERSION_1); - refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(f, dxpl_id, NULL, 0, &ioflags, oh->mesg[curmesg].raw); - - /* Save 'native' form of ref. count message */ - oh->mesg[curmesg].native = refcount; - - /* Set object header values */ - oh->has_refcount_msg = TRUE; - oh->nlink = *refcount; - - /* Mark the object header as dirty if the message was changed by decoding */ - if((ioflags & H5O_DECODEIO_DIRTY) && (H5F_get_intent(f) & H5F_ACC_RDWR)) { - oh->mesg[curmesg].dirty = TRUE; - oh->cache_info.is_dirty = TRUE; - } - } /* end if */ - /* Check if next message to examine is a link message */ - else if(H5O_LINK_ID == oh->mesg[curmesg].type->id) { - /* Increment the count of link messages */ - oh->link_msgs_seen++; - } /* end if */ - /* Check if next message to examine is an attribute message */ - else if(H5O_ATTR_ID == oh->mesg[curmesg].type->id) { - /* Increment the count of attribute messages */ - oh->attr_msgs_seen++; - } /* end if */ - } /* end for */ - } /* end while */ - - /* Mark the object header dirty if we've merged a message */ - if(merged_null_msgs) - oh->cache_info.is_dirty = TRUE; + /* 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 if */ + else + buf = read_buf; -/* Don't check for the incorrect # of object header messages bug unless we've - * enabled strict format checking. This allows for older files, created with - * a version of the library that had a bug in tracking the correct # of header - * messages to be read in without the library fussing about things. -QAK - */ -#ifdef H5_STRICT_FORMAT_CHECKS - /* Sanity check for the correct # of messages in object header */ - if(oh->version == H5O_VERSION_1) - if((oh->nmesgs + merged_null_msgs) != nmesgs) - HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - too few messages") -#else /* H5_STRICT_FORMAT_CHECKS */ - /* Check for incorrect # of messages in object header and if we have write - * access on the file, flag the object header as dirty, so it gets fixed. - */ - if(oh->version == H5O_VERSION_1) - if((oh->nmesgs + merged_null_msgs) != nmesgs && - (H5F_get_intent(f) & H5F_ACC_RDWR)) - oh->cache_info.is_dirty = TRUE; -#endif /* H5_STRICT_FORMAT_CHECKS */ + /* Parse the first chunk */ + if(H5O_chunk_deserialize(oh, 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") -#ifdef H5O_DEBUG -H5O_assert(oh); -#endif /* H5O_DEBUG */ + /* Note that we've loaded the object header from the file */ + udata->made_attempt = TRUE; /* Set return value */ ret_value = oh; 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 && oh) if(H5O_free(oh) < 0) @@ -663,7 +386,6 @@ H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t UNUSED addr, H5O_t * /* flush */ if(oh->cache_info.is_dirty) { uint8_t *p; /* Pointer to object header prefix buffer */ - unsigned u; /* Local index variable */ #ifdef H5O_DEBUG H5O_assert(oh); @@ -677,7 +399,10 @@ H5O_assert(oh); * on the entire block of memory needs to be updated if anything is * modified */ if(oh->version > H5O_VERSION_1) { - uint64_t chunk0_size = oh->chunk[0].size - H5O_SIZEOF_HDR(oh); /* Size of chunk 0's data */ + uint64_t chunk0_size; /* Size of chunk 0's data */ + + HDassert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh)); + chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh); /* Verify magic number */ HDassert(!HDmemcmp(p, H5O_HDR_MAGIC, H5_SIZEOF_MAGIC)); @@ -748,7 +473,7 @@ H5O_assert(oh); UINT32ENCODE(p, oh->nlink); /* First chunk size */ - UINT32ENCODE(p, (oh->chunk[0].size - H5O_SIZEOF_HDR(oh))); + UINT32ENCODE(p, (oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh))); /* Zero to alignment */ HDmemset(p, 0, (size_t)(H5O_SIZEOF_HDR(oh) - 12)); @@ -756,57 +481,14 @@ H5O_assert(oh); } /* end else */ HDassert((size_t)(p - oh->chunk[0].image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); - /* Mark chunk 0 as dirty, since the object header prefix has been updated */ - /* (this could be more sophisticated and track whether any prefix fields - * have been changed, which could save I/O accesses if the - * messages in chunk 0 haven't changed - QAK) - */ - HDassert(H5F_addr_eq(addr, oh->chunk[0].addr)); - oh->chunk[0].dirty = TRUE; - - /* Encode any dirty messages */ - if(H5O_flush_msgs(f, oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object header messages") - - /* Write each chunk to disk, if it's dirty */ - for(u = 0; u < oh->nchunks; u++) { - /* Sanity checks */ - if(oh->version > H5O_VERSION_1) - /* Make certain the magic # is present */ - HDassert(!HDmemcmp(oh->chunk[u].image, (u == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5_SIZEOF_MAGIC)); - else - /* Gaps should never occur in version 1 of the format */ - HDassert(oh->chunk[u].gap == 0); - - /* Write out chunk, if it's dirty */ - if(oh->chunk[u].dirty) { - /* Extra work, for later versions of the format */ - if(oh->version > H5O_VERSION_1) { - uint32_t metadata_chksum; /* Computed metadata checksum value */ - - /* Check for gap in chunk & zero it out */ - if(oh->chunk[u].gap) - HDmemset((oh->chunk[u].image + oh->chunk[u].size) - - (H5O_SIZEOF_CHKSUM + oh->chunk[u].gap), 0, oh->chunk[u].gap); - - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(oh->chunk[u].image, (oh->chunk[u].size - H5O_SIZEOF_CHKSUM), 0); - - /* Metadata checksum */ - p = oh->chunk[u].image + (oh->chunk[u].size - H5O_SIZEOF_CHKSUM); - UINT32ENCODE(p, metadata_chksum); - } /* end if */ - - /* Write the chunk out */ - HDassert(H5F_addr_defined(oh->chunk[u].addr)); - if(H5F_block_write(f, H5FD_MEM_OHDR, oh->chunk[u].addr, - oh->chunk[u].size, dxpl_id, oh->chunk[u].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 chunk as clean now */ - oh->chunk[u].dirty = FALSE; - } /* end if */ - } /* end for */ + /* 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") /* Mark object header as clean now */ oh->cache_info.is_dirty = FALSE; @@ -844,6 +526,7 @@ H5O_dest(H5F_t *f, H5O_t *oh) /* check args */ HDassert(oh); + HDassert(oh->rc == 0); /* Verify that node is clean */ HDassert(!oh->cache_info.is_dirty); @@ -892,17 +575,13 @@ H5O_clear(H5F_t *f, H5O_t *oh, hbool_t destroy) /* check args */ HDassert(oh); - /* Mark chunks as clean */ - for(u = 0; u < oh->nchunks; u++) - oh->chunk[u].dirty = FALSE; - /* Mark messages as clean */ for(u = 0; u < oh->nmesgs; u++) oh->mesg[u].dirty = FALSE; #ifndef NDEBUG - /* Reset the number of messages dirtied by decoding */ - oh->ndecode_dirtied = 0; + /* Reset the number of messages dirtied by decoding */ + oh->ndecode_dirtied = 0; #endif /* NDEBUG */ /* Mark whole header as clean */ @@ -934,22 +613,767 @@ done: static herr_t H5O_size(const H5F_t UNUSED *f, const H5O_t *oh, size_t *size_ptr) { - size_t size; /* Running sum of the object header's size */ - unsigned u; /* Local index variable */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_size) /* check args */ HDassert(oh); HDassert(size_ptr); - /* Add sizes of all the chunks */ - /* (includes size of prefix, in chunk 0) */ - for(u = 0, size = 0; u < oh->nchunks; u++) - size += oh->chunk[u].size; - - *size_ptr = size; + /* Report the object header's prefix+first chunk length */ + *size_ptr = (size_t)H5O_SIZEOF_HDR(oh) + oh->chunk0_size; FUNC_LEAVE_NOAPI(SUCCEED) } /* H5O_size() */ + +/*------------------------------------------------------------------------- + * Function: H5O_cache_chk_load + * + * Purpose: Loads an object header continuation chunk from disk. + * + * Return: Success: Pointer to the new object header chunk proxy. + * Failure: NULL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jul 12 2008 + * + *------------------------------------------------------------------------- + */ +static H5O_chunk_proxy_t * +H5O_cache_chk_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, + void *_udata2) +{ + H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk proxy object */ + H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata2; /* User data for callback */ + H5WB_t *wb = NULL; /* Wrapped buffer for prefix data */ + uint8_t chunk_buf[H5O_SPEC_READ_SIZE]; /* Buffer for speculative read */ + uint8_t *buf; /* Buffer to decode */ + H5O_chunk_proxy_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_cache_chk_load) + + /* Check arguments */ + HDassert(f); + HDassert(H5F_addr_defined(addr)); + HDassert(udata); + HDassert(udata->oh); + + /* 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->chunk_size))) + HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "can't get actual buffer") + + /* Read rest of the raw data */ + if(H5F_block_read(f, H5FD_MEM_OHDR, addr, udata->chunk_size, dxpl_id, buf) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read object header continuation chunk") + + /* Check if we are still decoding the object header */ + /* (as opposed to bringing a piece of it back from the file) */ + if(udata->decoding) { + /* Sanity check */ + HDassert(udata->common.f); + HDassert(udata->common.cont_msg_info); + + /* Parse the chunk */ + if(H5O_chunk_deserialize(udata->oh, addr, udata->chunk_size, buf, &(udata->common), &chk_proxy->cache_info.is_dirty) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize object header chunk") + + /* Set the fields for the chunk proxy */ + chk_proxy->oh = udata->oh; + chk_proxy->chunkno = udata->oh->nchunks - 1; + } /* end if */ + else { + /* Sanity check */ + HDassert(udata->chunkno < udata->oh->nchunks); + + /* Set the fields for the chunk proxy */ + chk_proxy->oh = udata->oh; + chk_proxy->chunkno = udata->chunkno; + + /* 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)); + } /* end else */ + + /* Increment reference count of object header */ + if(H5O_inc_rc(udata->oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "can't increment reference count on object header") + + /* Set return value */ + 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() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_cache_chk_flush + * + * Purpose: Flushes (and destroys) an object header continuation chunk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jul 12 2008 + * + *------------------------------------------------------------------------- + */ +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 UNUSED * flags_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_cache_chk_flush) + + /* 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(H5O_cache_chk_dest) + + /* 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)); + + /* 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 */ + + /* 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_dest() */ + + +/*------------------------------------------------------------------------- + * 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 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_cache_chk_clear(H5F_t *f, H5O_chunk_proxy_t *chk_proxy, hbool_t destroy) +{ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT(H5O_cache_chk_clear) + + /* check args */ + HDassert(chk_proxy); + + /* 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; + + 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_clear() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_cache_chk_size + * + * 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. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 12, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_cache_chk_size(const H5F_t UNUSED *f, const H5O_chunk_proxy_t *chk_proxy, size_t *size_ptr) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_cache_chk_size) + + /* check args */ + HDassert(chk_proxy); + HDassert(size_ptr); + + /* Report the object header continuation chunk's length */ + *size_ptr = chk_proxy->oh->chunk[chk_proxy->chunkno].size; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5O_cache_chk_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_add_cont_msg + * + * Purpose: Add information from a continuation message to the list of + * continuation messages in the object header + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 12, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_add_cont_msg(H5O_cont_msgs_t *cont_msg_info, const H5O_cont_t *cont) +{ + unsigned contno; /* Continuation message index */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_add_cont_msg) + + /* Check arguments */ + HDassert(cont_msg_info); + HDassert(cont); + + /* Increase chunk array size, if necessary */ + if(cont_msg_info->nmsgs >= cont_msg_info->alloc_nmsgs) { + unsigned na = MAX(H5O_NCHUNKS, cont_msg_info->alloc_nmsgs * 2); /* Double # of messages allocated */ + H5O_cont_t *x = H5FL_SEQ_REALLOC(H5O_cont_t, cont_msg_info->msgs, (size_t)na); + + if(!x) + HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "memory allocation failed") + cont_msg_info->alloc_nmsgs = na; + cont_msg_info->msgs = x; + } /* end if */ + + /* Init the continuation message info */ + contno = cont_msg_info->nmsgs++; + cont_msg_info->msgs[contno].addr = cont->addr; + cont_msg_info->msgs[contno].size = cont->size; + cont_msg_info->msgs[contno].chunkno = cont->chunkno; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_add_cont_msg() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_chunk_deserialize + * + * Purpose: Deserialize a chunk for an object header + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 12, 2008 + * + *------------------------------------------------------------------------- + */ +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 */ + uint8_t *eom_ptr; /* Pointer to end of messages for a chunk */ + unsigned curmesg; /* Current message being decoded in object header */ + unsigned merged_null_msgs = 0; /* Number of null messages merged together */ + unsigned chunkno; /* Current chunk's index */ +#ifndef NDEBUG + unsigned nullcnt; /* Count of null messages (for sanity checking gaps in chunks) */ +#endif /* NDEBUG */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_chunk_deserialize) + + /* Check arguments */ + HDassert(oh); + HDassert(image); + HDassert(udata->f); + HDassert(udata->cont_msg_info); + + /* Increase chunk array size, if necessary */ + if(oh->nchunks >= oh->alloc_nchunks) { + unsigned na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */ + H5O_chunk_t *x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, (size_t)na); + + if(!x) + HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed") + oh->alloc_nchunks = na; + oh->chunk = x; + } /* end if */ + + /* Init the chunk data info */ + chunkno = oh->nchunks++; + oh->chunk[chunkno].gap = 0; + if(chunkno == 0) { + /* First chunk's 'image' includes room for the object header prefix */ + oh->chunk[0].addr = addr; + oh->chunk[0].size = len + (size_t)H5O_SIZEOF_HDR(oh); + } /* end if */ + else { + oh->chunk[chunkno].addr = addr; + oh->chunk[chunkno].size = len; + } /* end else */ + if(NULL == (oh->chunk[chunkno].image = H5FL_BLK_MALLOC(chunk_image, oh->chunk[chunkno].size))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed") + + /* Copy disk image into chunk's image */ + HDmemcpy(oh->chunk[chunkno].image, image, oh->chunk[chunkno].size); + + /* Point into chunk image to decode */ + p = 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)); + /* 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)) + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "wrong object header chunk signature") + p += H5_SIZEOF_MAGIC; + } /* end if */ + + /* Save # of messages already inspected */ + curmesg = oh->nmesgs; + + /* Decode messages from this chunk */ + eom_ptr = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh)); +#ifndef NDEBUG + nullcnt = 0; +#endif /* NDEBUG */ + while(p < eom_ptr) { + unsigned mesgno; /* Current message to operate on */ + size_t mesg_size; /* Size of message read in */ + unsigned id; /* ID (type) of current message */ + uint8_t flags; /* Flags for current message */ + H5O_msg_crt_idx_t crt_idx = 0; /* Creation index for current message */ + + /* Decode message prefix info */ + + /* Version # */ + if(oh->version == H5O_VERSION_1) + UINT16DECODE(p, id) + else + id = *p++; + + /* 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); + HDassert(mesg_size == H5O_ALIGN_OH(oh, mesg_size)); + + /* Message flags */ + flags = *p++; + 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)) + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message") + if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN)) + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message") + if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && !(flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN)) + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message") + + /* Reserved bytes/creation index */ + if(oh->version == H5O_VERSION_1) + p += 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); + } /* end else */ + + /* Try to detect invalidly formatted object header message that + * extends past end of chunk. + */ + if(p + mesg_size > eom_ptr) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "corrupt object header") + +#ifndef NDEBUG + /* Increment count of null messages */ + if(H5O_NULL_ID == id) + nullcnt++; +#endif /* NDEBUG */ + + /* Check for combining two adjacent 'null' messages */ + if((udata->file_intent & H5F_ACC_RDWR) && + H5O_NULL_ID == id && oh->nmesgs > 0 && + H5O_NULL_ID == oh->mesg[oh->nmesgs - 1].type->id && + oh->mesg[oh->nmesgs - 1].chunkno == chunkno) { + + /* Combine adjacent null messages */ + mesgno = oh->nmesgs - 1; + oh->mesg[mesgno].raw_size += H5O_SIZEOF_MSGHDR_OH(oh) + mesg_size; + oh->mesg[mesgno].dirty = TRUE; + merged_null_msgs++; + udata->merged_null_msgs++; + } /* end if */ + else { + /* Check if we need to extend message table to hold the new message */ + if(oh->nmesgs >= oh->alloc_nmesgs) + if(H5O_alloc_msgs(oh, (size_t)1) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate more space for messages") + + /* Get index for message */ + mesgno = oh->nmesgs++; + + /* Initialize information about message */ + oh->mesg[mesgno].dirty = FALSE; + 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_size = mesg_size; + oh->mesg[mesgno].chunkno = chunkno; + + /* Point unknown messages at 'unknown' message class */ + /* (Usually from future versions of the library) */ + if(id >= NELMTS(H5O_msg_class_g) || NULL == H5O_msg_class_g[id]) { + H5O_unknown_t *unknown; /* Pointer to "unknown" message info */ + + /* Allocate "unknown" message info */ + if(NULL == (unknown = H5FL_MALLOC(H5O_unknown_t))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed") + + /* Save the original message type ID */ + *unknown = id; + + /* Save 'native' form of unknown message */ + oh->mesg[mesgno].native = unknown; + + /* Set message to "unknown" class */ + oh->mesg[mesgno].type = H5O_msg_class_g[H5O_UNKNOWN_ID]; + + /* Check for "fail if unknown" message flag */ + if(flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN) + HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "unknown message with 'fail if unknown' flag found") + /* Check for "mark if unknown" message flag, etc. */ + else if((flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN) && + !(flags & H5O_MSG_FLAG_WAS_UNKNOWN) && + (udata->file_intent & H5F_ACC_RDWR)) { + + /* Mark the message as "unknown" */ + /* This is a bit aggressive, since the application may + * never change anything about the object (metadata or + * raw data), but we can sort out the finer details + * when/if we start using the flag - QAK + */ + /* Also, it's possible that this functionality may not + * get invoked if the object header is brought into + * the metadata cache in some other "weird" way, like + * using H5Ocopy() - QAK + */ + oh->mesg[mesgno].flags |= H5O_MSG_FLAG_WAS_UNKNOWN; + + /* Mark the message and chunk as dirty */ + oh->mesg[mesgno].dirty = TRUE; + udata->mesgs_modified = TRUE; + *dirty = TRUE; + } /* end if */ + } /* end if */ + else + /* Set message class for "known" messages */ + oh->mesg[mesgno].type = H5O_msg_class_g[id]; + } /* end else */ + + /* Advance decode pointer past message */ + p += mesg_size; + + /* Check for 'gap' at end of chunk */ + if((eom_ptr - p) > 0 && (eom_ptr - p) < H5O_SIZEOF_MSGHDR_OH(oh)) { + /* Gaps can only occur in later versions of the format */ + HDassert(oh->version > H5O_VERSION_1); + + /* Gaps should only occur in chunks with no null messages */ + HDassert(nullcnt == 0); + + /* Set gap information for chunk */ + oh->chunk[chunkno].gap = (size_t)(eom_ptr - p); + + /* Increment location in chunk */ + p += 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); + + /* Compute checksum on chunk */ + computed_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0); + + /* 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); + + /* Do some inspection/interpretation of new messages from this chunk */ + /* (detect continuation messages, ref. count messages, etc.) */ + while(curmesg < oh->nmesgs) { + /* Check if next message to examine is a continuation message */ + if(H5O_CONT_ID == oh->mesg[curmesg].type->id) { + H5O_cont_t *cont; + unsigned ioflags = 0; /* Flags for decode routine */ + + /* Decode continuation message */ + cont = (H5O_cont_t *)(H5O_MSG_CONT->decode)(udata->f, udata->dxpl_id, NULL, 0, &ioflags, oh->mesg[curmesg].raw); + cont->chunkno = udata->cont_msg_info->nmsgs + 1; /*the next continuation message/chunk */ + + /* Save 'native' form of continuation message */ + oh->mesg[curmesg].native = cont; + + /* Add to continuation messages left to interpret */ + if(H5O_add_cont_msg(udata->cont_msg_info, cont) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add continuation message") + + /* Mark the message & chunk as dirty if the message was changed by decoding */ + if((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) { + oh->mesg[curmesg].dirty = TRUE; + udata->mesgs_modified = TRUE; + *dirty = TRUE; + } /* end if */ + } /* end if */ + /* Check if next message to examine is a ref. count message */ + else if(H5O_REFCOUNT_ID == oh->mesg[curmesg].type->id) { + H5O_refcount_t *refcount; + unsigned ioflags = 0; /* Flags for decode routine */ + + /* Decode ref. count message */ + HDassert(oh->version > H5O_VERSION_1); + refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(udata->f, udata->dxpl_id, NULL, 0, &ioflags, oh->mesg[curmesg].raw); + + /* Save 'native' form of ref. count message */ + oh->mesg[curmesg].native = refcount; + + /* Set object header values */ + oh->has_refcount_msg = TRUE; + oh->nlink = *refcount; + + /* Mark the message & chunk as dirty if the message was changed by decoding */ + if((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) { + oh->mesg[curmesg].dirty = TRUE; + udata->mesgs_modified = TRUE; + *dirty = TRUE; + } /* end if */ + } /* end if */ + /* Check if next message to examine is a link message */ + else if(H5O_LINK_ID == oh->mesg[curmesg].type->id) { + /* Increment the count of link messages */ + oh->link_msgs_seen++; + } /* end if */ + /* Check if next message to examine is an attribute message */ + else if(H5O_ATTR_ID == oh->mesg[curmesg].type->id) { + /* Increment the count of attribute messages */ + oh->attr_msgs_seen++; + } /* end if */ + + /* Advance to next message */ + curmesg++; + } /* end while */ + + /* Mark the chunk dirty if we've merged null messages */ + if(merged_null_msgs) { + udata->mesgs_modified = TRUE; + *dirty = TRUE; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_chunk_deserialize() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_chunk_serialize + * + * Purpose: Serialize a chunk for an object header + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 12, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno) +{ + H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_chunk_serialize) + + /* Check arguments */ + HDassert(f); + HDassert(oh); + + /* Encode any dirty messages in this chunk */ + for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) + if(curr_msg->dirty && curr_msg->chunkno == chunkno) + /* Casting away const OK -QAK */ + if(H5O_msg_flush((H5F_t *)f, oh, curr_msg) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message") + + /* Sanity checks */ + if(oh->version > H5O_VERSION_1) + /* Make certain the magic # is present */ + HDassert(!HDmemcmp(oh->chunk[chunkno].image, (chunkno == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5_SIZEOF_MAGIC)); + else + /* Gaps should never occur in version 1 of the format */ + HDassert(oh->chunk[chunkno].gap == 0); + + /* 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 */ + + /* Check for gap in chunk & zero it out */ + if(oh->chunk[chunkno].gap) + HDmemset((oh->chunk[chunkno].image + oh->chunk[chunkno].size) - + (H5O_SIZEOF_CHKSUM + oh->chunk[chunkno].gap), 0, oh->chunk[chunkno].gap); + + /* Compute metadata checksum */ + 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); + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_chunk_serialize() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_chunk_proxy_dest + * + * Purpose: Destroy a chunk proxy object + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * July 13, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_chunk_proxy_dest(H5O_chunk_proxy_t *chk_proxy) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5O_chunk_proxy_dest) + + /* Check arguments */ + HDassert(chk_proxy); + + /* Decrement reference count of object header */ + if(H5O_dec_rc(chk_proxy->oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "can't decrement reference count on object header") + + /* Release the chunk proxy object */ + chk_proxy = H5FL_FREE(H5O_chunk_proxy_t, chk_proxy); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_chunk_proxy_dest() */ + diff --git a/src/H5Ochunk.c b/src/H5Ochunk.c new file mode 100644 index 0000000..59102b6 --- /dev/null +++ b/src/H5Ochunk.c @@ -0,0 +1,359 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5Ochunk.c + * Jul 13 2008 + * Quincey Koziol <koziol@hdfgroup.org> + * + * Purpose: Object header chunk routines. + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5O_PACKAGE /*suppress error about including H5Opkg */ + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Opkg.h" /* Object headers */ + + +/****************/ +/* Local Macros */ +/****************/ + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Package Typedefs */ +/********************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + + +/*********************/ +/* Package Variables */ +/*********************/ + +/* Declare the free list for H5O_chunk_proxy_t's */ +H5FL_DEFINE(H5O_chunk_proxy_t); + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + + + +/*------------------------------------------------------------------------- + * Function: H5O_chunk_add + * + * Purpose: Add new chunk for object header to metadata cache + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jul 13 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_chunk_add(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx) +{ + H5O_chunk_proxy_t *chk_proxy = NULL; /* Proxy for chunk, to mark it dirty in the cache */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_chunk_add, FAIL) + + /* check args */ + HDassert(f); + HDassert(oh); + HDassert(idx < oh->nchunks); + HDassert(idx > 0); + + /* Allocate space for the object header data structure */ + if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Set the values in the chunk proxy */ + chk_proxy->oh = oh; + chk_proxy->chunkno = idx; + + /* Insert the chunk proxy into the cache */ + if(H5AC_set(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, chk_proxy, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to cache object header chunk") + chk_proxy = NULL; + + /* Increment reference count on object header */ + if(H5O_inc_rc(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, FAIL, "can't increment reference count on object header") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_chunk_add() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_chunk_protect + * + * Purpose: Protect an object header chunk for modifications + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jul 17 2008 + * + *------------------------------------------------------------------------- + */ +H5O_chunk_proxy_t * +H5O_chunk_protect(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx) +{ + H5O_chunk_proxy_t *chk_proxy; /* Proxy for protected chunk */ + H5O_chunk_proxy_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_chunk_protect, NULL) + + /* check args */ + HDassert(f); + HDassert(oh); + HDassert(idx < oh->nchunks); + + /* Check for protecting first chunk */ + if(0 == idx) { + /* Create new "fake" chunk proxy for first chunk */ + /* (since the first chunk is already handled by the H5O_t object) */ + if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed") + + /* Set chunk proxy fields */ + chk_proxy->oh = oh; + chk_proxy->chunkno = idx; + } /* end if */ + else { + H5O_chk_cache_ud_t chk_udata; /* User data for loading chunk */ + + /* Construct the user data for protecting chunk proxy */ + /* (and _not_ decoding it) */ + HDmemset(&chk_udata, 0, sizeof(chk_udata)); + chk_udata.oh = oh; + chk_udata.chunkno = idx; + chk_udata.chunk_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, NULL, &chk_udata, H5AC_WRITE))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header chunk") + + /* Sanity check */ + HDassert(chk_proxy->oh == oh); + HDassert(chk_proxy->chunkno == idx); + } /* end else */ + + /* Set return value */ + ret_value = chk_proxy; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_chunk_protect() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_chunk_unprotect + * + * Purpose: Unprotect an object header chunk after modifications + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jul 17 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_chunk_unprotect(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_chunk_proxy_t *chk_proxy, + unsigned chk_flags) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_chunk_unprotect, FAIL) + + /* check args */ + HDassert(f); + HDassert(oh); + HDassert(chk_proxy); + HDassert(!(chk_flags & (unsigned)~(H5AC__DIRTIED_FLAG | H5AC__SIZE_CHANGED_FLAG))); + + /* Check for releasing first chunk */ + if(0 == chk_proxy->chunkno) { + /* Check for resizing the first chunk */ + if(chk_flags & H5AC__SIZE_CHANGED_FLAG) { + /* Resize object header in cache */ + if(H5AC_resize_pinned_entry(oh, oh->chunk[0].size) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTRESIZE, FAIL, "unable to resize chunk in cache") + } /* end if */ + /* Check for dirtying the first chunk */ + else if(chk_flags & H5AC__DIRTIED_FLAG) { + /* Mark object header as dirty in cache */ + if(H5AC_mark_pinned_or_protected_entry_dirty(oh) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty") + } /* end else/if */ + else { + /* Sanity check */ + HDassert(0 && "Unknown chunk proxy flag(s)?!?"); + } /* end else */ + + /* Free fake chunk proxy */ + chk_proxy = H5FL_FREE(H5O_chunk_proxy_t, chk_proxy); + } /* end if */ + else { + /* Release the chunk proxy from the cache, marking it dirty */ + if(H5AC_unprotect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[chk_proxy->chunkno].addr, chk_proxy, chk_flags) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_chunk_unprotect() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_chunk_update_idx + * + * Purpose: Update the chunk index for a chunk proxy + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jul 13 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_chunk_update_idx(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx) +{ + H5O_chunk_proxy_t *chk_proxy; /* Proxy for chunk, to mark it dirty in the cache */ + H5O_chk_cache_ud_t chk_udata; /* User data for loading chunk */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_chunk_update_idx, FAIL) + + /* check args */ + HDassert(f); + HDassert(oh); + HDassert(idx < oh->nchunks); + HDassert(idx > 0); + + /* Construct the user data for protecting chunk proxy */ + /* (and _not_ decoding it) */ + HDmemset(&chk_udata, 0, sizeof(chk_udata)); + chk_udata.oh = oh; + chk_udata.chunkno = idx; + chk_udata.chunk_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, NULL, &chk_udata, H5AC_WRITE))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + + /* Update index for chunk proxy in cache */ + chk_proxy->chunkno = idx; + + /* Release the chunk proxy from the cache, marking it deleted */ + if(H5AC_unprotect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, chk_proxy, H5AC__DIRTIED_FLAG) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_chunk_update_idx() */ + + +/*------------------------------------------------------------------------- + * Function: H5O_chunk_delete + * + * Purpose: Notify metadata cache that a chunk has been deleted + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jul 13 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_chunk_delete(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx) +{ + H5O_chunk_proxy_t *chk_proxy; /* Proxy for chunk, to mark it dirty in the cache */ + H5O_chk_cache_ud_t chk_udata; /* User data for loading chunk */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_chunk_delete, FAIL) + + /* check args */ + HDassert(f); + HDassert(oh); + HDassert(idx < oh->nchunks); + HDassert(idx > 0); + + /* Construct the user data for protecting chunk proxy */ + /* (and _not_ decoding it) */ + HDmemset(&chk_udata, 0, sizeof(chk_udata)); + chk_udata.oh = oh; + chk_udata.chunkno = idx; + chk_udata.chunk_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, NULL, &chk_udata, H5AC_WRITE))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + + /* Sanity check */ + HDassert(chk_proxy->oh == oh); + HDassert(chk_proxy->chunkno == idx); + + /* Release the chunk proxy from the cache, marking it deleted */ + if(H5AC_unprotect(f, dxpl_id, H5AC_OHDR_CHK, oh->chunk[idx].addr, chk_proxy, (H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O_chunk_delete() */ + diff --git a/src/H5Ocont.c b/src/H5Ocont.c index df336dd..7f9dd47 100644 --- a/src/H5Ocont.c +++ b/src/H5Ocont.c @@ -224,7 +224,7 @@ H5O_cont_free(void *mesg) *------------------------------------------------------------------------- */ static herr_t -H5O_cont_delete(H5F_t *f, hid_t dxpl_id, H5O_t UNUSED *open_oh, void *_mesg) +H5O_cont_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, void *_mesg) { H5O_cont_t *mesg = (H5O_cont_t *) _mesg; herr_t ret_value = SUCCEED; /* Return value */ @@ -235,9 +235,10 @@ H5O_cont_delete(H5F_t *f, hid_t dxpl_id, H5O_t UNUSED *open_oh, void *_mesg) HDassert(f); HDassert(mesg); - /* Release space for chunk */ - if(H5MF_xfree(f, H5FD_MEM_OHDR, dxpl_id, mesg->addr, (hsize_t)mesg->size) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free object header chunk") + /* Notify the cache that the chunk has been deleted */ + /* (releases the space for the chunk) */ + if(H5O_chunk_delete(f, dxpl_id, open_oh, mesg->chunkno) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove chunk from cache") done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Ocopy.c b/src/H5Ocopy.c index 8896795..163e525 100644 --- a/src/H5Ocopy.c +++ b/src/H5Ocopy.c @@ -316,7 +316,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, HDassert(cpy_info); /* Get source object header */ - if(NULL == (oh_src = (H5O_t *)H5AC_protect(oloc_src->file, dxpl_id, H5AC_OHDR, oloc_src->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh_src = H5O_protect(oloc_src, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Get pointer to object class for this object */ @@ -579,7 +579,6 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Set dest. chunk information */ - oh_dst->chunk[0].dirty = TRUE; oh_dst->chunk[0].size = (size_t)dst_oh_size; oh_dst->chunk[0].gap = dst_oh_gap; @@ -739,7 +738,7 @@ done: HDfree(deleted); /* Release pointer to source object header and its derived objects */ - if(oh_src && H5AC_unprotect(oloc_src->file, dxpl_id, H5AC_OHDR, oloc_src->addr, oh_src, H5AC__NO_FLAGS_SET) < 0) + if(oh_src && H5O_unprotect(oloc_src, dxpl_id, oh_src, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") /* Release pointer to destination object header */ diff --git a/src/H5Odbg.c b/src/H5Odbg.c index 9285f4b..8661cfe 100644 --- a/src/H5Odbg.c +++ b/src/H5Odbg.c @@ -377,10 +377,6 @@ H5O_debug_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, haddr_t addr, FILE *stream, i HDfprintf(stream, "%*sChunk %d...\n", indent, "", i); - HDfprintf(stream, "%*s%-*s %t\n", indent + 3, "", MAX(0, fwidth - 3), - "Dirty:", - oh->chunk[i].dirty); - HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", MAX(0, fwidth - 3), "Address:", oh->chunk[i].addr); @@ -538,6 +534,7 @@ herr_t H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth) { H5O_t *oh = NULL; /* Object header to display */ + H5O_loc_t loc; /* Object location for object to delete */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5O_debug, FAIL) @@ -549,14 +546,19 @@ H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int f HDassert(indent >= 0); HDassert(fwidth >= 0); - if(NULL == (oh = (H5O_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR, addr, NULL, NULL, H5AC_READ))) + /* Set up the object location */ + loc.file = f; + loc.addr = addr; + loc.holding_file = FALSE; + + if(NULL == (oh = H5O_protect(&loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* debug */ H5O_debug_real(f, dxpl_id, oh, addr, stream, indent, fwidth); done: - if(oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(&loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Omessage.c b/src/H5Omessage.c index fc6146a..e2355ae 100644 --- a/src/H5Omessage.c +++ b/src/H5Omessage.c @@ -127,21 +127,17 @@ H5O_msg_create(const H5O_loc_t *loc, unsigned type_id, unsigned mesg_flags, HDassert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS)); HDassert(mesg); - /* Check for write access on the file */ - if(0 == (H5F_INTENT(loc->file) & H5F_ACC_RDWR)) - HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file") - - /* Protect the object header */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") + /* Pin the object header */ + if(NULL == (oh = H5O_pin(loc, dxpl_id))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header") /* Go append message to object header */ if(H5O_msg_append_oh(loc->file, dxpl_id, oh, type_id, mesg_flags, update_flags, mesg) < 0) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to append to object header") done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh && H5O_unpin(oh) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_msg_create() */ @@ -280,21 +276,17 @@ H5O_msg_write(const H5O_loc_t *loc, unsigned type_id, unsigned mesg_flags, HDassert(mesg); HDassert(0 == (mesg_flags & ~H5O_MSG_FLAG_BITS)); - /* Check for write access on the file */ - if(0 == (H5F_INTENT(loc->file) & H5F_ACC_RDWR)) - HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file") - - /* Protect the object header */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") + /* Pin the object header */ + if(NULL == (oh = H5O_pin(loc, dxpl_id))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header") /* Call the "real" modify routine */ if(H5O_msg_write_real(loc->file, dxpl_id, oh, type, mesg_flags, update_flags, mesg) < 0) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header message") done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh && H5O_unpin(oh) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_msg_write() */ @@ -484,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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header") /* Call the "real" read routine */ @@ -492,7 +484,7 @@ H5O_msg_read(const H5O_loc_t *loc, unsigned type_id, void *mesg, HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to load object header") done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -809,14 +801,14 @@ 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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Count the messages of the correct type */ ret_value = H5O_msg_count_real(oh, type); done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -890,7 +882,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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Call the "real" exists routine */ @@ -898,7 +890,7 @@ H5O_msg_exists(const H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id) HGOTO_ERROR(H5E_OHDR, H5E_READERROR, FAIL, "unable to verify object header message") done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) != SUCCEED) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -986,17 +978,17 @@ H5O_msg_remove(const H5O_loc_t *loc, unsigned type_id, int sequence, hbool_t adj type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); - /* Protect the object header to iterate over */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") + /* Pin the object header */ + if(NULL == (oh = H5O_pin(loc, dxpl_id))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header") /* Call the "real" remove routine */ if((ret_value = H5O_msg_remove_real(loc->file, oh, type, sequence, NULL, NULL, adj_link, dxpl_id)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove object header message") done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh && H5O_unpin(oh) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_msg_remove() */ @@ -1038,17 +1030,17 @@ H5O_msg_remove_op(const H5O_loc_t *loc, unsigned type_id, int sequence, type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); - /* Protect the object header to iterate over */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") + /* Pin the object header */ + if(NULL == (oh = H5O_pin(loc, dxpl_id))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPIN, FAIL, "unable to pin object header") /* Call the "real" remove routine */ if((ret_value = H5O_msg_remove_real(loc->file, oh, type, sequence, op, op_data, adj_link, dxpl_id)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove object header message") done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") + if(oh && H5O_unpin(oh) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPIN, FAIL, "unable to unpin object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_msg_remove_op() */ @@ -1230,7 +1222,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_t *)H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Call the "real" iterate routine */ @@ -1238,7 +1230,7 @@ H5O_msg_iterate(const H5O_loc_t *loc, unsigned type_id, HERROR(H5E_OHDR, H5E_BADITER, "unable to iterate over object header messages"); done: - if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -1962,7 +1954,9 @@ H5O_copy_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx, const H5O_msg_class_t *type, const void *mesg, unsigned mesg_flags, unsigned update_flags) { + H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */ H5O_mesg_t *idx_msg = &oh->mesg[idx]; /* Pointer to message to modify */ + unsigned chk_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting chunk */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_copy_mesg) @@ -1974,6 +1968,10 @@ H5O_copy_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx, HDassert(type->copy); HDassert(mesg); + /* Protect chunk */ + if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, idx_msg->chunkno))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + /* Reset existing native information for the header's message */ H5O_msg_reset_real(type, idx_msg->native); @@ -1986,17 +1984,23 @@ H5O_copy_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx, /* Mark the message as modified */ idx_msg->dirty = TRUE; + chk_flags |= H5AC__DIRTIED_FLAG; + + /* Release chunk */ + if(H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy, chk_flags) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + chk_proxy = NULL; /* Update the modification time, if requested */ if(update_flags & H5O_UPDATE_TIME) if(H5O_touch_oh(f, dxpl_id, oh, FALSE) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTUPDATE, FAIL, "unable to update time on object") - /* Mark object header as dirty in cache */ - if(H5AC_mark_pinned_or_protected_entry_dirty(oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty") - done: + /* Release chunk, if not already released */ + if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, oh, chk_proxy, chk_flags) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk") + FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_copy_mesg() */ @@ -2183,9 +2187,8 @@ H5O_msg_flush(H5F_t *f, H5O_t *oh, H5O_mesg_t *mesg) HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message") } /* end if */ - /* Pass "modifiedness" from message to chunk */ + /* Mark the message as clean now */ mesg->dirty = FALSE; - oh->chunk[mesg->chunkno].dirty = TRUE; done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Opkg.h b/src/H5Opkg.h index 25cea5a..d60fdb7 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -253,7 +253,6 @@ struct H5O_mesg_t { }; typedef struct H5O_chunk_t { - hbool_t dirty; /*dirty flag */ haddr_t addr; /*chunk file address */ size_t size; /*chunk size */ size_t gap; /*space at end of chunk too small for null message */ @@ -268,9 +267,6 @@ struct H5O_t { size_t sizeof_size; /* Size of file sizes */ size_t sizeof_addr; /* Size of file addresses */ - /* Misc. information (not stored) */ - unsigned npins; /* Number of times the header is pinned */ - /* Debugging information (not stored) */ #ifdef H5O_ENABLE_BAD_MESG_COUNT hbool_t store_bad_mesg_count; /* Flag to indicate that a bad message count should be stored */ @@ -282,6 +278,12 @@ struct H5O_t { size_t ndecode_dirtied; /* Number of messages dirtied by decoding */ #endif /* NDEBUG */ + /* Chunk management information (not stored) */ + size_t rc; /* Reference count of [continuation] chunks using this structure */ + size_t chunk0_size; /* Size of serialized first chunk */ + hbool_t mesgs_modified; /* Whether any messages were modified when the object header was deserialized */ + hbool_t prefix_modified; /* Whether prefix was modified when the object header was deserialized */ + /* Object information (stored) */ hbool_t has_refcount_msg; /* Whether the object has a ref. count message */ unsigned nlink; /*link count */ @@ -332,10 +334,55 @@ typedef struct H5O_addr_map_t { hsize_t inc_ref_count; /* Number of deferred increments to reference count */ } H5O_addr_map_t; - -/* H5O inherits cache-like properties from H5AC */ +/* Stack of continuation messages to interpret */ +typedef struct H5O_cont_msgs_t { + size_t nmsgs; /* Number of continuation messages found so far */ + size_t alloc_nmsgs; /* Continuation messages allocated */ + H5O_cont_t *msgs; /* Array of continuation messages */ +} H5O_cont_msgs_t; + +/* Common callback information for loading object header prefix from disk */ +typedef struct H5O_common_cache_ud_t { + H5F_t *f; /* Pointer to file for object header/chunk */ + hid_t dxpl_id; /* DXPL for operation */ + unsigned file_intent; /* Read/write intent for file */ + unsigned merged_null_msgs; /* Number of null messages merged together */ + hbool_t mesgs_modified; /* Whether any messages were modified when the object header was deserialized */ + H5O_cont_msgs_t *cont_msg_info; /* Pointer to continuation messages to work on */ +} H5O_common_cache_ud_t; + +/* Callback information for loading object header prefix from disk */ +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 */ + H5O_common_cache_ud_t common; /* Common object header cache callback info */ +} H5O_cache_ud_t; + +/* Structure representing each chunk in the cache */ +typedef struct H5O_chunk_proxy_t { + H5AC_info_t cache_info; /* Information for metadata cache functions, _must_ be */ + /* first field in structure */ + + H5O_t *oh; /* Object header for this chunk */ + unsigned chunkno; /* Chunk number for this chunk */ +} H5O_chunk_proxy_t; + +/* Callback information for loading object header chunk from disk */ +typedef struct H5O_chk_cache_ud_t { + hbool_t decoding; /* Whether the object header is being decoded */ + H5O_t *oh; /* Object header for this chunk */ + unsigned chunkno; /* Index of chunk being brought in (for re-loads) */ + size_t chunk_size; /* Chunk size */ + H5O_common_cache_ud_t common; /* Common object header cache callback info */ +} H5O_chk_cache_ud_t; + + +/* H5O object header inherits cache-like properties from H5AC */ H5_DLLVAR const H5AC_class_t H5AC_OHDR[1]; +/* H5O object header chunk inherits cache-like properties from H5AC */ +H5_DLLVAR const H5AC_class_t H5AC_OHDR_CHK[1]; + /* Header message ID to class mapping */ H5_DLLVAR const H5O_msg_class_t *const H5O_msg_class_g[H5O_MSG_TYPES]; @@ -474,6 +521,9 @@ H5_DLL herr_t H5O_flush_msgs(H5F_t *f, H5O_t *oh); H5_DLL hid_t H5O_open_by_loc(const H5G_loc_t *obj_loc, hid_t lapl_id, hid_t dxpl_id, hbool_t app_ref); H5_DLL herr_t H5O_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, H5O_mesg_t *mesg); H5_DLL const H5O_obj_class_t *H5O_obj_class_real(H5O_t *oh); +H5_DLL int H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, hbool_t *deleted); +H5_DLL herr_t H5O_inc_rc(H5O_t *oh); +H5_DLL herr_t H5O_dec_rc(H5O_t *oh); H5_DLL herr_t H5O_free(H5O_t *oh); /* Object header message routines */ @@ -496,6 +546,15 @@ H5_DLL void *H5O_msg_copy_file(const H5O_msg_class_t *type, H5F_t *file_src, H5_DLL herr_t H5O_msg_iterate_real(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type, const H5O_mesg_operator_t *op, void *op_data, hid_t dxpl_id); +/* Object header chunk routines */ +H5_DLL herr_t H5O_chunk_add(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx); +H5_DLL H5O_chunk_proxy_t *H5O_chunk_protect(H5F_t *f, hid_t dxpl_id, H5O_t *oh, + unsigned idx); +H5_DLL herr_t H5O_chunk_unprotect(H5F_t *f, hid_t dxpl_id, H5O_t *oh, + H5O_chunk_proxy_t *chk_proxy, unsigned chk_flags); +H5_DLL herr_t H5O_chunk_update_idx(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx); +H5_DLL herr_t H5O_chunk_delete(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx); + /* Collect storage info for btree and heap */ H5_DLL herr_t H5O_attr_bh_info(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5_ih_info_t *bh_info); @@ -542,6 +601,7 @@ H5_DLL htri_t H5O_is_attr_dense_test(hid_t oid); H5_DLL herr_t H5O_num_attrs_test(hid_t oid, hsize_t *nattrs); H5_DLL herr_t H5O_attr_dense_info_test(hid_t oid, hsize_t *name_count, hsize_t *corder_count); H5_DLL herr_t H5O_check_msg_marked_test(hid_t oid, hbool_t flag_val); +H5_DLL herr_t H5O_expunge_chunks_test(const H5O_loc_t *oloc, hid_t dxpl_id); #endif /* H5O_TESTING */ /* Object header debugging routines */ diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index f16f6dc..927deb3 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -37,6 +37,7 @@ #include "H5Spublic.h" /* Dataspace functions */ /* Private headers needed by this file */ +#include "H5ACprivate.h" /* Metadata cache */ #include "H5Fprivate.h" /* File access */ #include "H5SLprivate.h" /* Skip lists */ #include "H5Tprivate.h" /* Datatype functions */ @@ -604,9 +605,11 @@ 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 int H5O_link_oh(H5F_t *f, int adjust, hid_t dxpl_id, H5O_t *oh, unsigned *oh_flags); -H5_DLL H5O_t *H5O_pin(H5O_loc_t *loc, 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_pin(const H5O_loc_t *loc, hid_t dxpl_id); H5_DLL herr_t H5O_unpin(H5O_t *oh); +H5_DLL herr_t H5O_unprotect(const H5O_loc_t *loc, hid_t dxpl_id, H5O_t *oh, + unsigned oh_flags); H5_DLL herr_t H5O_touch(const H5O_loc_t *loc, hbool_t force, hid_t dxpl_id); H5_DLL herr_t H5O_touch_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hbool_t force); diff --git a/src/H5Oshared.c b/src/H5Oshared.c index cdd9778..4a9c2bb 100644 --- a/src/H5Oshared.c +++ b/src/H5Oshared.c @@ -256,12 +256,12 @@ H5O_shared_link_adj(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, * is possible, for example, if an attribute's datatype is shared in * the same object header the attribute is in. Adjust the link * count directly. */ - unsigned oh_flags = H5AC__NO_FLAGS_SET; /* This is used only to satisfy H5O_link_oh */ + hbool_t deleted = FALSE; /* This is used only to satisfy H5O_link_oh */ - if(H5O_link_oh(f, adjust, dxpl_id, open_oh, &oh_flags) < 0) + if(H5O_link_oh(f, adjust, dxpl_id, open_oh, &deleted) < 0) HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared object link count") - HDassert(!(oh_flags & H5AC__DELETED_FLAG)); + HDassert(!deleted); } else /* The shared message is in another object header */ if(H5O_link(&oloc, adjust, dxpl_id) < 0) diff --git a/src/H5Otest.c b/src/H5Otest.c index 041194a..77b7540 100644 --- a/src/H5Otest.c +++ b/src/H5Otest.c @@ -98,7 +98,7 @@ H5O_is_attr_dense_test(hid_t oid) { H5O_t *oh = NULL; /* Object header */ H5O_ainfo_t ainfo; /* Attribute information for object */ - H5O_loc_t *loc; /* Pointer to object's location */ + H5O_loc_t *loc; /* Pointer to object's location */ htri_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_is_attr_dense_test, FAIL) @@ -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_t *)H5AC_protect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -130,7 +130,7 @@ H5O_is_attr_dense_test(hid_t oid) ret_value = FALSE; done: - if(oh && H5AC_unprotect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, H5AC_ind_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -173,7 +173,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_t *)H5AC_protect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -217,7 +217,7 @@ done: /* Release resources */ if(bt2_name && H5B2_close(bt2_name, H5AC_ind_dxpl_id) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index") - if(oh && H5AC_unprotect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, H5AC_ind_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -260,7 +260,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_t *)H5AC_protect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -301,7 +301,7 @@ done: /* Release resources */ if(bt2_name && H5B2_close(bt2_name, H5AC_ind_dxpl_id) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index") - if(oh && H5AC_unprotect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, H5AC_ind_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -346,7 +346,7 @@ H5O_attr_dense_info_test(hid_t oid, hsize_t *name_count, hsize_t *corder_count) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found") /* Get the object header */ - if(NULL == (oh = (H5O_t *)H5AC_protect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Check for attribute info stored */ @@ -390,7 +390,7 @@ done: HDONE_ERROR(H5E_OHDR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for name index") if(bt2_corder && H5B2_close(bt2_corder, H5AC_ind_dxpl_id) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for creation order index") - if(oh && H5AC_unprotect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, H5AC_ind_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) @@ -434,7 +434,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_t *)H5AC_protect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(loc, H5AC_ind_dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header") /* Locate "unknown" message */ @@ -453,9 +453,68 @@ H5O_check_msg_marked_test(hid_t oid, hbool_t flag_val) HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "'unknown' message type not found") done: - if(oh && H5AC_unprotect(loc->file, H5AC_ind_dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(loc, H5AC_ind_dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* H5O_check_msg_marked_test() */ + +/*-------------------------------------------------------------------------- + NAME + H5O_expunge_chunks_test + PURPOSE + Expunge all the chunks for an object header from the cache. + USAGE + herr_t H5O_expunge_chunks_test(f, dxpl_id, loc) + H5F_t *f; IN: Pointer to file that object is within + hid_t dxpl_id; IN: DXPL to use for operation + H5O_loc_t *loc; IN: Object location for object header to expunge + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Iterates over all the chunks for an object header an expunges each from the + metadata cache. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5O_expunge_chunks_test(const H5O_loc_t *loc, hid_t dxpl_id) +{ + H5O_t *oh = NULL; /* Object header */ + haddr_t chk_addr[16]; /* Array of chunk addresses */ + unsigned nchunks; /* Number of chunks in object header */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5O_expunge_chunks_test, FAIL) + + /* Get the object header */ + if(NULL == (oh = H5O_protect(loc, dxpl_id, H5AC_WRITE))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header") + + /* Safety check */ + nchunks = oh->nchunks; + HDassert(nchunks < NELMTS(chk_addr)); + + /* Iterate over all the chunks, saving the chunk addresses */ + for(u = 0; u < oh->nchunks; u++) + chk_addr[u] = oh->chunk[u].addr; + + /* Release the object header */ + if(H5O_unprotect(loc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header") + + /* Iterate over all the saved chunk addresses, evicting them from the cache */ + /* (in reverse order, so that chunk #0 is unpinned) */ + for(u = nchunks - 1; u < nchunks; u--) + if(H5AC_expunge_entry(loc->file, dxpl_id, (u == 0 ? H5AC_OHDR : H5AC_OHDR_CHK), chk_addr[u], H5AC__NO_FLAGS_SET) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTEXPUNGE, FAIL, "unable to expunge object header chunk") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5O_expunge_chunks_test() */ + @@ -366,8 +366,9 @@ H5R_dereference(H5F_t *file, hid_t dxpl_id, H5R_type_t ref_type, const void *_re H5O_loc_t oloc; /* Object location */ H5G_name_t path; /* Path of object */ H5G_loc_t loc; /* Group location */ + unsigned rc; /* Reference count of object */ H5O_type_t obj_type; /* Type of object */ - hid_t ret_value; + hid_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5R_dereference) @@ -415,8 +416,9 @@ H5R_dereference(H5F_t *file, hid_t dxpl_id, H5R_type_t ref_type, const void *_re HGOTO_ERROR(H5E_REFERENCE, H5E_UNSUPPORTED, FAIL, "internal error (unknown reference type)") } /* end switch */ - /* Check to make certain that this object hasn't been deleted since the reference was created */ - if(H5O_link(&oloc, 0, dxpl_id) <= 0) + /* Get the # of links for object, and its type */ + /* (To check to make certain that this object hasn't been deleted since the reference was created) */ + if(H5O_get_rc_and_type(&oloc, dxpl_id, &rc, &obj_type) < 0 || 0 == rc) HGOTO_ERROR(H5E_REFERENCE, H5E_LINKCOUNT, FAIL, "dereferencing deleted object") /* Construct a group location for opening the object */ @@ -424,10 +426,6 @@ H5R_dereference(H5F_t *file, hid_t dxpl_id, H5R_type_t ref_type, const void *_re loc.oloc = &oloc; loc.path = &path; - /* Get the type of the object */ - if(H5O_obj_type(&oloc, &obj_type, dxpl_id) < 0) - HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, FAIL, "unable to get object type") - /* Open the object */ switch(obj_type) { case H5O_TYPE_GROUP: @@ -688,6 +686,7 @@ H5R_get_obj_type(H5F_t *file, hid_t dxpl_id, H5R_type_t ref_type, const void *_ref, H5O_type_t *obj_type) { H5O_loc_t oloc; /* Object location */ + unsigned rc; /* Reference count of object */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5R_get_obj_type) @@ -736,14 +735,11 @@ H5R_get_obj_type(H5F_t *file, hid_t dxpl_id, H5R_type_t ref_type, HGOTO_ERROR(H5E_REFERENCE, H5E_UNSUPPORTED, FAIL, "internal error (unknown reference type)") } /* end switch */ - /* Check to make certain that this object hasn't been deleted since the reference was created */ - if(H5O_link(&oloc, 0, dxpl_id) <= 0) + /* Get the # of links for object, and its type */ + /* (To check to make certain that this object hasn't been deleted since the reference was created) */ + if(H5O_get_rc_and_type(&oloc, dxpl_id, &rc, obj_type) < 0 || 0 == rc) HGOTO_ERROR(H5E_REFERENCE, H5E_LINKCOUNT, FAIL, "dereferencing deleted object") - /* Get the object type */ - if(H5O_obj_type(&oloc, obj_type, dxpl_id) < 0) - HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, FAIL, "unable to get object type") - done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5R_get_obj_type() */ @@ -25,7 +25,6 @@ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ -#include "H5ACprivate.h" /* Metadata cache */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fpkg.h" /* File access */ #include "H5FLprivate.h" /* Free Lists */ @@ -2247,7 +2246,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_t *)H5AC_protect(oloc.file, dxpl_id, H5AC_OHDR, oloc.addr, NULL, NULL, H5AC_READ))) + if(NULL == (oh = H5O_protect(&oloc, dxpl_id, H5AC_READ))) HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load object header") } /* end if */ else @@ -2276,7 +2275,7 @@ H5SM_read_mesg(H5F_t *f, const H5SM_sohm_t *mesg, H5HF_t *fheap, done: /* Close the object header if we opened one and had an error */ if(oh && oh != open_oh) { - if(H5AC_unprotect(oloc.file, dxpl_id, H5AC_OHDR, oloc.addr, oh, H5AC__NO_FLAGS_SET) < 0) + if(oh && H5O_unprotect(&oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to release object header") if(H5O_close(&oloc) < 0) HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "unable to close object header") diff --git a/src/Makefile.am b/src/Makefile.am index 56104df..eefb878 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,7 +71,7 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5MF.c H5MFaggr.c H5MFdbg.c H5MFsection.c \ H5MM.c H5MP.c H5MPtest.c \ H5O.c H5Oainfo.c H5Oalloc.c H5Oattr.c \ - H5Oattribute.c H5Obogus.c H5Obtreek.c H5Ocache.c \ + H5Oattribute.c H5Obogus.c H5Obtreek.c H5Ocache.c H5Ochunk.c \ H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c H5Oefl.c \ H5Ofill.c H5Oginfo.c \ H5Olayout.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 1cbe182..570d12e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -122,7 +122,7 @@ am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \ H5Lexternal.lo H5lib_settings.lo H5MF.lo H5MFaggr.lo \ H5MFdbg.lo H5MFsection.lo H5MM.lo H5MP.lo H5MPtest.lo H5O.lo \ H5Oainfo.lo H5Oalloc.lo H5Oattr.lo H5Oattribute.lo H5Obogus.lo \ - H5Obtreek.lo H5Ocache.lo H5Ocont.lo H5Ocopy.lo H5Odbg.lo \ + H5Obtreek.lo H5Ocache.lo H5Ochunk.lo H5Ocont.lo H5Ocopy.lo H5Odbg.lo \ H5Odrvinfo.lo H5Odtype.lo H5Oefl.lo H5Ofill.lo H5Oginfo.lo \ H5Olayout.lo H5Olinfo.lo H5Olink.lo H5Omessage.lo H5Omtime.lo \ H5Oname.lo H5Onull.lo H5Opline.lo H5Orefcount.lo H5Osdspace.lo \ @@ -485,7 +485,7 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5MF.c H5MFaggr.c H5MFdbg.c H5MFsection.c \ H5MM.c H5MP.c H5MPtest.c \ H5O.c H5Oainfo.c H5Oalloc.c H5Oattr.c \ - H5Oattribute.c H5Obogus.c H5Obtreek.c H5Ocache.c \ + H5Oattribute.c H5Obogus.c H5Obtreek.c H5Ocache.c H5Ochunk.c \ H5Ocont.c H5Ocopy.c H5Odbg.c H5Odrvinfo.c H5Odtype.c H5Oefl.c \ H5Ofill.c H5Oginfo.c \ H5Olayout.c \ @@ -789,6 +789,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Obogus.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Obtreek.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocache.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ochunk.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocont.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Ocopy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Odbg.Plo@am__quote@ diff --git a/test/ohdr.c b/test/ohdr.c index e26afef..4ff8866 100644 --- a/test/ohdr.c +++ b/test/ohdr.c @@ -104,7 +104,7 @@ test_cont(char *filename, hid_t fapl) if(H5AC_flush(f, H5P_DATASET_XFER_DEFAULT) < 0) FAIL_STACK_ERROR - if(H5AC_expunge_entry(f, H5P_DATASET_XFER_DEFAULT, H5AC_OHDR, oh_locA.addr, H5AC__NO_FLAGS_SET) < 0) + if(H5O_expunge_chunks_test(&oh_locA, H5P_DATASET_XFER_DEFAULT) < 0) FAIL_STACK_ERROR if(H5O_get_hdr_info(&oh_locA, H5P_DATASET_XFER_DEFAULT, &hdr_info) < 0) |