diff options
Diffstat (limited to 'src/H5HFcache.c')
-rw-r--r-- | src/H5HFcache.c | 2911 |
1 files changed, 1800 insertions, 1111 deletions
diff --git a/src/H5HFcache.c b/src/H5HFcache.c index 4b02e06..7171da9 100644 --- a/src/H5HFcache.c +++ b/src/H5HFcache.c @@ -1,4 +1,4 @@ -/* / * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * @@ -53,20 +53,6 @@ #define H5HF_DBLOCK_VERSION 0 /* Direct block */ #define H5HF_IBLOCK_VERSION 0 /* Indirect block */ -/* Size of stack buffer for serialized headers */ -#define H5HF_HDR_BUF_SIZE 512 - -/* Size of stack buffer for serialized indirect blocks */ -#define H5HF_IBLOCK_BUF_SIZE 4096 - -/* Size of minimum header to decode for determining the full header size */ -#define H5HF_MIN_HEADER_SIZE ( \ - H5_SIZEOF_MAGIC + /* Signature */ \ - 1 + /* Version */ \ - 2 + /* Heap ID len */ \ - 2 /* I/O filters' encoded len */ \ - ) - /******************/ /* Local Typedefs */ @@ -87,24 +73,57 @@ static herr_t H5HF__dtable_encode(H5F_t *f, uint8_t **pp, const H5HF_dtable_t *d static herr_t H5HF__dtable_decode(H5F_t *f, const uint8_t **pp, H5HF_dtable_t *dtable); /* Metadata cache (H5AC) callbacks */ -static H5HF_hdr_t *H5HF_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5HF_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_hdr_t *hdr, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5HF_cache_hdr_dest(H5F_t *f, H5HF_hdr_t *hdr); -static herr_t H5HF_cache_hdr_clear(H5F_t *f, H5HF_hdr_t *hdr, hbool_t destroy); -static herr_t H5HF_cache_hdr_size(const H5F_t *f, const H5HF_hdr_t *hdr, size_t *size_ptr); -static H5HF_indirect_t *H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5HF_cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_indirect_t *iblock, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5HF_cache_iblock_dest(H5F_t *f, H5HF_indirect_t *iblock); -static herr_t H5HF_cache_iblock_clear(H5F_t *f, H5HF_indirect_t *iblock, hbool_t destroy); -static herr_t H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock); -static herr_t H5HF_cache_iblock_size(const H5F_t *f, const H5HF_indirect_t *iblock, size_t *size_ptr); -static H5HF_direct_t *H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5HF_cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_direct_t *dblock, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5HF_cache_dblock_dest(H5F_t *f, H5HF_direct_t *dblock); -static herr_t H5HF_cache_dblock_clear(H5F_t *f, H5HF_direct_t *dblock, hbool_t destroy); -static herr_t H5HF_cache_dblock_notify(H5C_notify_action_t action, H5HF_direct_t *dblock); -static herr_t H5HF_cache_dblock_size(const H5F_t *f, const H5HF_direct_t *dblock, size_t *size_ptr); - +static herr_t H5HF__cache_hdr_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5HF__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5HF__cache_hdr_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5HF__cache_hdr_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5HF__cache_hdr_pre_serialize(const H5F_t *f, hid_t dxpl_id, + void *thing, haddr_t addr, size_t len, size_t compressed_len, + haddr_t *new_addr, size_t *new_len, size_t *new_compressed_len, + unsigned *flags); +static herr_t H5HF__cache_hdr_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5HF__cache_hdr_free_icr(void *thing); + +static herr_t H5HF__cache_iblock_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5HF__cache_iblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5HF__cache_iblock_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5HF__cache_iblock_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5HF__cache_iblock_pre_serialize(const H5F_t *f, hid_t dxpl_id, + void *thing, haddr_t addr, size_t len, size_t compressed_len, + haddr_t *new_addr, size_t *new_len, size_t *new_compressed_len, + unsigned *flags); +static herr_t H5HF__cache_iblock_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5HF__cache_iblock_notify(H5C_notify_action_t action, void *thing); +static herr_t H5HF__cache_iblock_free_icr(void *thing); + +static herr_t H5HF__cache_dblock_get_load_size(const void *image_ptr, void *udata, + size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static htri_t H5HF__cache_dblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); +static void *H5HF__cache_dblock_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5HF__cache_dblock_image_len(const void *thing, + size_t *image_len, hbool_t *compressed_ptr, + size_t *compressed_image_len_ptr); +static herr_t H5HF__cache_dblock_pre_serialize(const H5F_t *f, hid_t dxpl_id, + void *thing, haddr_t addr, size_t len, size_t compressed_len, + haddr_t *new_addr, size_t *new_len, size_t *new_compressed_len, + unsigned *flags); +static herr_t H5HF__cache_dblock_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5HF__cache_dblock_notify(H5C_notify_action_t action, void *thing); +static herr_t H5HF__cache_dblock_free_icr(void *thing); /* Debugging Function Prototypes */ #ifndef NDEBUG @@ -125,35 +144,56 @@ static herr_t H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f, hid_t dxpl_i /* H5HF header inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FHEAP_HDR[1] = {{ - H5AC_FHEAP_HDR_ID, - (H5AC_load_func_t)H5HF_cache_hdr_load, - (H5AC_flush_func_t)H5HF_cache_hdr_flush, - (H5AC_dest_func_t)H5HF_cache_hdr_dest, - (H5AC_clear_func_t)H5HF_cache_hdr_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5HF_cache_hdr_size, + H5AC_FHEAP_HDR_ID, /* Metadata client ID */ + "fractal heap header", /* Metadata client name (for debugging) */ + H5FD_MEM_FHEAP_HDR, /* File space memory type for client */ + H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ + H5HF__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5HF__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ + H5HF__cache_hdr_deserialize, /* 'deserialize' callback */ + H5HF__cache_hdr_image_len, /* 'image_len' callback */ + H5HF__cache_hdr_pre_serialize, /* 'pre_serialize' callback */ + H5HF__cache_hdr_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5HF__cache_hdr_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* H5HF indirect block inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FHEAP_IBLOCK[1] = {{ - H5AC_FHEAP_IBLOCK_ID, - (H5AC_load_func_t)H5HF_cache_iblock_load, - (H5AC_flush_func_t)H5HF_cache_iblock_flush, - (H5AC_dest_func_t)H5HF_cache_iblock_dest, - (H5AC_clear_func_t)H5HF_cache_iblock_clear, - (H5AC_notify_func_t)H5HF_cache_iblock_notify, - (H5AC_size_func_t)H5HF_cache_iblock_size, + H5AC_FHEAP_IBLOCK_ID, /* Metadata client ID */ + "fractal heap indirect block", /* Metadata client name (for debugging) */ + H5FD_MEM_FHEAP_IBLOCK, /* File space memory type for client */ + H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ + H5HF__cache_iblock_get_load_size, /* 'get_load_size' callback */ + H5HF__cache_iblock_verify_chksum, /* 'verify_chksum' callback */ + H5HF__cache_iblock_deserialize, /* 'deserialize' callback */ + H5HF__cache_iblock_image_len, /* 'image_len' callback */ + H5HF__cache_iblock_pre_serialize, /* 'pre_serialize' callback */ + H5HF__cache_iblock_serialize, /* 'serialize' callback */ + H5HF__cache_iblock_notify, /* 'notify' callback */ + H5HF__cache_iblock_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; /* H5HF direct block inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_FHEAP_DBLOCK[1] = {{ - H5AC_FHEAP_DBLOCK_ID, - (H5AC_load_func_t)H5HF_cache_dblock_load, - (H5AC_flush_func_t)H5HF_cache_dblock_flush, - (H5AC_dest_func_t)H5HF_cache_dblock_dest, - (H5AC_clear_func_t)H5HF_cache_dblock_clear, - (H5AC_notify_func_t)H5HF_cache_dblock_notify, - (H5AC_size_func_t)H5HF_cache_dblock_size, + H5AC_FHEAP_DBLOCK_ID, /* Metadata client ID */ + "fractal heap direct block", /* Metadata client name (for debugging) */ + H5FD_MEM_FHEAP_DBLOCK, /* File space memory type for client */ + H5C__CLASS_COMPRESSED_FLAG, /* Client class behavior flags */ + H5HF__cache_dblock_get_load_size, /* 'get_load_size' callback */ + H5HF__cache_dblock_verify_chksum, /* 'verify_chksum' callback */ + H5HF__cache_dblock_deserialize, /* 'deserialize' callback */ + H5HF__cache_dblock_image_len, /* 'image_len' callback */ + H5HF__cache_dblock_pre_serialize, /* 'pre_serialize' callback */ + H5HF__cache_dblock_serialize, /* 'serialize' callback */ + H5HF__cache_dblock_notify, /* 'notify' callback */ + H5HF__cache_dblock_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -272,174 +312,294 @@ H5HF__dtable_encode(H5F_t *f, uint8_t **pp, const H5HF_dtable_t *dtable) /*------------------------------------------------------------------------- - * Function: H5HF_cache_hdr_load + * Function: H5HF__cache_hdr_get_load_size() * - * Purpose: Loads a fractal heap header from the disk. + * Purpose: Determine the size of the fractal heap header on disk, + * and set *image_len to this value. * - * Return: Success: Pointer to a new fractal heap + * This code is based on the old H5HF_cache_hdr_load() routine + * that was used with the version 2 metadata cache. Note the + * use of a dummy header to compute the on disk size of the header. + * + * Note also that the value returned by this function presumes that + * there is no I/O filtering data in the header. If there is, the + * size reported will be too small, and H5C_load_entry() + * will have to make two tries to load the fractal heap header. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_hdr_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; /* pointer to user data */ + H5HF_hdr_t dummy_hdr; /* dummy header -- to compute size */ + unsigned id_len; /* Size of heap IDs (in bytes) */ + unsigned filter_len; /* Size of I/O filter information (in bytes) */ + size_t filter_info_size; /* Size of filter information */ + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(udata); + HDassert(image_len); + + if(image == NULL) { + /* Set the internal parameters for the heap */ + dummy_hdr.f = udata->f; + dummy_hdr.sizeof_size = H5F_SIZEOF_SIZE(udata->f); + dummy_hdr.sizeof_addr = H5F_SIZEOF_ADDR(udata->f); + + /* Compute the 'base' size of the fractal heap header on disk */ + *image_len = (size_t)H5HF_HEADER_SIZE(&dummy_hdr); + + } else { /* compute actual_len */ + + HDassert(actual_len); + HDassert(*actual_len == *image_len); + + /* Magic number */ + if(HDmemcmp(image, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_DONE(FAIL) + image += H5_SIZEOF_MAGIC; + + /* Version */ + if(*image++ != H5HF_HDR_VERSION) + HGOTO_DONE(FAIL) + + /* General heap information */ + UINT16DECODE(image, id_len); /* Heap ID length */ + UINT16DECODE(image, filter_len); /* I/O filters' encoded length */ + + if(filter_len > 0) { + + /* Compute the size of the extra filter information */ + filter_info_size = (size_t)(H5F_SIZEOF_SIZE(udata->f) /* Size of size for filtered root direct block */ + + (unsigned)4 /* Size of filter mask for filtered root direct block */ + + filter_len); /* Size of encoded I/O filter info */ + + /* Compute the heap header's size */ + *actual_len += filter_info_size; + } + + } /* compute actual_len */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_hdr_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_hdr_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_hdr_verify_chksum() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_hdr_deserialize + * + * Purpose: Given a buffer containing an on disk image of a fractal heap + * header block, allocate an instance of H5HF_hdr_t, load the contents + * of the buffer into into the new instance of H5HF_hdr_t, and then + * return a pointer to the new instance. + * + * Since H5HF__cache_hdr_get_load_size() reports header on disk size + * base on the assumption that the header contains no I/O filtering + * data, it is possible that the provided image will be too small. + * + * In this case, we DO NOT flag an error when this is discovered. + * Instead, we make note of the correct image size, and report + * success. + * + * Since H5HF__cache_hdr_image_len() callback is defined, + * H5C_load_entry() will call H5HF__cache_hdr_image_len() and + * obtain the correct image length. + * + * Since the H5AC__CLASS_SPECULATIVE_LOAD_FLAG is set, + * H5C_load_entry() will load an image of the correct size, and + * then call this function again to deserialize it. Before doing + * so, it will also call H5HF__cache_hdr_free_icr() to discard the + * result of the first deserialize call. + * + * Note that the v2 B-tree and free space manager associated + * with the fractal heap (roots stored in the huge_bt2 and fspace + * fields respectively) are not loaded at this time. As best I can + * tell from reviewing the code, they are loaded or created when + * they are accessed. + * + * Return: Success: Pointer to in core representation * Failure: NULL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static H5HF_hdr_t * -H5HF_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5HF__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { - H5HF_hdr_t *hdr = NULL; /* Fractal heap info */ - H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; - size_t min_size; /* Header size */ - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5HF_HDR_BUF_SIZE]; /* Buffer for header */ - uint8_t *buf; /* Pointer to header buffer */ - size_t buf_size; /* Current size of temporary buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5HF_hdr_t *hdr = NULL; /* Fractal heap info */ + H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; /* User data for callback */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into into supplied image */ + size_t size; /* Header size */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ - unsigned tries, max_tries; /* The # of read attempts */ - unsigned retries; /* The # of retries */ uint8_t heap_flags; /* Status flags for heap */ - H5HF_hdr_t *ret_value; /* Return value */ + void * ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ + HDassert(image); + HDassert(len > 0); HDassert(udata); + HDassert(dirty); /* Allocate space for the fractal heap data structure */ if(NULL == (hdr = H5HF_hdr_alloc(udata->f))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't wrap buffer") - - /* Compute the minimum size of the fractal heap header to determine filter info */ - min_size = (size_t)H5HF_MIN_HEADER_SIZE; - - /* Get a pointer to a buffer that's large enough for serialized header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, min_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "can't get actual buffer") - buf_size = min_size; - - /* Get the # of read attempts */ - tries = max_tries = H5F_GET_READ_ATTEMPTS(udata->f); - retries = 0; - do { - /* Read minimum header from disk */ - if(H5F_block_read(udata->f, H5FD_MEM_FHEAP_HDR, addr, min_size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "can't read fractal heap header") - - /* Get temporary pointer to serialized header */ - p = buf; - - /* Magic number */ - if(HDmemcmp(p, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - continue; /* Transfer control to while() and count this as a bad read, not an error */ - p += H5_SIZEOF_MAGIC; - - /* Version */ - if(*p++ != H5HF_HDR_VERSION) - continue; /* Transfer control to while() and count this as a bad read, not an error */ - - /* General heap information */ - UINT16DECODE(p, hdr->id_len); /* Heap ID length */ - UINT16DECODE(p, hdr->filter_len); /* I/O filters' encoded length */ - - /* Fixed-size header length */ - hdr->heap_size = (size_t)H5HF_HEADER_SIZE(hdr); - - /* Check for I/O filter information to decode */ - if(hdr->filter_len > 0) - /* Add the variable-len I/O filter information */ - hdr->heap_size += (size_t)(hdr->sizeof_size /* Size of size for filtered root direct block */ - + (unsigned)4 /* Size of filter mask for filtered root direct block */ - + hdr->filter_len); /* Size of encoded I/O filter info */ - - /* Check if we need to resize the buffer */ - if(hdr->heap_size > buf_size) { - /* Re-size current buffer */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, hdr->heap_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "can't get actual buffer") - buf_size = hdr->heap_size; - } /* end if */ - - /* Read the whole header, possibly with filter info */ - /* (Can't use H5F_read_check_metadata() since the length from the - * minimum-sized header info might be incorrect. -QAK) - */ - if(H5F_block_read(udata->f, H5FD_MEM_FHEAP_HDR, addr, hdr->heap_size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "can't read remainder of fractal heap header") - - /* Retrieve stored and computed checksums */ - H5F_get_checksums(buf, hdr->heap_size, &stored_chksum, &computed_chksum); + /* Compute the 'base' size of the fractal heap header on disk */ + size = (size_t)H5HF_HEADER_SIZE(hdr); - /* Verify checksum */ - if(stored_chksum == computed_chksum) - break; - } while (--tries); + /* the size we have just calculated presumes that there is no I/O + * filter information in the header. If there is no filter information, + * the deserialize operation should succeed. + * + * If there is filter information, the first attempt to deserialize + * the header will reveal this. In this case, we will be unable to + * deserialize the header as the supplied image will be too small. + * However, we will make note of the correct size and report success + * anyway. + * + * When H5C_load_entry() calls H5HF__cache_hdr_image_len(), we will report + * the correct size. Since the H5C__CLASS_SPECULATIVE_LOAD_FLAG is set, + * this will prompt H5C_load_entry() to load the correct size image, + * discard the result of the first attempt at deserialization, and + * call this routine a second time to deserialize the correct size + * buffer. + */ + HDassert(size <= len); - if(tries == 0) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "incorrect metadata checksum after all tries (%u) for fractal heap header", max_tries) + /* Magic number */ + if(HDmemcmp(image, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "wrong fractal heap header signature") + image += H5_SIZEOF_MAGIC; - /* Calculate and track the # of retry */ - retries += (max_tries - tries); - if(retries) /* Does not track 0 retry */ - if(H5F_track_metadata_read_retries(udata->f, H5AC_FHEAP_HDR_ID, retries) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "cannot track read tries = %u ", retries) + /* Version */ + if(*image++ != H5HF_HDR_VERSION) + HGOTO_ERROR(H5E_HEAP, H5E_VERSION, NULL, "wrong fractal heap header version") - /* Reset pointer into [possibly] re-sized buffer */ - /* (Skip over information decoded earlier) */ - p = buf + min_size; + /* General heap information */ + UINT16DECODE(image, hdr->id_len); /* Heap ID length */ + UINT16DECODE(image, hdr->filter_len); /* I/O filters' encoded length */ /* Heap status flags */ /* (bit 0: "huge" object IDs have wrapped) */ /* (bit 1: checksum direct blocks) */ - heap_flags = *p++; + heap_flags = *image++; hdr->huge_ids_wrapped = heap_flags & H5HF_HDR_FLAGS_HUGE_ID_WRAPPED; hdr->checksum_dblocks = heap_flags & H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS; /* "Huge" object information */ - UINT32DECODE(p, hdr->max_man_size); /* Max. size of "managed" objects */ - H5F_DECODE_LENGTH(udata->f, p, hdr->huge_next_id); /* Next ID to use for "huge" object */ - H5F_addr_decode(udata->f, &p, &hdr->huge_bt2_addr); /* Address of "huge" object tracker B-tree */ + UINT32DECODE(image, hdr->max_man_size); /* Max. size of "managed" objects */ + H5F_DECODE_LENGTH(udata->f, image, hdr->huge_next_id); /* Next ID to use for "huge" object */ + H5F_addr_decode(udata->f, &image, &hdr->huge_bt2_addr); /* Address of "huge" object tracker B-tree */ /* "Managed" object free space information */ - H5F_DECODE_LENGTH(udata->f, p, hdr->total_man_free); /* Internal free space in managed direct blocks */ - H5F_addr_decode(udata->f, &p, &hdr->fs_addr); /* Address of free section header */ + H5F_DECODE_LENGTH(udata->f, image, hdr->total_man_free); /* Internal free space in managed direct blocks */ + H5F_addr_decode(udata->f, &image, &hdr->fs_addr); /* Address of free section header */ /* Heap statistics */ - H5F_DECODE_LENGTH(udata->f, p, hdr->man_size); - H5F_DECODE_LENGTH(udata->f, p, hdr->man_alloc_size); - H5F_DECODE_LENGTH(udata->f, p, hdr->man_iter_off); - H5F_DECODE_LENGTH(udata->f, p, hdr->man_nobjs); - H5F_DECODE_LENGTH(udata->f, p, hdr->huge_size); - H5F_DECODE_LENGTH(udata->f, p, hdr->huge_nobjs); - H5F_DECODE_LENGTH(udata->f, p, hdr->tiny_size); - H5F_DECODE_LENGTH(udata->f, p, hdr->tiny_nobjs); + H5F_DECODE_LENGTH(udata->f, image, hdr->man_size); + H5F_DECODE_LENGTH(udata->f, image, hdr->man_alloc_size); + H5F_DECODE_LENGTH(udata->f, image, hdr->man_iter_off); + H5F_DECODE_LENGTH(udata->f, image, hdr->man_nobjs); + H5F_DECODE_LENGTH(udata->f, image, hdr->huge_size); + H5F_DECODE_LENGTH(udata->f, image, hdr->huge_nobjs); + H5F_DECODE_LENGTH(udata->f, image, hdr->tiny_size); + H5F_DECODE_LENGTH(udata->f, image, hdr->tiny_nobjs); /* Managed objects' doubling-table info */ - if(H5HF__dtable_decode(udata->f, &p, &(hdr->man_dtable)) < 0) + if(H5HF__dtable_decode(hdr->f, &image, &(hdr->man_dtable)) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, NULL, "unable to encode managed obj. doubling table info") + /* Sanity check */ + /* (allow for checksum not decoded yet) */ + HDassert((size_t)(image - (const uint8_t *)_image) == (size - H5HF_SIZEOF_CHKSUM)); + /* Check for I/O filter information to decode */ if(hdr->filter_len > 0) { + size_t filter_info_size; /* Size of filter information */ H5O_pline_t *pline; /* Pipeline information from the header on disk */ + /* Compute the size of the extra filter information */ + filter_info_size = (size_t)(hdr->sizeof_size /* Size of size for filtered root direct block */ + + (unsigned)4 /* Size of filter mask for filtered root direct block */ + + hdr->filter_len); /* Size of encoded I/O filter info */ + + /* Compute the heap header's size */ + hdr->heap_size = size + filter_info_size; + + if(size == len) + /* we were supplied with too small a buffer -- goto done + * and let H5C_load_entry() retry with a larger buffer + */ + HGOTO_DONE((void *)hdr) + + else + if((size + filter_info_size) != len) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "bad image len") + /* Decode the size of a filtered root direct block */ - H5F_DECODE_LENGTH(udata->f, p, hdr->pline_root_direct_size); + H5F_DECODE_LENGTH(udata->f, image, hdr->pline_root_direct_size); /* Decode the filter mask for a filtered root direct block */ - UINT32DECODE(p, hdr->pline_root_direct_filter_mask); + UINT32DECODE(image, hdr->pline_root_direct_filter_mask); /* Decode I/O filter information */ - if(NULL == (pline = (H5O_pline_t *)H5O_msg_decode(udata->f, udata->dxpl_id, NULL, H5O_PLINE_ID, p))) + if(NULL == (pline = (H5O_pline_t *)H5O_msg_decode(hdr->f, udata->dxpl_id, NULL, H5O_PLINE_ID, image))) HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, NULL, "can't decode I/O pipeline filters") - p += hdr->filter_len; + + image += hdr->filter_len; /* Copy the information into the header's I/O pipeline structure */ if(NULL == H5O_msg_copy(H5O_PLINE_ID, pline, &(hdr->pline))) @@ -448,354 +608,441 @@ H5HF_cache_hdr_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) /* Release the space allocated for the I/O pipeline filters */ H5O_msg_free(H5O_PLINE_ID, pline); } /* end if */ + else + /* Set the heap header's size */ + hdr->heap_size = size; + + /* checksum verification already done in verify_chksum cb */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - (const uint8_t *)buf) == (hdr->heap_size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == hdr->heap_size); /* Finish initialization of heap header */ if(H5HF_hdr_finish_init(hdr) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "can't finish initializing shared fractal heap header") /* Set return value */ - ret_value = hdr; + ret_value = (void *)hdr; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, NULL, "can't close wrapped buffer") if(!ret_value && hdr) if(H5HF_hdr_free(hdr) < 0) HDONE_ERROR(H5E_HEAP, H5E_CANTRELEASE, NULL, "unable to release fractal heap header") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_hdr_load() */ /*lint !e818 Can't make udata a pointer to const */ +} /* end H5HF__cache_hdr_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_hdr_flush + * Function: H5HF__cache_hdr_image_len * - * Purpose: Flushes a dirty fractal heap header to disk. + * Purpose: Return the actual size of the fractal heap header on + * disk image. * - * Return: Non-negative on success/Negative on failure + * If the header contains filter information, this size will be + * larger than the value returned by H5HF__cache_hdr_get_load_size(). * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_hdr_t *hdr, unsigned H5_ATTR_UNUSED * flags_ptr) +static herr_t +H5HF__cache_hdr_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5WB_t *wb = NULL; /* Wrapped buffer for header data */ - uint8_t hdr_buf[H5HF_HDR_BUF_SIZE]; /* Buffer for header */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5HF_hdr_t *hdr = (const H5HF_hdr_t *)_thing; /* Fractal heap info */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + HDassert(image_len); - if(hdr->cache_info.is_dirty) { - uint8_t *buf; /* Temporary raw data buffer */ - uint8_t *p; /* Pointer into raw data buffer */ - size_t size; /* Header size on disk */ - uint8_t heap_flags; /* Status flags for heap */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - -#ifndef NDEBUG -{ - /* Verify that flush dependencies are working correctly. Do this - * by verifying that either: - * - * 1) the header has a root iblock, and that the root iblock and all - * of its children are clean, or - * - * 2) The header has a root dblock, which is clean, or - * - * 3) The heap is empty, and thus the header has neither a root - * iblock no a root dblock. In this case, the flush ordering - * constraint is met by default. - * - * Do this with a call to H5HF__cache_verify_hdr_descendants_clean(). - */ - hbool_t descendants_clean = TRUE; + *image_len = hdr->heap_size; - if(H5HF__cache_verify_hdr_descendants_clean(f, dxpl_id, hdr, &descendants_clean) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify hdr descendants clean.") - HDassert(descendants_clean); -} -#endif /* NDEBUG */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HF__cache_hdr_image_len() */ - /* Set the shared heap header's file context for this operation */ - hdr->f = f; - - /* Wrap the local buffer for serialized header info */ - if(NULL == (wb = H5WB_wrap(hdr_buf, sizeof(hdr_buf)))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't wrap buffer") - - /* Compute the size of the heap header on disk */ - size = hdr->heap_size; - - /* Get a pointer to a buffer that's large enough for serialized header */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "can't get actual buffer") - - /* Get temporary pointer to serialized header */ - p = buf; - - /* Magic number */ - HDmemcpy(p, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5HF_HDR_VERSION; - - /* General heap information */ - UINT16ENCODE(p, hdr->id_len); /* Heap ID length */ - UINT16ENCODE(p, hdr->filter_len); /* I/O filters' encoded length */ - - /* Heap status flags */ - /* (bit 0: "huge" object IDs have wrapped) */ - /* (bit 1: checksum direct blocks) */ - heap_flags = 0; - heap_flags = (uint8_t)(heap_flags | (hdr->huge_ids_wrapped ? H5HF_HDR_FLAGS_HUGE_ID_WRAPPED : 0)); - heap_flags = (uint8_t)(heap_flags | (hdr->checksum_dblocks ? H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS : 0)); - *p++ = heap_flags; - - /* "Huge" object information */ - UINT32ENCODE(p, hdr->max_man_size); /* Max. size of "managed" objects */ - H5F_ENCODE_LENGTH(f, p, hdr->huge_next_id); /* Next ID to use for "huge" object */ - H5F_addr_encode(f, &p, hdr->huge_bt2_addr); /* Address of "huge" object tracker B-tree */ - - /* "Managed" object free space information */ - H5F_ENCODE_LENGTH(f, p, hdr->total_man_free); /* Internal free space in managed direct blocks */ - H5F_addr_encode(f, &p, hdr->fs_addr); /* Address of free section header */ - - /* Heap statistics */ - H5F_ENCODE_LENGTH(f, p, hdr->man_size); - H5F_ENCODE_LENGTH(f, p, hdr->man_alloc_size); - H5F_ENCODE_LENGTH(f, p, hdr->man_iter_off); - H5F_ENCODE_LENGTH(f, p, hdr->man_nobjs); - H5F_ENCODE_LENGTH(f, p, hdr->huge_size); - H5F_ENCODE_LENGTH(f, p, hdr->huge_nobjs); - H5F_ENCODE_LENGTH(f, p, hdr->tiny_size); - H5F_ENCODE_LENGTH(f, p, hdr->tiny_nobjs); - - /* Managed objects' doubling-table info */ - if(H5HF__dtable_encode(hdr->f, &p, &(hdr->man_dtable)) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, FAIL, "unable to encode managed obj. doubling table info") - - /* Check for I/O filter information to encode */ - if(hdr->filter_len > 0) { - /* Encode the size of a filtered root direct block */ - H5F_ENCODE_LENGTH(f, p, hdr->pline_root_direct_size); + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_hdr_pre_serialize + * + * Purpose: As best I can tell, fractal heap header blocks are always + * allocated in real file space. Thus this routine simply verifies + * this, verifies that the len parameter contains the expected + * value, and returns an error if either of these checks fail. + * + * When compiled in debug mode, the function also verifies that all + * indirect and direct blocks that are children of the header are + * either clean, or not in the metadata cache. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_hdr_pre_serialize(const H5F_t *f, hid_t dxpl_id, void *_thing, + haddr_t addr, size_t len, size_t H5_ATTR_UNUSED compressed_len, + haddr_t H5_ATTR_UNUSED *new_addr, size_t H5_ATTR_UNUSED *new_len, + size_t H5_ATTR_UNUSED *new_compressed_len, unsigned *flags) +{ + H5HF_hdr_t *hdr = (H5HF_hdr_t *)_thing; /* Fractal heap info */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Encode the filter mask for a filtered root direct block */ - UINT32ENCODE(p, hdr->pline_root_direct_filter_mask); + FUNC_ENTER_STATIC - /* Encode I/O filter information */ - if(H5O_msg_encode(hdr->f, H5O_PLINE_ID, FALSE, p, &(hdr->pline)) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, FAIL, "can't encode I/O pipeline fiters") - p += hdr->filter_len; - } /* end if */ + /* Sanity checks */ + HDassert(f); + HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + HDassert(H5F_addr_defined(addr)); + HDassert(addr == hdr->heap_addr); + HDassert(new_addr); + HDassert(new_len); + HDassert(flags); - /* Compute metadata checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); +#ifndef NDEBUG +{ + hbool_t descendants_clean = TRUE; - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); + /* Verify that flush dependencies are working correctly. Do this + * by verifying that either: + * + * 1) the header has a root iblock, and that the root iblock and all + * of its children are clean, or + * + * 2) The header has a root dblock, which is clean, or + * + * 3) The heap is empty, and thus the header has neither a root + * iblock no a root dblock. In this case, the flush ordering + * constraint is met by default. + * + * Do this with a call to H5HF__cache_verify_hdr_descendants_clean(). + */ + if(H5HF__cache_verify_hdr_descendants_clean((H5F_t *)f, dxpl_id, hdr, &descendants_clean) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify hdr descendants clean.") + HDassert(descendants_clean); +} +#endif /* NDEBUG */ - /* Write the heap header. */ - HDassert((size_t)(p - buf) == size); - if(H5F_block_write(f, H5FD_MEM_FHEAP_HDR, addr, size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFLUSH, FAIL, "unable to save fractal heap header to disk") + if(H5F_IS_TMP_ADDR(f, addr)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "addr in temporary space?!?."); - hdr->cache_info.is_dirty = FALSE; - } /* end if */ + if(len != hdr->heap_size) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "unexpected image len."); - if(destroy) - if(H5HF_cache_hdr_dest(f, hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap header") + *flags = 0; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") - FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_cache_hdr_flush() */ +} /* end H5HF__cache_hdr_pre_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_hdr_dest + * Function: H5HF__cache_hdr_serialize * - * Purpose: Destroys a fractal heap header in memory. + * Purpose: Construct the on disk image of the header, and place it in + * the buffer pointed to by image. Return SUCCEED on success, + * and FAIL on failure. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_hdr_dest(H5F_t *f, H5HF_hdr_t *hdr) +static herr_t +H5HF__cache_hdr_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) { + H5HF_hdr_t *hdr = (H5HF_hdr_t *)_thing; /* Fractal heap info */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ + uint8_t heap_flags; /* Status flags for heap */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ + HDassert(f); + HDassert(image); HDassert(hdr); - HDassert(hdr->rc == 0); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + HDassert(len == hdr->heap_size); + + /* Set the shared heap header's file context for this operation */ + hdr->f = f; + + /* Magic number */ + HDmemcpy(image, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!hdr->cache_info.free_file_space_on_destroy || H5F_addr_defined(hdr->cache_info.addr)); + /* Version # */ + *image++ = H5HF_HDR_VERSION; - /* Check for freeing file space for heap header */ - if(hdr->cache_info.free_file_space_on_destroy) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_HDR, H5AC_dxpl_id, hdr->cache_info.addr, (hsize_t)hdr->heap_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap header") + /* General heap information */ + UINT16ENCODE(image, hdr->id_len); /* Heap ID length */ + UINT16ENCODE(image, hdr->filter_len); /* I/O filters' encoded length */ + + /* Heap status flags */ + /* (bit 0: "huge" object IDs have wrapped) */ + /* (bit 1: checksum direct blocks) */ + heap_flags = 0; + heap_flags = (uint8_t)(heap_flags | (hdr->huge_ids_wrapped ? H5HF_HDR_FLAGS_HUGE_ID_WRAPPED : 0)); + heap_flags = (uint8_t)(heap_flags | (hdr->checksum_dblocks ? H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS : 0)); + *image++ = heap_flags; + + /* "Huge" object information */ + UINT32ENCODE(image, hdr->max_man_size); /* Max. size of "managed" objects */ + H5F_ENCODE_LENGTH(f, image, hdr->huge_next_id); /* Next ID to use for "huge" object */ + H5F_addr_encode(f, &image, hdr->huge_bt2_addr); /* Address of "huge" object tracker B-tree */ + + /* "Managed" object free space information */ + H5F_ENCODE_LENGTH(f, image, hdr->total_man_free); /* Internal free space in managed direct blocks */ + H5F_addr_encode(f, &image, hdr->fs_addr); /* Address of free section header */ + + /* Heap statistics */ + H5F_ENCODE_LENGTH(f, image, hdr->man_size); + H5F_ENCODE_LENGTH(f, image, hdr->man_alloc_size); + H5F_ENCODE_LENGTH(f, image, hdr->man_iter_off); + H5F_ENCODE_LENGTH(f, image, hdr->man_nobjs); + H5F_ENCODE_LENGTH(f, image, hdr->huge_size); + H5F_ENCODE_LENGTH(f, image, hdr->huge_nobjs); + H5F_ENCODE_LENGTH(f, image, hdr->tiny_size); + H5F_ENCODE_LENGTH(f, image, hdr->tiny_nobjs); + + /* Managed objects' doubling-table info */ + if(H5HF__dtable_encode(hdr->f, &image, &(hdr->man_dtable)) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, FAIL, "unable to encode managed obj. doubling table info") + + /* Check for I/O filter information to encode */ + if(hdr->filter_len > 0) { + /* Encode the size of a filtered root direct block */ + H5F_ENCODE_LENGTH(f, image, hdr->pline_root_direct_size); + + /* Encode the filter mask for a filtered root direct block */ + UINT32ENCODE(image, hdr->pline_root_direct_filter_mask); + + /* Encode I/O filter information */ + if(H5O_msg_encode(hdr->f, H5O_PLINE_ID, FALSE, image, &(hdr->pline)) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, FAIL, "can't encode I/O pipeline fiters") + image += hdr->filter_len; } /* end if */ - /* Free the shared info itself */ - if(H5HF_hdr_free(hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "unable to release fractal heap header") + /* Compute metadata checksum */ + metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); + + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + + /* sanity check */ + HDassert((size_t)(image - (uint8_t *)_image) == len); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_hdr_dest() */ +} /* end H5HF__cache_hdr_serialize() */ + +/***************************************/ +/* no H5HF__cache_hdr_notify() function */ +/***************************************/ /*------------------------------------------------------------------------- - * Function: H5HF_cache_hdr_clear + * Function: H5HF__cache_hdr_free_icr * - * Purpose: Mark a fractal heap header in memory as non-dirty. + * Purpose: Free the in core representation of the fractal heap header. * - * Return: Non-negative on success/Negative on failure + * This routine frees just the header itself, not the + * associated version 2 B-Tree, the associated Free Space Manager, + * nor the indirect/direct block tree that is rooted in the header. * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * This routine also does not free the file space that may + * be allocated to the header. + * + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_hdr_clear(H5F_t *f, H5HF_hdr_t *hdr, hbool_t destroy) +static herr_t +H5HF__cache_hdr_free_icr(void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_hdr_t *hdr = (H5HF_hdr_t *)_thing; /* Fractal heap info */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + HDassert(hdr->rc == 0); - /* Reset the dirty flag. */ - hdr->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5HF_cache_hdr_dest(f, hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap header") + if(H5HF_hdr_free(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "unable to release fractal heap header") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_hdr_clear() */ +} /* end H5HF__cache_hdr_free_icr() */ + +/***********************************************************/ +/* metadata cache callback definitions for indirect blocks */ +/***********************************************************/ /*------------------------------------------------------------------------- - * Function: H5HF_cache_hdr_size + * Function: H5HF__cache_iblock_get_load_size() * - * Purpose: Compute the size in bytes of a fractal heap header - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Compute the size of the on disk image of the indirect + * block, and place this value in *image_len. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_hdr_size(const H5F_t H5_ATTR_UNUSED *f, const H5HF_hdr_t *hdr, size_t *size_ptr) +static herr_t +H5HF__cache_iblock_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5HF_iblock_cache_ud_t *udata = (H5HF_iblock_cache_ud_t *)_udata; /* User data for callback */ - /* Check arguments */ - HDassert(f); - HDassert(hdr); - HDassert(size_ptr); + FUNC_ENTER_STATIC_NOERR - /* Set size value */ - *size_ptr = hdr->heap_size; + /* Sanity checks */ + HDassert(udata); + HDassert(udata->par_info); + HDassert(udata->par_info->hdr); + HDassert(image_len); + + if(image == NULL) + *image_len = (size_t)H5HF_MAN_INDIRECT_SIZE(udata->par_info->hdr, *udata->nrows); + else { + HDassert(actual_len); + HDassert(*actual_len == *image_len); + } FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5HF_cache_hdr_size() */ +} /* end H5HF__cache_iblock_get_load_size() */ /***********************************************************/ /* metadata cache callback definitions for indirect blocks */ /***********************************************************/ + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_iblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF__cache_iblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_iblock_verify_chksum() */ + /*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_load + * Function: H5HF__cache_iblock_deserialize * - * Purpose: Loads a fractal heap indirect block from the disk. + * Purpose: Given a buffer containing the on disk image of the indirect + * block, allocate an instance of H5HF_indirect_t, load the data + * in the buffer into this new instance, and return a pointer to + * it. * - * Return: Success: Pointer to a new fractal heap indirect block + * As best I can tell, the size of the indirect block image is fully + * know before the image is loaded, so this function should succeed + * unless the image is corrupt or memory allocation fails. * + * Return: Success: Pointer to in core representation * Failure: NULL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 27 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static H5HF_indirect_t * -H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5HF__cache_iblock_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { H5HF_hdr_t *hdr; /* Shared fractal heap information */ - H5HF_iblock_cache_ud_t *udata = (H5HF_iblock_cache_ud_t *)_udata; /* user data for callback */ - H5HF_indirect_t *iblock = NULL; /* Indirect block info */ - H5WB_t *wb = NULL; /* Wrapped buffer for indirect block data */ - uint8_t iblock_buf[H5HF_IBLOCK_BUF_SIZE]; /* Buffer for indirect block */ - uint8_t *buf; /* Temporary buffer */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5HF_iblock_cache_ud_t *udata = (H5HF_iblock_cache_ud_t *)_udata; /* User data for callback */ + H5HF_indirect_t *iblock = NULL; /* Indirect block info */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ haddr_t heap_addr; /* Address of heap header in the file */ + uint32_t stored_chksum; /* Stored metadata checksum value */ unsigned u; /* Local index variable */ - H5HF_indirect_t *ret_value; /* Return value */ + void * ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ + HDassert(image); HDassert(udata); - - /* Allocate space for the fractal heap indirect block */ - if(NULL == (iblock = H5FL_CALLOC(H5HF_indirect_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - /* Get the pointer to the shared heap header */ + HDassert(dirty); hdr = udata->par_info->hdr; + HDassert(hdr->f); /* Set the shared heap header's file context for this operation */ hdr->f = udata->f; + /* Allocate space for the fractal heap indirect block */ + if(NULL == (iblock = H5FL_CALLOC(H5HF_indirect_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + /* Share common heap information */ iblock->hdr = hdr; if(H5HF_hdr_incr(hdr) < 0) @@ -806,35 +1053,23 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) iblock->nrows = *udata->nrows; iblock->nchildren = 0; - /* Wrap the local buffer for serialized indirect block */ - if(NULL == (wb = H5WB_wrap(iblock_buf, sizeof(iblock_buf)))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't wrap buffer") - /* Compute size of indirect block */ iblock->size = H5HF_MAN_INDIRECT_SIZE(hdr, iblock->nrows); - /* Get a pointer to a buffer that's large enough for serialized indirect block */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, iblock->size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "can't get actual buffer") - - /* Read and validate indirect block from disk */ - if(H5F_read_check_metadata(f, dxpl_id, H5FD_MEM_FHEAP_IBLOCK, H5AC_FHEAP_IBLOCK_ID, addr, iblock->size, iblock->size, buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "incorrect metadata checksum for fractal heap indirect block") - - /* Get temporary pointer to serialized indirect block */ - p = buf; + /* sanity check */ + HDassert(iblock->size == len); /* Magic number */ - if(HDmemcmp(p, H5HF_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "wrong fractal heap indirect block signature") - p += H5_SIZEOF_MAGIC; + if(HDmemcmp(image, H5HF_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "wrong fractal heap indirect block signature") + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5HF_IBLOCK_VERSION) + if(*image++ != H5HF_IBLOCK_VERSION) HGOTO_ERROR(H5E_HEAP, H5E_VERSION, NULL, "wrong fractal heap direct block version") /* Address of heap that owns this block */ - H5F_addr_decode(udata->f, &p, &heap_addr); + H5F_addr_decode(udata->f, &image, &heap_addr); if(H5F_addr_ne(heap_addr, hdr->heap_addr)) HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "incorrect heap header address for direct block") @@ -859,7 +1094,7 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) } /* end else */ /* Offset of heap within the heap's address space */ - UINT64DECODE_VAR(p, iblock->block_off, hdr->heap_off_size); + UINT64DECODE_VAR(image, iblock->block_off, hdr->heap_off_size); /* Allocate & decode child block entry tables */ HDassert(iblock->nrows > 0); @@ -881,7 +1116,7 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) for(u = 0; u < (iblock->nrows * hdr->man_dtable.cparam.width); u++) { /* Decode child block address */ - H5F_addr_decode(udata->f, &p, &(iblock->ents[u].addr)); + H5F_addr_decode(udata->f, &image, &(iblock->ents[u].addr)); /* Check for heap with I/O filters */ if(hdr->filter_len > 0) { @@ -891,7 +1126,7 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) /* Decode extra information for direct blocks */ if(u < (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width)) { /* Size of filtered direct block */ - H5F_DECODE_LENGTH(udata->f, p, iblock->filt_ents[u].size); + H5F_DECODE_LENGTH(udata->f, image, iblock->filt_ents[u].size); /* Sanity check */ /* (either both the address & size are defined or both are @@ -901,7 +1136,7 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) || (!H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size == 0)); /* I/O filter mask for filtered direct block */ - UINT32DECODE(p, iblock->filt_ents[u].filter_mask); + UINT32DECODE(image, iblock->filt_ents[u].filter_mask); } /* end if */ } /* end if */ @@ -915,14 +1150,17 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) /* Sanity check */ HDassert(iblock->nchildren); /* indirect blocks w/no children should have been deleted */ - /* Already decoded and compared stored checksum earlier, when reading */ + /* checksum verification already done by verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); /* Sanity check */ - HDassert((size_t)(p - (const uint8_t *)buf) == (iblock->size - H5_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == iblock->size); /* Check if we have any indirect block children */ if(iblock->nrows > hdr->man_dtable.max_direct_rows) { - unsigned indir_rows; /* Number of indirect rows in this indirect block */ + unsigned indir_rows;/* Number of indirect rows in this indirect block */ /* Compute the number of indirect rows for this indirect block */ indir_rows = iblock->nrows - hdr->man_dtable.max_direct_rows; @@ -935,343 +1173,323 @@ H5HF_cache_iblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) iblock->child_iblocks = NULL; /* Set return value */ - ret_value = iblock; + ret_value = (void *)iblock; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, NULL, "can't close wrapped buffer") if(!ret_value && iblock) if(H5HF_man_iblock_dest(iblock) < 0) HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy fractal heap indirect block") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_iblock_load() */ +} /* end H5HF__cache_iblock_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_flush + * Function: H5HF__cache_iblock_image_len * - * Purpose: Flushes a dirty fractal heap indirect block to disk. + * Purpose: Return the size of the on disk image of the iblock. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 6 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_iblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_indirect_t *iblock, unsigned H5_ATTR_UNUSED * flags_ptr) +static herr_t +H5HF__cache_iblock_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - H5WB_t *wb = NULL; /* Wrapped buffer for indirect block data */ - uint8_t iblock_buf[H5HF_IBLOCK_BUF_SIZE]; /* Buffer for indirect block */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5HF_indirect_t *iblock = (const H5HF_indirect_t *)_thing; /* Indirect block info */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ HDassert(iblock); + HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK); + HDassert(image_len); - if(iblock->cache_info.is_dirty) { - H5HF_hdr_t *hdr; /* Shared fractal heap information */ - uint8_t *buf; /* Temporary buffer */ - uint8_t *p; /* Pointer into raw data buffer */ -#ifndef NDEBUG - unsigned nchildren = 0; /* Track # of children */ - unsigned max_child = 0; /* Track max. child entry used */ -#endif /* NDEBUG */ - uint32_t metadata_chksum; /* Computed metadata checksum value */ - size_t u; /* Local index variable */ - -#ifndef NDEBUG -{ - /* Verify that flush dependencies are working correctly. Do this - * by verifying that all children of this iblock are clean. - */ - hbool_t descendants_clean = TRUE; - unsigned iblock_status; - - if(H5AC_get_entry_status(f, iblock->addr, &iblock_status) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get iblock status") - - /* since the current iblock is the guest of honor in a flush, we know - * that it is locked into the cache for the duration of the call. Hence - * there is no need to check to see if it is pinned or protected, or to - * protect it if it is not. - */ - if(H5HF__cache_verify_iblock_descendants_clean(f, dxpl_id, iblock, &iblock_status, &descendants_clean) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify descendants clean.") - - HDassert(descendants_clean); -} -#endif /* NDEBUG */ - - /* Get the pointer to the shared heap header */ - hdr = iblock->hdr; - - /* Set the shared heap header's file context for this operation */ - hdr->f = f; - - /* Wrap the local buffer for serialized indirect block */ - if(NULL == (wb = H5WB_wrap(iblock_buf, sizeof(iblock_buf)))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't wrap buffer") - - /* Get a pointer to a buffer that's large enough for serialized indirect block */ - if(NULL == (buf = (uint8_t *)H5WB_actual(wb, iblock->size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "can't get actual buffer") - - /* Get temporary pointer to buffer for serialized indirect block */ - p = buf; - - /* Magic number */ - HDmemcpy(p, H5HF_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; - - /* Version # */ - *p++ = H5HF_IBLOCK_VERSION; - - /* Address of heap header for heap which owns this block */ - H5F_addr_encode(f, &p, hdr->heap_addr); - - /* Offset of block in heap */ - UINT64ENCODE_VAR(p, iblock->block_off, hdr->heap_off_size); - - /* Encode indirect block-specific fields */ - for(u = 0; u < (iblock->nrows * hdr->man_dtable.cparam.width); u++) { - /* Encode child block address */ - H5F_addr_encode(f, &p, iblock->ents[u].addr); + *image_len = iblock->size; - /* Check for heap with I/O filters */ - if(hdr->filter_len > 0) { - /* Sanity check */ - HDassert(iblock->filt_ents); + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HF__cache_iblock_image_len() */ - /* Encode extra information for direct blocks */ - if(u < (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width)) { - /* Sanity check */ - /* (either both the address & size are defined or both are - * not defined) - */ - HDassert((H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size) - || (!H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size == 0)); + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_iblock_pre_serialize + * + * Purpose: The primary objective of this function is to determine if the + * indirect block is currently allocated in temporary file space, + * and if so, to move it to real file space before the entry is + * serialized. + * + * In debug compiles, this function also verifies that all children + * of this indirect block are either clean or are not in cache. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_iblock_pre_serialize(const H5F_t *f, hid_t dxpl_id, void *_thing, + haddr_t addr, size_t H5_ATTR_UNUSED len, size_t H5_ATTR_UNUSED compressed_len, + haddr_t *new_addr, size_t H5_ATTR_UNUSED *new_len, + size_t H5_ATTR_UNUSED *new_compressed_len, unsigned *flags) +{ + H5HF_hdr_t *hdr; /* Shared fractal heap information */ + H5HF_indirect_t *iblock = (H5HF_indirect_t *)_thing; /* Indirect block info */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Size of filtered direct block */ - H5F_ENCODE_LENGTH(f, p, iblock->filt_ents[u].size); + FUNC_ENTER_STATIC - /* I/O filter mask for filtered direct block */ - UINT32ENCODE(p, iblock->filt_ents[u].filter_mask); - } /* end if */ - } /* end if */ + /* Sanity checks */ + HDassert(f); + HDassert(iblock); + HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK); + HDassert(iblock->cache_info.size == iblock->size); + HDassert(H5F_addr_defined(addr)); + HDassert(H5F_addr_eq(iblock->addr, addr)); + HDassert(new_addr); + HDassert(new_len); + HDassert(flags); + hdr = iblock->hdr; + HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); #ifndef NDEBUG - /* Count child blocks */ - if(H5F_addr_defined(iblock->ents[u].addr)) { - nchildren++; - if(u > max_child) - max_child = u; - } /* end if */ -#endif /* NDEBUG */ - } /* end for */ - - /* Compute checksum */ - metadata_chksum = H5_checksum_metadata(buf, (size_t)(p - buf), 0); +{ + hbool_t descendants_clean = TRUE; + unsigned iblock_status = 0; - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); + /* verify that flush dependencies are working correctly. Do this + * by verifying that all children of this iblock are clean. + */ + if(H5AC_get_entry_status(f, iblock->addr, &iblock_status) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get iblock status") - /* Sanity check */ - HDassert((size_t)(p - buf) == iblock->size); -#ifndef NDEBUG - HDassert(nchildren == iblock->nchildren); - HDassert(max_child == iblock->max_child); + /* since the current iblock is the guest of honor in a flush, we know + * that it is locked into the cache for the duration of the call. Hence + * there is no need to check to see if it is pinned or protected, or to + * protect it if it is not. + */ + if(H5HF__cache_verify_iblock_descendants_clean((H5F_t *)f, dxpl_id, iblock, &iblock_status, &descendants_clean) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_SYSTEM, FAIL, "can't verify descendants clean.") + HDassert(descendants_clean); +} #endif /* NDEBUG */ - /* Check for needing to re-allocate indirect block from 'temp.' to 'normal' file space */ - if(H5F_IS_TMP_ADDR(f, addr)) { - /* Sanity check */ - HDassert(H5F_addr_eq(iblock->addr, addr)); + /* Check to see if we must re-allocate the iblock from temporary to + * normal (AKA real) file space. + */ + if(H5F_IS_TMP_ADDR(f, addr)) { + haddr_t iblock_addr; - /* Allocate 'normal' space for the new indirect block on disk */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, (hsize_t)iblock->size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block") + /* Allocate 'normal' space for the new indirect block on disk */ + if(HADDR_UNDEF == (iblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_IBLOCK, dxpl_id, (hsize_t)iblock->size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap indirect block") - /* Sanity check */ - HDassert(!H5F_addr_eq(iblock->addr, addr)); + /* Sanity check */ + HDassert(!H5F_addr_eq(iblock->addr, iblock_addr)); - /* Let the metadata cache know the block moved */ - if(H5AC_move_entry(f, H5AC_FHEAP_IBLOCK, iblock->addr, addr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move indirect block") + /* Let the metadata cache know the block moved */ + if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_IBLOCK, iblock->addr, iblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move indirect block") - /* Update the internal address for the block */ - iblock->addr = addr; + /* Update the internal address for the block */ + iblock->addr = iblock_addr; - /* Check for root indirect block */ - if(NULL == iblock->parent) { - /* Update information about indirect block's location */ - hdr->man_dtable.table_addr = addr; + /* Check for root indirect block */ + if(NULL == iblock->parent) { + /* Update information about indirect block's location */ + hdr->man_dtable.table_addr = iblock_addr; - /* Mark that heap header was modified */ - if(H5HF_hdr_dirty(hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end if */ - else { - H5HF_indirect_t *par_iblock; /* Parent indirect block */ - unsigned par_entry; /* Entry in parent indirect block */ + /* Mark that heap header was modified */ + if(H5HF_hdr_dirty(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") + } /* end if */ + else { + H5HF_indirect_t *par_iblock; /* Parent indirect block */ + unsigned par_entry; /* Entry in parent indirect block */ - /* Get parent information */ - par_iblock = iblock->parent; - par_entry = iblock->par_entry; + /* Get parent information */ + par_iblock = iblock->parent; + par_entry = iblock->par_entry; - /* Update information about indirect block's location */ - par_iblock->ents[par_entry].addr = addr; + /* Update information about indirect block's location */ + par_iblock->ents[par_entry].addr = iblock_addr; - /* Mark that parent was modified */ - if(H5HF_iblock_dirty(par_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end if */ + /* Mark that parent was modified */ + if(H5HF_iblock_dirty(par_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") } /* end if */ - /* Indirect block must be in 'normal' file space now */ - HDassert(!H5F_IS_TMP_ADDR(f, addr)); - - /* Write the indirect block */ - if(H5F_block_write(f, H5FD_MEM_FHEAP_IBLOCK, addr, iblock->size, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFLUSH, FAIL, "unable to save fractal heap indirect block to disk") - - /* Reset dirty flags */ - iblock->cache_info.is_dirty = FALSE; + *new_addr = iblock_addr; + *flags = H5C__SERIALIZE_MOVED_FLAG; } /* end if */ - - if(destroy) - if(H5HF_cache_iblock_dest(f, iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block") + else + *flags = 0; done: - /* Release resources */ - if(wb && H5WB_unwrap(wb) < 0) - HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer") - FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_cache_iblock_flush() */ +} /* end H5HF__cache_iblock_pre_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_dest + * Function: H5HF__cache_iblock_serialize * - * Purpose: Destroys a fractal heap indirect block in memory. + * Purpose: Given a pointer to an iblock, and a pointer to a buffer of + * the appropriate size, write the contents of the iblock to the + * buffer in format appropriate for writing to disk. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 6 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_iblock_dest(H5F_t *f, H5HF_indirect_t *iblock) +static herr_t +H5HF__cache_iblock_serialize(const H5F_t *f, void *_image, size_t len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_hdr_t *hdr; /* Shared fractal heap information */ + H5HF_indirect_t *iblock = (H5HF_indirect_t *)_thing; /* Indirect block info */ + uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ +#ifndef NDEBUG + unsigned nchildren = 0; /* Track # of children */ + size_t max_child = 0; /* Track max. child entry used */ +#endif /* NDEBUG */ + uint32_t metadata_chksum; /* Computed metadata checksum value */ + size_t u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* - * Check arguments. - */ + /* Sanity checks */ + HDassert(f); + HDassert(image); HDassert(iblock); - HDassert(iblock->rc == 0); - HDassert(iblock->hdr); + HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK); + HDassert(iblock->cache_info.size == iblock->size); + HDassert(len == iblock->size); - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!iblock->cache_info.free_file_space_on_destroy || H5F_addr_defined(iblock->cache_info.addr)); - - /* Check for freeing file space for indirect block */ - if(iblock->cache_info.free_file_space_on_destroy) { - /* Check if the indirect block is NOT currently allocated in temp. file space */ - /* (temp. file space does not need to be freed) */ - if(!H5F_IS_TMP_ADDR(f, iblock->cache_info.addr)) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_IBLOCK, H5AC_dxpl_id, iblock->cache_info.addr, (hsize_t)iblock->size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap indirect block") - } /* end if */ - } /* end if */ + /* Indirect block must be in 'normal' file space */ + HDassert(!H5F_IS_TMP_ADDR(f, iblock->addr)); + HDassert(H5F_addr_eq(iblock->addr, iblock->cache_info.addr)); - /* Destroy fractal heap indirect block */ - if(H5HF_man_iblock_dest(iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block") + /* Get the pointer to the shared heap header */ + hdr = iblock->hdr; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_iblock_dest() */ + /* Set the shared heap header's file context for this operation */ + hdr->f = f; - -/*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_clear - * - * Purpose: Mark a fractal heap indirect block in memory as non-dirty. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 6 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5HF_cache_iblock_clear(H5F_t *f, H5HF_indirect_t *iblock, hbool_t destroy) -{ - herr_t ret_value = SUCCEED; /* Return value */ + /* Magic number */ + HDmemcpy(image, H5HF_IBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - FUNC_ENTER_NOAPI_NOINIT + /* Version # */ + *image++ = H5HF_IBLOCK_VERSION; - /* - * Check arguments. - */ - HDassert(iblock); + /* Address of heap header for heap which owns this block */ + H5F_addr_encode(f, &image, hdr->heap_addr); - /* Reset the dirty flag. */ - iblock->cache_info.is_dirty = FALSE; + /* Offset of block in heap */ + UINT64ENCODE_VAR(image, iblock->block_off, hdr->heap_off_size); - if(destroy) - if(H5HF_cache_iblock_dest(f, iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block") + /* Encode indirect block-specific fields */ + for(u = 0; u < (iblock->nrows * hdr->man_dtable.cparam.width); u++) { + /* Encode child block address */ + H5F_addr_encode(f, &image, iblock->ents[u].addr); + + /* Check for heap with I/O filters */ + if(hdr->filter_len > 0) { + /* Sanity check */ + HDassert(iblock->filt_ents); + + /* Encode extra information for direct blocks */ + if(u < (hdr->man_dtable.max_direct_rows * hdr->man_dtable.cparam.width)) { + /* Sanity check */ + /* (either both the address & size are defined or both are + * not defined) + */ + HDassert((H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size) + || (!H5F_addr_defined(iblock->ents[u].addr) && iblock->filt_ents[u].size == 0)); + + /* Size of filtered direct block */ + H5F_ENCODE_LENGTH(f, image, iblock->filt_ents[u].size); + + /* I/O filter mask for filtered direct block */ + UINT32ENCODE(image, iblock->filt_ents[u].filter_mask); + } /* end if */ + } /* end if */ + +#ifndef NDEBUG + /* Count child blocks */ + if(H5F_addr_defined(iblock->ents[u].addr)) { + nchildren++; + if(u > max_child) + max_child = u; + } /* end if */ +#endif /* NDEBUG */ + } /* end for */ + + /* Compute checksum */ + metadata_chksum = H5_checksum_metadata((uint8_t *)_image, (size_t)(image - (uint8_t *)_image), 0); + + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + + /* Sanity checks */ + HDassert((size_t)(image - (uint8_t *)_image) == iblock->size); +#ifndef NDEBUG + HDassert(nchildren == iblock->nchildren); + HDassert(max_child == iblock->max_child); +#endif /* NDEBUG */ -done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_iblock_clear() */ +} /* end H5HF__cache_iblock_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_notify + * Function: H5HF__cache_iblock_notify * - * Purpose: Setup / takedown flush dependencies as indirect blocks + * Purpose: This function is used to create and destroy flush dependency + * relationships between iblocks and their parents as indirect blocks * are loaded / inserted and evicted from the metadata cache. * - * Return: Non-negative on success/Negative on failure + * In general, the parent will be another iblock, but it may be the + * header if the iblock in question is the root iblock. + * + * Return: Success: SUCCEED + * Failure: FAIL * * Programmer: John Mainzer - * 5/17/14 + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock) +static herr_t +H5HF__cache_iblock_notify(H5C_notify_action_t action, void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_indirect_t *iblock = (H5HF_indirect_t *)_thing; /* Indirect block info */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ HDassert(iblock); HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK); HDassert(iblock->hdr); if(action == H5AC_NOTIFY_ACTION_BEFORE_EVICT) @@ -1316,6 +1534,7 @@ H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock) switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: if(iblock->parent) { /* this is a child iblock */ /* create flush dependency with parent iblock */ if(H5AC_create_flush_dependency(iblock->parent, iblock) < 0) @@ -1328,6 +1547,10 @@ H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock) } /* end else */ break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: if(iblock->fd_parent) { /* this is a child iblock */ /* destroy flush dependency with parent iblock */ @@ -1348,95 +1571,324 @@ H5HF_cache_iblock_notify(H5C_notify_action_t action, H5HF_indirect_t *iblock) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_iblock_notify() */ +} /* end H5HF__cache_iblock_notify() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_iblock_size + * Function: H5HF__cache_iblock_free_icr * - * Purpose: Compute the size in bytes of a fractal heap indirect block - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Unlink the supplied instance of H5HF_indirect_t from the + * fractal heap and free its memory. * - * Return: Non-negative on success/Negative on failure + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Mar 6 2006 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_iblock_size(const H5F_t H5_ATTR_UNUSED *f, const H5HF_indirect_t *iblock, size_t *size_ptr) +static herr_t +H5HF__cache_iblock_free_icr(void *thing) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + H5HF_indirect_t *iblock = (H5HF_indirect_t *)thing; /* Fractal heap indirect block to free */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Check arguments */ + FUNC_ENTER_STATIC + + /* Sanity checks */ HDassert(iblock); - HDassert(size_ptr); + HDassert(iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(iblock->cache_info.type == H5AC_FHEAP_IBLOCK); + HDassert(iblock->rc == 0); + HDassert(iblock->hdr); - /* Set size value */ - *size_ptr = iblock->size; + /* Destroy fractal heap indirect block */ + if(H5HF_man_iblock_dest(iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap indirect block") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_iblock_free_icr() */ +/*********************************************************/ +/* metadata cache callback definitions for direct blocks */ +/*********************************************************/ + + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_dblock_get_load_size() + * + * Purpose: Determine the size of the direct block on disk image, and + * return it in *image_len. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_dblock_get_load_size(const void *_image, void *_udata, size_t *image_len, size_t *actual_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + const H5HF_dblock_cache_ud_t *udata = (const H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */ + const H5HF_parent_t *par_info; /* Pointer to parent information */ + const H5HF_hdr_t *hdr; /* Shared fractal heap information */ + size_t compressed_size=0; + hbool_t compressed; + + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(udata); + HDassert(image_len); + par_info = (const H5HF_parent_t *)(&(udata->par_info)); + HDassert(par_info); + hdr = par_info->hdr; + HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + + if(hdr->filter_len > 0) { + + /* Check for root direct block */ + if(par_info->iblock == NULL) { + /* filtered direct block */ + compressed_size = hdr->pline_root_direct_size; + } /* end if */ + else { + /* filtered direct block */ + compressed_size = par_info->iblock->filt_ents[par_info->entry].size; + } /* end else */ + } + + if(image == NULL) { + + /* depend on I/O filters on this heap */ + *image_len = (hdr->filter_len > 0) ? compressed_size:udata->dblock_size; + + } else { + + HDassert(actual_len); + HDassert(*actual_len == *image_len); + HDassert(compressed_ptr); + HDassert(compressed_image_len_ptr); + + if(hdr->filter_len > 0) { + HDassert(*image_len == compressed_size); + compressed = TRUE; + } else { + HDassert(*image_len == udata->dblock_size); + compressed = FALSE; + compressed_size = 0; + } + + /* decompressed size */ + *actual_len = udata->dblock_size; + *compressed_ptr = compressed; + *compressed_image_len_ptr = compressed_size; + } + FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5HF_cache_iblock_size() */ +} /* end H5HF__cache_dblock_get_load_size() */ /*********************************************************/ /* metadata cache callback definitions for direct blocks */ /*********************************************************/ +/*------------------------------------------------------------------------- + * Function: H5HF__cache_dblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF__cache_dblock_verify_chksum(const void *_image, size_t len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5HF_dblock_cache_ud_t *udata = (H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */ + void *read_buf = NULL; /* Pointer to buffer to read in */ + size_t read_size; /* Size of filtered direct block to read */ + H5HF_hdr_t *hdr; /* Shared fractal heap information */ + H5HF_parent_t *par_info; /* Pointer to parent information */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t t_chksum; /* Computed metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + size_t chk_size; /* The size for validating checksum */ + uint8_t *chk_p; /* Pointer to the area for validating checksum */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(image); + HDassert(udata); + par_info = (H5HF_parent_t *)(&(udata->par_info)); + HDassert(par_info); + hdr = par_info->hdr; + HDassert(hdr); + + /* len is the decompressed size of the direct block */ + + udata->decompressed = FALSE; + udata->dblk = NULL; + + /* Get out if data block is not checksummed */ + if(!(hdr->checksum_dblocks)) + HGOTO_DONE(TRUE); + + /* Determine the size on disk */ + if(hdr->filter_len > 0) { + + /* Check for root direct block */ + if(par_info->iblock == NULL) { + /* Set up parameters to read filtered direct block */ + read_size = hdr->pline_root_direct_size; + } /* end if */ + else { + /* Set up parameters to read filtered direct block */ + read_size = par_info->iblock->filt_ents[par_info->entry].size; + } /* end else */ + } else + read_size = len; + + /* Allocate buffer to perform I/O filtering on and copy image into + * it. Must do this as H5Z_pipeline() may re-sized the buffer + * provided to it. + */ + if(NULL == (read_buf = H5MM_malloc(read_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer") + + if(hdr->filter_len > 0) { + size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */ + unsigned filter_mask; /* Excluded filters for direct block */ + H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ + + /* Push direct block data through I/O filter pipeline */ + nbytes = read_size; + filter_mask = udata->filter_mask; + HDmemcpy(read_buf, image, read_size); + + if(H5Z_pipeline(&(hdr->pline), H5Z_FLAG_REVERSE, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &read_size, &read_buf) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFILTER, FAIL, "output pipeline failed") + + /* Sanity check */ + HDassert(nbytes == len); + udata->decompressed = TRUE; + + } else + HDmemcpy(read_buf, image, read_size); + + /* Decode checksum */ + chk_size = (size_t)(H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr) - H5HF_SIZEOF_CHKSUM); + chk_p = (uint8_t *)read_buf + chk_size; + + /* Metadata checksum */ + UINT32DECODE(chk_p, stored_chksum); + + chk_p -= H5HF_SIZEOF_CHKSUM; + + /* Reset checksum field, for computing the checksum */ + /* (Casting away const OK - QAK) */ + HDmemset(chk_p, 0, (size_t)H5HF_SIZEOF_CHKSUM); + + /* Compute checksum on entire direct block */ + computed_chksum = H5_checksum_metadata(read_buf, len, 0); + + /* Restore the checksum */ + UINT32ENCODE(chk_p, stored_chksum) + + /* Verify checksum */ + if(stored_chksum != computed_chksum) + HGOTO_DONE(FALSE); + + /* Save the decompressed data to be used later in deserialize callback */ + if(hdr->filter_len > 0) { + + HDassert(udata->decompressed); + HDassert(len == udata->dblock_size); + /* Allocate block buffer */ + if(NULL == (udata->dblk = H5FL_BLK_MALLOC(direct_block, (size_t)len))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Copy un-filtered data into block's buffer */ + HDmemcpy(udata->dblk, read_buf, len); + } + +done: + /* Release the read buffer */ + if(read_buf) + H5MM_xfree(read_buf); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_dblock_verify_chksum() */ + /*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_load + * Function: H5HF__cache_dblock_deserialize * - * Purpose: Loads a fractal heap direct block from the disk. + * Purpose: Given a buffer containing the on disk image of a direct + * block, allocate an instance of H5HF_direct_t, load the data + * in the buffer into this new instance, and return a pointer to + * it. * - * Return: Success: Pointer to a new fractal heap direct block + * As best I can tell, the size of the direct block image is fully + * know before the image is loaded, so this function should succeed + * unless the image is corrupt or memory allocation fails. * + * Return: Success: Pointer to in core representation * Failure: NULL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 27 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static H5HF_direct_t * -H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) +static void * +H5HF__cache_dblock_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { H5HF_hdr_t *hdr; /* Shared fractal heap information */ H5HF_dblock_cache_ud_t *udata = (H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */ H5HF_parent_t *par_info; /* Pointer to parent information */ - H5HF_direct_t *dblock = NULL; /* Direct block info */ - const uint8_t *p; /* Pointer into raw data buffer */ + H5HF_direct_t *dblock = NULL; /* Direct block info */ + const uint8_t *image; /* Pointer into raw data buffer */ haddr_t heap_addr; /* Address of heap header in the file */ - uint32_t computed_chksum; /* Computed metadata checksum value */ - uint32_t stored_chksum; /* Metadata checksum value */ - unsigned tries, max_tries; /* The # of read attempts */ - unsigned retries; /* The # of retries */ - size_t chk_size; /* The size for validating checksum */ - uint8_t *chk_p; /* Pointer to the area for validating checksum */ - size_t read_size; /* Size of filtered direct block to read */ - H5HF_direct_t *ret_value; /* Return value */ + void * ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata != NULL); - HDassert(udata->f != NULL); - HDassert(udata->dblock_size > 0); + /* Sanity checks */ + HDassert(_image); + HDassert(udata); + par_info = (H5HF_parent_t *)(&(udata->par_info)); + HDassert(par_info); + hdr = par_info->hdr; + HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); + HDassert(dirty); /* Allocate space for the fractal heap direct block */ if(NULL == (dblock = H5FL_MALLOC(H5HF_direct_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") HDmemset(&dblock->cache_info, 0, sizeof(H5AC_info_t)); - /* Get the pointer to the shared heap header */ - par_info = (H5HF_parent_t *)(&(udata->par_info)); - hdr = par_info->hdr; - /* Set the shared heap header's file context for this operation */ hdr->f = udata->f; @@ -1449,46 +1901,54 @@ H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) dblock->size = udata->dblock_size; dblock->file_size = 0; - /* Allocate block buffer */ -/* XXX: Change to using free-list factories */ - if(NULL == (dblock->blk = H5FL_BLK_MALLOC(direct_block, (size_t)dblock->size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - /* Determine read_size for filter buffer */ + /* initialize fields used in serialization */ + dblock->write_buf = NULL; + dblock->write_size = 0; + + if(udata->dblk && udata->decompressed) { + /* direct block is already decompressed in verify_chksum callback */ + HDassert(hdr->filter_len > 0); + HDassert(len == dblock->size); + dblock->blk = udata->dblk; + } else { + HDassert(udata->dblk == NULL); + HDassert(!udata->decompressed); + + /* Allocate block buffer */ + /* XXX: Change to using free-list factories */ + if(NULL == (dblock->blk = H5FL_BLK_MALLOC(direct_block, (size_t)dblock->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + } + + /* Check for I/O filters on this heap */ if(hdr->filter_len > 0) { - /* Check for root direct block */ - if(par_info->iblock == NULL) { - /* Sanity check */ - HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr)); - - /* Set up parameters to read filtered direct block */ - read_size = hdr->pline_root_direct_size; - } /* end if */ - else { - /* Sanity check */ - HDassert(H5F_addr_eq(par_info->iblock->ents[par_info->entry].addr, addr)); - - /* Set up parameters to read filtered direct block */ - read_size = par_info->iblock->filt_ents[par_info->entry].size; - } /* end else */ - } /* end if */ - - tries = max_tries = H5F_GET_READ_ATTEMPTS(f); - do { - /* Check for I/O filters on this heap */ - if(hdr->filter_len > 0) { - H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ - size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */ - void *read_buf; /* Pointer to buffer to read in */ - unsigned filter_mask; /* Excluded filters for direct block */ + H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ + size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */ + void *read_buf; /* Pointer to buffer to read in */ + size_t read_size; /* Size of filtered direct block to read */ + unsigned filter_mask; /* Excluded filters for direct block */ + + if(!udata->decompressed) { + HDassert(udata->dblk == NULL); + + /* Check for root direct block */ + if(par_info->iblock == NULL) { + /* Set up parameters to read filtered direct block */ + read_size = hdr->pline_root_direct_size; + } /* end if */ + else { + /* Set up parameters to read filtered direct block */ + read_size = par_info->iblock->filt_ents[par_info->entry].size; + } /* end else */ + HDassert(len == read_size); - /* Allocate buffer to perform I/O filtering on */ + /* Allocate buffer to perform I/O filtering on and copy image into + * it. Must do this as H5Z_pipeline() may re-sized the buffer + * provided to it. + */ if(NULL == (read_buf = H5MM_malloc(read_size))) HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "memory allocation failed for pipeline buffer") - - /* Read filtered direct block from disk */ - if(H5F_block_read(f, H5FD_MEM_FHEAP_DBLOCK, addr, read_size, dxpl_id, read_buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "can't read fractal heap direct block") + HDmemcpy(read_buf, _image, len); /* Push direct block data through I/O filter pipeline */ nbytes = read_size; @@ -1504,62 +1964,28 @@ H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) /* Release the read buffer */ H5MM_xfree(read_buf); - } /* end if */ - else { - /* Read direct block from disk */ - if(H5F_block_read(f, H5FD_MEM_FHEAP_DBLOCK, addr, dblock->size, dxpl_id, dblock->blk) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "can't read fractal heap direct block") - } /* end else */ - - /* Get out if data block is not checksummed */ - if(!(hdr->checksum_dblocks)) - break; - - /* Decode checksum on direct block, if requested */ - chk_size = (size_t)(H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr) - H5HF_SIZEOF_CHKSUM); - chk_p = dblock->blk + chk_size; - - /* Metadata checksum */ - UINT32DECODE(chk_p, stored_chksum); - - chk_p -= H5HF_SIZEOF_CHKSUM; - - /* Reset checksum field, for computing the checksum */ - /* (Casting away const OK - QAK) */ - HDmemset(chk_p, 0, (size_t)H5HF_SIZEOF_CHKSUM); - - /* Compute checksum on entire direct block */ - computed_chksum = H5_checksum_metadata(dblock->blk, dblock->size, 0); - - /* Verify checksum */ - if(stored_chksum == computed_chksum) - break; - - } while (--tries); - - if(tries == 0) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "incorrect metadata checksum after all tries (%u) for fractal heap direct block", max_tries) - - /* Calculate and track the # of retries */ - retries = max_tries - tries; - if(retries) /* Does not track 0 retry */ - if(H5F_track_metadata_read_retries(f, H5AC_FHEAP_DBLOCK_ID, retries) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "cannot track read retries = %u ", retries) + } + } /* end if */ + else { + /* copy image to dblock->blk */ + HDassert(dblock->size == len); + HDmemcpy(dblock->blk, _image, dblock->size); + } /* end else */ /* Start decoding direct block */ - p = dblock->blk; + image = dblock->blk; /* Magic number */ - if(HDmemcmp(p, H5HF_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "wrong fractal heap direct block signature") - p += H5_SIZEOF_MAGIC; + if(HDmemcmp(image, H5HF_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "wrong fractal heap direct block signature") + image += H5_SIZEOF_MAGIC; /* Version */ - if(*p++ != H5HF_DBLOCK_VERSION) + if(*image++ != H5HF_DBLOCK_VERSION) HGOTO_ERROR(H5E_HEAP, H5E_VERSION, NULL, "wrong fractal heap direct block version") /* Address of heap that owns this block (just for file integrity checks) */ - H5F_addr_decode(udata->f, &p, &heap_addr); + H5F_addr_decode(udata->f, &image, &heap_addr); if(H5F_addr_ne(heap_addr, hdr->heap_addr)) HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "incorrect heap header address for direct block") @@ -1574,17 +2000,24 @@ H5HF_cache_dblock_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_udata) } /* end if */ /* Offset of heap within the heap's address space */ - UINT64DECODE_VAR(p, dblock->block_off, hdr->heap_off_size); + UINT64DECODE_VAR(image, dblock->block_off, hdr->heap_off_size); + + /* Decode checksum on direct block, if requested */ + if(hdr->checksum_dblocks) { + uint32_t stored_chksum; /* Metadata checksum value */ - /* Advance past optional checksum on direct block, it was verified earlier */ - if(hdr->checksum_dblocks) - p += H5HF_SIZEOF_CHKSUM; + /* checksum verification already done in verify_chksum cb */ + + /* Metadata checksum */ + UINT32DECODE(image, stored_chksum); + + } /* end if */ /* Sanity check */ - HDassert((size_t)(p - dblock->blk) == (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)); + HDassert((size_t)(image - dblock->blk) == (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)); /* Set return value */ - ret_value = dblock; + ret_value = (void *)dblock; done: if(!ret_value && dblock) @@ -1592,402 +2025,646 @@ done: HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy fractal heap direct block") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_dblock_load() */ +} /* end H5HF__cache_dblock_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_flush + * Function: H5HF__cache_dblock_image_len * - * Purpose: Flushes a dirty fractal heap direct block to disk. + * Purpose: Report the actual size of the direct block image on disk. + * Note that this value will probably be incorrect if compression + * is enabled and the entry is dirty. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 27 2006 + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_dblock_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HF_direct_t *dblock, unsigned H5_ATTR_UNUSED * flags_ptr) +static herr_t +H5HF__cache_dblock_image_len(const void *_thing, size_t *image_len, hbool_t *compressed_ptr, size_t *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const H5HF_direct_t *dblock = (const H5HF_direct_t *)_thing; /* Direct block info */ + const H5HF_indirect_t *par_iblock; /* Parent iblock */ + const H5HF_hdr_t *hdr; /* Shared fractal heap information */ + hbool_t compressed; + size_t size; + size_t compressed_size; - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); + /* Sanity checks */ HDassert(dblock); + HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK); + HDassert(image_len); + HDassert(compressed_ptr); + HDassert(compressed_image_len_ptr); - if(dblock->cache_info.is_dirty) { - H5HF_hdr_t *hdr; /* Shared fractal heap information */ - hbool_t at_tmp_addr = H5F_IS_TMP_ADDR(f, addr); /* Flag to indicate direct block is at temporary address */ - void *write_buf; /* Pointer to buffer to write out */ - size_t write_size; /* Size of buffer to write out */ - uint8_t *p; /* Pointer into raw data buffer */ + /* Set up convenience variables */ + hdr = dblock->hdr; + par_iblock = dblock->parent; - /* Get the pointer to the shared heap header */ - hdr = dblock->hdr; + /* Check for I/O filters on this heap */ + if(hdr->filter_len > 0) { - /* Set the shared heap header's file context for this operation */ - hdr->f = f; + /* Filters are enabled, so set compressed to TRUE, and set + * size equal to the uncompressed size of the direct block. + * If the data is available, set compressed_size to the compressed + * size of the direct block -- otherwise set it equal to the + * uncompressed size. + * + * We have three possible scenarios here. + * + * First, the block may never have been flushed. In this + * case, both dblock->file_size and the size stored in the + * parent (either the header or the parent iblock) will all + * be zero. In this case, return the uncompressed size + * stored in dblock->size as the compressed size. + * + * Second, the block may have just been serialized, in which + * case, dblock->file_size should be zero, and the correct + * on disk size should be stored in the parent (again, either + * the header or the parent iblock as case may be). + * + * Third, we may be in the process of discarding this + * dblock without writing it. In this case, dblock->file_size + * should be non-zero and have the correct size. Note that + * in this case, the direct block will have been detached, + * and thus looking up the parent will likely return incorrect + * data. + */ + size = dblock->size; + compressed = TRUE; + compressed_size = dblock->size; /* will overwrite if compressed + * size is available. + */ + + if(dblock->file_size != 0) + compressed_size = dblock->file_size; + else { + if(par_iblock) { + unsigned par_entry; /* Entry in parent indirect block */ - HDassert(dblock->blk); - p = dblock->blk; + par_entry = dblock->par_entry; + compressed_size = par_iblock->filt_ents[par_entry].size; - /* Magic number */ - HDmemcpy(p, H5HF_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); - p += H5_SIZEOF_MAGIC; + } /* end if */ + else { + compressed_size = hdr->pline_root_direct_size; + } - /* Version # */ - *p++ = H5HF_DBLOCK_VERSION; + if(compressed_size == 0) + compressed_size = dblock->size; - /* Address of heap header for heap which owns this block */ - H5F_addr_encode(f, &p, hdr->heap_addr); + } /* end else */ + } /* end if */ + else { + size = dblock->size; + compressed = FALSE; + compressed_size = 0; /* a convenient, invalid value */ + } - /* Offset of block in heap */ - UINT64ENCODE_VAR(p, dblock->block_off, hdr->heap_off_size); + HDassert(size > 0); - /* Metadata checksum */ - if(hdr->checksum_dblocks) { - uint32_t metadata_chksum; /* Computed metadata checksum value */ + *image_len = size; + *compressed_ptr = compressed; + *compressed_image_len_ptr = compressed_size; - /* Clear the checksum field, to compute the checksum */ - HDmemset(p, 0, (size_t)H5HF_SIZEOF_CHKSUM); + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HF__cache_dblock_image_len() */ - /* Compute checksum on entire direct block */ - metadata_chksum = H5_checksum_metadata(dblock->blk, dblock->size, 0); + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_dblock_pre_serialize + * + * Purpose: In principle, the purpose of this function is to determine + * the size and location of the disk image of the target direct + * block. In this case, the uncompressed size of the block is + * fixed, but sined the H5C__CLASS_COMPRESSED_FLAG is set, + * we may need to compute and report the compressed size. + * + * This is a bit sticky in the case of a direct block when I/O + * filters are enabled, as the size of the compressed version + * of the on disk image is not known until the direct block has + * been run through the filters. Further, the location of the + * on disk image may change if the compressed size of the image + * changes as well. + * + * To complicate matters further, the direct block may have been + * initially allocated in temporary (AKA imaginary) file space. + * In this case, we must relocate the direct block's on disk + * image to real file space regardless of whether it has changed + * size. + * + * One simplifying factor is the direct block's "blk" field, + * which contains a pointer to a buffer which (with the exception + * of a small header) contains the on disk image in uncompressed + * form. + * + * To square this particular circle, this function does + * everything the serialize function usually does, with the + * exception of copying the image into the image buffer provided + * to the serialize function by the metadata cache. The data to + * copy is provided to the serialize function in a buffer pointed + * to by the write_buf field. + * + * If I/O filters are enabled, on exit, + * H5HF__cache_dblock_pre_serialize() sets the write_buf field to + * point to a buffer containing the filtered image of the direct + * block. The serialize function should free this block, and set + * the write_buf field to NULL after copying it into the image + * buffer provided by the metadata cache. + * + * If I/O filters are not enabled, this function prepares + * the buffer pointed to by the blk field for copying to the + * image buffer provided by the metadata cache, and sets the + * write_buf field equal to the blk field. In this case, the + * serialize function should simply set the write_buf field to + * NULL after copying the direct block image into the image + * buffer. + * + * In both of the above cases, the length of the buffer pointed + * to by write_buf is provided in the write_len field. This + * field must contain 0 on entry to this function, and should + * be set back to 0 at the end of the serialize function. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_dblock_pre_serialize(const H5F_t *f, hid_t dxpl_id, void *_thing, + haddr_t addr, size_t len, size_t compressed_len, haddr_t *new_addr, + size_t H5_ATTR_UNUSED *new_len, size_t *new_compressed_len, unsigned *flags) +{ + hbool_t at_tmp_addr; /* Flag to indicate direct block is */ + /* at temporary address */ + haddr_t dblock_addr; + H5HF_hdr_t *hdr; /* Shared fractal heap information */ + H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Direct block info */ + H5HF_indirect_t *par_iblock; /* Parent indirect block */ + unsigned par_entry; /* Entry in parent indirect block */ + void *write_buf; /* Pointer to buffer to write out */ + size_t write_size; /* Size of buffer to write out */ + uint8_t *image; /* Pointer into raw data buffer */ + unsigned dblock_flags = 0; + herr_t ret_value = SUCCEED; /* Return value */ - /* Metadata checksum */ - UINT32ENCODE(p, metadata_chksum); - } /* end if */ + FUNC_ENTER_STATIC - /* Sanity check */ - HDassert((size_t)(p - dblock->blk) == (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)); + /* Sanity checks */ + HDassert(f); + HDassert(dblock); + HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK); + HDassert(dblock->write_buf == NULL); + HDassert(dblock->write_size == 0); + HDassert(dblock->cache_info.size == len); + HDassert(H5F_addr_defined(addr)); + HDassert(len == dblock->size); + HDassert(new_addr); + HDassert(new_compressed_len); + HDassert(flags); - /* Check for I/O filters on this heap */ - if(hdr->filter_len > 0) { - H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ - size_t nbytes; /* Number of bytes used */ - unsigned filter_mask = 0; /* Filter mask for block */ + /* Set up local variables */ + hdr = dblock->hdr; + dblock_addr = addr; /* will update dblock_addr if we move the block */ - /* Allocate buffer to perform I/O filtering on */ - write_size = dblock->size; - if(NULL == (write_buf = H5MM_malloc(write_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer") - HDmemcpy(write_buf, dblock->blk, write_size); + /* dblock->size must match dblock->cache_info.size */ + HDassert(dblock->cache_info.size == dblock->size); - /* Push direct block data through I/O filter pipeline */ - nbytes = write_size; - if(H5Z_pipeline(&(hdr->pline), 0, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &write_size, &write_buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "output pipeline failed") + /* Set the shared heap header's file context for this operation */ + hdr->f = (H5F_t *)f; - /* Use the compressed number of bytes as the size to write */ - write_size = nbytes; + HDassert(hdr); + HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); - /* Check for root direct block */ - if(dblock->parent == NULL) { - hbool_t hdr_changed = FALSE; /* Whether the header information changed */ + if(dblock->parent) { + /* this is the common case, in which the direct block is the child + * of an indirect block. Set up the convenience variables we will + * need if the address and/or compressed size of the on disk image + * of the direct block changes, and do some sanity checking in + * passing. + */ + par_iblock = dblock->parent; + par_entry = dblock->par_entry; - /* Sanity check */ - HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr)); - HDassert(hdr->pline_root_direct_size > 0); + HDassert(par_iblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(par_iblock->cache_info.type == H5AC_FHEAP_IBLOCK); + HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)); + } /* end if */ + else { + /* the direct block is a root direct block -- just set par_iblock + * to NULL, as the field will not be used. + */ + par_iblock = NULL; + } /* end else */ - /* Check if the filter mask changed */ - if(hdr->pline_root_direct_filter_mask != filter_mask) { - hdr->pline_root_direct_filter_mask = filter_mask; - hdr_changed = TRUE; - } /* end if */ + at_tmp_addr = H5F_IS_TMP_ADDR(f, addr); - /* Check if we need to re-size the block on disk */ - if(hdr->pline_root_direct_size != write_size || at_tmp_addr) { - /* Check if the direct block is NOT currently allocated in temp. file space */ - /* (temp. file space does not need to be freed) */ - if(!at_tmp_addr) { - /* Release direct block's current disk space */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, addr, (hsize_t)hdr->pline_root_direct_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") - } /* end if */ + /* Begin by preping the direct block to be written to disk. Do + * this by writing the correct magic number, the dblock version, + * the address of the header, the offset of the block in the heap, + * and the checksum at the beginning of the block. + */ - /* Allocate space for the compressed direct block */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") + HDassert(dblock->blk); + image = dblock->blk; - /* Let the metadata cache know, if the block moved */ - if(!H5F_addr_eq(hdr->man_dtable.table_addr, addr)) - if(H5AC_move_entry(f, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, addr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") + /* Magic number */ + HDmemcpy(image, H5HF_DBLOCK_MAGIC, (size_t)H5_SIZEOF_MAGIC); + image += H5_SIZEOF_MAGIC; - /* Update information about compressed direct block's location & size */ - hdr->man_dtable.table_addr = addr; - hdr->pline_root_direct_size = write_size; + /* Version # */ + *image++ = H5HF_DBLOCK_VERSION; - /* Note that heap header was modified */ - hdr_changed = TRUE; - } /* end if */ + /* Address of heap header for heap which owns this block */ + H5F_addr_encode(f, &image, hdr->heap_addr); - /* Check if heap header was modified */ - if(hdr_changed) - if(H5HF_hdr_dirty(hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end if */ - else { - hbool_t par_changed = FALSE; /* Whether the parent's information changed */ - H5HF_indirect_t *par_iblock; /* Parent indirect block */ - unsigned par_entry; /* Entry in parent indirect block */ + /* Offset of block in heap */ + UINT64ENCODE_VAR(image, dblock->block_off, hdr->heap_off_size); - /* Get parent information */ - par_iblock = dblock->parent; - par_entry = dblock->par_entry; + /* Metadata checksum */ + if(hdr->checksum_dblocks) { + uint32_t metadata_chksum; /* Computed metadata checksum value */ - /* Sanity check */ - HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)); - HDassert(par_iblock->filt_ents[par_entry].size > 0); + /* Clear the checksum field, to compute the checksum */ + HDmemset(image, 0, (size_t)H5HF_SIZEOF_CHKSUM); - /* Check if the filter mask changed */ - if(par_iblock->filt_ents[par_entry].filter_mask != filter_mask) { - par_iblock->filt_ents[par_entry].filter_mask = filter_mask; - par_changed = TRUE; - } /* end if */ + /* Compute checksum on entire direct block */ + metadata_chksum = H5_checksum_metadata(dblock->blk, dblock->size, 0); - /* Check if we need to re-size the block on disk */ - if(par_iblock->filt_ents[par_entry].size != write_size || at_tmp_addr) { - /* Check if the direct block is NOT currently allocated in temp. file space */ - /* (temp. file space does not need to be freed) */ - if(!at_tmp_addr) { - /* Release direct block's current disk space */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, addr, (hsize_t)par_iblock->filt_ents[par_entry].size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") - } /* end if */ + /* Metadata checksum */ + UINT32ENCODE(image, metadata_chksum); + } /* end if */ - /* Allocate space for the compressed direct block */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") + /* at this point, dblock->blk should point to an uncompressed image of + * the direct block. If I/O filters are not enabled, this image should + * be ready to hand off to the metadata cache. + */ - /* Let the metadata cache know, if the block moved */ - if(!H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)) - if(H5AC_move_entry(f, H5AC_FHEAP_DBLOCK, par_iblock->ents[par_entry].addr, addr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") + /* Sanity check */ + HDassert((size_t)(image - dblock->blk) == (size_t)H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)); - /* Update information about compressed direct block's location & size */ - par_iblock->ents[par_entry].addr = addr; - par_iblock->filt_ents[par_entry].size = write_size; + /* If I/O filters are enabled on this heap, we must run the direct block + * image through the filters to obtain the image that we will hand off + * to the metadata cache. + */ - /* Note that parent was modified */ - par_changed = TRUE; - } /* end if */ + /* Check for I/O filters on this heap */ + if(hdr->filter_len > 0) { + H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ + size_t nbytes; /* Number of bytes used */ + unsigned filter_mask = 0; /* Filter mask for block */ + + /* Allocate buffer to perform I/O filtering on */ + write_size = dblock->size; + + if(NULL == (write_buf = H5MM_malloc(write_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer") + HDmemcpy(write_buf, dblock->blk, write_size); + + /* Push direct block data through I/O filter pipeline */ + nbytes = write_size; + if(H5Z_pipeline(&(hdr->pline), 0, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &write_size, &write_buf) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "output pipeline failed") + + /* Use the compressed number of bytes as the size to write */ + write_size = nbytes; + + /* If the size and/or location of the on disk image of the + * direct block changes, we must touch up its parent to reflect + * these changes. Do this differently depending on whether the + * direct block's parent is an indirect block or (rarely) the + * fractal heap header. In this case, the direct block is known + * as a root direct block. + */ - /* Check if parent was modified */ - if(par_changed) - if(H5HF_iblock_dirty(par_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end else */ - } /* end if */ - else { - write_buf = dblock->blk; - write_size = dblock->size; + /* Check for root direct block */ + if(dblock->parent == NULL) { + hbool_t hdr_changed = FALSE; /* Whether the header info changed */ - /* Check for needing to re-allocate direct block from 'temp.' to 'normal' file space */ - if(at_tmp_addr) { - /* Check for root direct block */ - if(NULL == dblock->parent) { - /* Sanity check */ - HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr)); + /* Sanity check */ + HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr)); + HDassert(hdr->pline_root_direct_size > 0); - /* Allocate 'normal' space for the direct block */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") + /* Check if the filter mask changed */ + if(hdr->pline_root_direct_filter_mask != filter_mask) { + hdr->pline_root_direct_filter_mask = filter_mask; + hdr_changed = TRUE; + } /* end if */ + + /* verify that the cache's last record of the compressed + * size matches the heap's last record. This value will + * likely change shortly. + */ + HDassert(compressed_len == hdr->pline_root_direct_size); + + /* Check if we need to re-size the block on disk */ + if(hdr->pline_root_direct_size != write_size || at_tmp_addr) { + /* Check if the direct block is NOT currently allocated + * in temp. file space + * + * (temp. file space does not need to be freed) + */ + if(!at_tmp_addr) { + /* Release direct block's current disk space */ + if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, addr, (hsize_t)hdr->pline_root_direct_size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") + } /* end if */ - /* Sanity check */ - HDassert(!H5F_addr_eq(hdr->man_dtable.table_addr, addr)); + /* Allocate space for the compressed direct block */ + if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") - /* Let the metadata cache know the block moved */ - if(H5AC_move_entry(f, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, addr) < 0) + /* Let the metadata cache know, if the block moved */ + if(!H5F_addr_eq(hdr->man_dtable.table_addr, dblock_addr)) + if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, dblock_addr) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") - /* Update information about direct block's location */ - hdr->man_dtable.table_addr = addr; + /* Update information about compressed direct block's + * location & size + */ + HDassert(hdr->man_dtable.table_addr == addr); + HDassert(hdr->pline_root_direct_size == compressed_len); + hdr->man_dtable.table_addr = dblock_addr; + hdr->pline_root_direct_size = write_size; - /* Mark that heap header was modified */ - if(H5HF_hdr_dirty(hdr) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end if */ - else { - H5HF_indirect_t *par_iblock; /* Parent indirect block */ - unsigned par_entry; /* Entry in parent indirect block */ + /* Note that heap header was modified */ + hdr_changed = TRUE; + } /* end if */ + + /* Check if heap header was modified */ + if(hdr_changed) + if(H5HF_hdr_dirty(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") + } /* end if */ + else { /* the direct block's parent is an indirect block */ + hbool_t par_changed = FALSE; /* Whether the parent's infochanged */ + + /* Sanity check */ + HDassert(par_iblock); + HDassert(par_iblock->filt_ents[par_entry].size > 0); - /* Get parent information */ - par_iblock = dblock->parent; - par_entry = dblock->par_entry; + /* Check if the filter mask changed */ + if(par_iblock->filt_ents[par_entry].filter_mask != filter_mask) { + par_iblock->filt_ents[par_entry].filter_mask = filter_mask; + par_changed = TRUE; + } /* end if */ - /* Sanity check */ - HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)); + /* verify that the cache's last record of the compressed + * size matches the heap's last record. This value will + * likely change shortly. + */ + HDassert(compressed_len == par_iblock->filt_ents[par_entry].size); - /* Allocate 'normal' space for the direct block */ - if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") + /* Check if we need to re-size the block on disk */ + if(par_iblock->filt_ents[par_entry].size != write_size || at_tmp_addr) { + /* Check if the direct block is NOT currently allocated + * in temp. file space + * + * (temp. file space does not need to be freed) + */ + if(!at_tmp_addr) { + /* Release direct block's current disk space */ + if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, addr, (hsize_t)par_iblock->filt_ents[par_entry].size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") + } /* end if */ - /* Sanity check */ - HDassert(!H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)); + /* Allocate space for the compressed direct block */ + if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") - /* Let the metadata cache know the block moved */ - if(H5AC_move_entry(f, H5AC_FHEAP_DBLOCK, par_iblock->ents[par_entry].addr, addr) < 0) + /* Let the metadata cache know, if the block moved */ + if(!H5F_addr_eq(par_iblock->ents[par_entry].addr, dblock_addr)) + if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_DBLOCK, par_iblock->ents[par_entry].addr, dblock_addr) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") - /* Update information about direct block's location */ - par_iblock->ents[par_entry].addr = addr; + /* Update information about compressed direct block's + * location & size + */ + HDassert(par_iblock->ents[par_entry].addr == addr); + HDassert(par_iblock->filt_ents[par_entry].size == compressed_len); + par_iblock->ents[par_entry].addr = dblock_addr; + par_iblock->filt_ents[par_entry].size = write_size; - /* Mark that parent was modified */ - if(H5HF_iblock_dirty(par_iblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") - } /* end else */ + /* Note that parent was modified */ + par_changed = TRUE; } /* end if */ + + /* Check if parent was modified */ + if(par_changed) + if(H5HF_iblock_dirty(par_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") } /* end else */ + } /* end if */ + else { + /* I/O filters are not enabled -- thus all we need to do is check to + * see if the direct block is in temporary (AKA imaginary) file + * space, and move it to real file space if it is. + * + * As in the I/O filters case above, we will have to touch up the + * direct blocks parent if the direct block is relocated. + * + * Recall that temporary file space need not be freed, which + * simplifies matters slightly. + */ + write_buf = dblock->blk; + write_size = dblock->size; - /* Direct block must be in 'normal' file space now */ - HDassert(!H5F_IS_TMP_ADDR(f, addr)); + /* Check to see if we must re-allocate direct block from 'temp.' + * to 'normal' file space + */ + if(at_tmp_addr) { + /* Check for root direct block */ + if(NULL == dblock->parent) { + /* Sanity check */ + HDassert(H5F_addr_eq(hdr->man_dtable.table_addr, addr)); - /* Write the direct block */ - if(H5F_block_write(f, H5FD_MEM_FHEAP_DBLOCK, addr, write_size, dxpl_id, write_buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFLUSH, FAIL, "unable to save fractal heap direct block to disk") + /* Allocate 'normal' space for the direct block */ + if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") - /* Release the write buffer, if it was allocated */ - if(write_buf != dblock->blk) - H5MM_xfree(write_buf); + /* Sanity check */ + HDassert(!H5F_addr_eq(hdr->man_dtable.table_addr, dblock_addr)); - dblock->cache_info.is_dirty = FALSE; - } /* end if */ + /* Let the metadata cache know the block moved */ + if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_DBLOCK, hdr->man_dtable.table_addr, dblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") - if(destroy) - if(H5HF_cache_dblock_dest(f, dblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block") + /* Update information about direct block's location */ + hdr->man_dtable.table_addr = dblock_addr; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5HF_cache_dblock_flush() */ + /* Mark that heap header was modified */ + if(H5HF_hdr_dirty(hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") + } /* end if */ + else { /* the direct block's parent is an indirect block */ + /* Sanity check */ + HDassert(par_iblock); + HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, addr)); - -/*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_dest - * - * Purpose: Destroys a fractal heap direct block in memory. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 27 2006 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5HF_cache_dblock_dest(H5F_t *f, H5HF_direct_t *dblock) -{ - herr_t ret_value = SUCCEED; /* Return value */ + /* Allocate 'normal' space for the direct block */ + if(HADDR_UNDEF == (dblock_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FHEAP_DBLOCK, dxpl_id, (hsize_t)write_size))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "file allocation failed for fractal heap direct block") - FUNC_ENTER_NOAPI_NOINIT + /* Sanity check */ + HDassert(!H5F_addr_eq(par_iblock->ents[par_entry].addr, dblock_addr)); - /* - * Check arguments. - */ - HDassert(dblock); + /* Let the metadata cache know the block moved */ + if(H5AC_move_entry((H5F_t *)f, H5AC_FHEAP_DBLOCK, par_iblock->ents[par_entry].addr, dblock_addr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move direct block") - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!dblock->cache_info.free_file_space_on_destroy || H5F_addr_defined(dblock->cache_info.addr)); + /* Update information about direct block's location */ + par_iblock->ents[par_entry].addr = dblock_addr; - /* Check for freeing file space for direct block */ - if(dblock->cache_info.free_file_space_on_destroy) { - /* Sanity check */ - HDassert(dblock->file_size > 0); - - /* Check if the direct block is NOT currently allocated in temp. file space */ - /* (temp. file space does not need to be freed) */ - if(!H5F_IS_TMP_ADDR(f, dblock->cache_info.addr)) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, H5AC_dxpl_id, dblock->cache_info.addr, dblock->file_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block") + /* Mark that parent was modified */ + if(H5HF_iblock_dirty(par_iblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty") + } /* end else */ } /* end if */ + } /* end else */ + + /* At this point, write_buf points to a buffer containing the image + * of the direct block that is ready to copy into the image buffer, + * and write_size contains the length of this buffer. + * + * Also, if image size or address has changed, the direct block's + * parent has been modified to reflect the change. + * + * Now, make note of the pointer and length of the above buffer for + * use by the serialize function. + */ + dblock->write_buf = (uint8_t *)write_buf; + dblock->write_size = write_size; + + /* finally, pass data back to the metadata cache as appropriate */ + if(!H5F_addr_eq(addr, dblock_addr)) { + dblock_flags |= H5C__SERIALIZE_MOVED_FLAG; + *new_addr = dblock_addr; } /* end if */ - /* Destroy fractal heap direct block */ - if(H5HF_man_dblock_dest(dblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block") + if((hdr->filter_len > 0) && (compressed_len != write_size)) { + dblock_flags |= H5C__SERIALIZE_COMPRESSED_FLAG; + *new_compressed_len = write_size; + } /* end if */ + + *flags = dblock_flags; + + /* final sanity check */ + HDassert(dblock->write_buf); + HDassert(dblock->write_size > 0); done: + /* discard the write buf if we have an error */ + if(write_buf && (write_buf != dblock->blk) && (dblock->write_buf == NULL)) + H5MM_xfree(write_buf); + FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_dblock_dest() */ +} /* end H5HF__cache_dblock_pre_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_clear + * Function: H5HF__cache_dblock_serialize * - * Purpose: Mark a fractal heap direct block in memory as non-dirty. + * Purpose: In principle, this function is supposed to construct the on + * disk image of the direct block, and place that image in the + * image buffer provided by the metadata cache. * - * Return: Non-negative on success/Negative on failure + * However, since there are cases in which the pre_serialize + * function has to construct the on disk image to determine its size + * and address, this function simply copies the image prepared by + * the pre-serialize function into the supplied image buffer, and + * discards a buffer if necessary. * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 27 2006 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_dblock_clear(H5F_t *f, H5HF_direct_t *dblock, hbool_t destroy) +static herr_t +H5HF__cache_dblock_serialize(const H5F_t *f, void *image, size_t len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Direct block info */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* - * Check arguments. - */ + /* Sanity checks */ + HDassert(f); + HDassert(image); + HDassert(len > 0); HDassert(dblock); + HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK); + HDassert((dblock->blk != dblock->write_buf) || (dblock->cache_info.size == dblock->size)); + HDassert(dblock->write_buf); + HDassert(dblock->write_size > 0); + HDassert((dblock->blk != dblock->write_buf) || (dblock->write_size == dblock->size)); + HDassert(dblock->write_size == len); + + /* Copy the image from *(dblock->write_buf) to *image */ + HDmemcpy(image, dblock->write_buf, dblock->write_size); + + /* Free *(dblock->write_buf) if it was allocated by the + * pre-serialize function + */ + if(dblock->write_buf != dblock->blk) + H5MM_xfree(dblock->write_buf); - /* Reset the dirty flag. */ - dblock->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5HF_cache_dblock_dest(f, dblock) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block") + /* Reset the write_buf and write_size fields */ + dblock->write_buf = NULL; + dblock->write_size = 0; -done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_dblock_clear() */ +} /* end H5HF__cache_dblock_serialize() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_notify + * Function: H5HF__cache_dblock_notify * * Purpose: Setup / takedown flush dependencies as direct blocks * are loaded / inserted and evicted from the metadata cache. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * * Programmer: John Mainzer - * 5/17/14 + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_dblock_notify(H5C_notify_action_t action, H5HF_direct_t *dblock) +static herr_t +H5HF__cache_dblock_notify(H5C_notify_action_t action, void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Fractal heap direct block */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* - * Check arguments. - */ + /* Sanity checks */ HDassert(dblock); HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK); HDassert(dblock->hdr); HDassert((dblock->fd_parent) || ((dblock->hdr->man_dtable.curr_root_rows == 0) && (dblock->block_off == (hsize_t)0))); switch(action) { case H5AC_NOTIFY_ACTION_AFTER_INSERT: + case H5AC_NOTIFY_ACTION_AFTER_LOAD: HDassert(dblock->parent == dblock->fd_parent); if(dblock->parent) { /* this is a leaf dblock */ /* create flush dependency with parent iblock */ @@ -2001,6 +2678,10 @@ H5HF_cache_dblock_notify(H5C_notify_action_t action, H5HF_direct_t *dblock) } /* end else */ break; + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + /* do nothing */ + break; + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: HDassert((dblock->parent == dblock->fd_parent) || ((NULL == dblock->parent) && (dblock->fd_parent))); @@ -2023,39 +2704,47 @@ H5HF_cache_dblock_notify(H5C_notify_action_t action, H5HF_direct_t *dblock) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HF_cache_dblock_notify() */ +} /* end H5HF__cache_dblock_notify() */ /*------------------------------------------------------------------------- - * Function: H5HF_cache_dblock_size + * Function: H5HF__cache_dblock_free_icr * - * Purpose: Compute the size in bytes of a fractal heap direct block - * on disk, and return it in *size_ptr. On failure, - * the value of *size_ptr is undefined. + * Purpose: Free the in core memory allocated to the supplied direct + * block. * - * Return: Non-negative on success/Negative on failure + * Note: The metadata cache sets the object's cache_info.magic to + * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr + * callback (checked in assert). * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Feb 24 2006 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 6/21/14 * *------------------------------------------------------------------------- */ -static herr_t -H5HF_cache_dblock_size(const H5F_t H5_ATTR_UNUSED *f, const H5HF_direct_t *dblock, size_t *size_ptr) +static herr_t +H5HF__cache_dblock_free_icr(void *_thing) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + H5HF_direct_t *dblock = (H5HF_direct_t *)_thing; /* Fractal heap direct block */ + herr_t ret_value = SUCCEED; /* Return value */ - /* check arguments */ - HDassert(dblock); - HDassert(size_ptr); + FUNC_ENTER_STATIC - /* Set size value */ - *size_ptr = dblock->size; + /* Sanity checks */ + HDassert(dblock); + HDassert(dblock->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(dblock->cache_info.type == H5AC_FHEAP_DBLOCK); - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5HF_cache_dblock_size() */ + /* Destroy fractal heap direct block */ + if(H5HF_man_dblock_dest(dblock) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block") +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_dblock_free_icr() */ /*------------------------------------------------------------------------ @@ -2181,7 +2870,7 @@ H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, hid_t dxpl_id, * in this case, since we know that the entry is in cache, * we can pass NULL udata. */ - if(NULL == (root_iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5AC_READ))) + if(NULL == (root_iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5C__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.") unprotect_root_iblock = TRUE; } /* end if */ @@ -2242,7 +2931,7 @@ H5HF__cache_verify_hdr_descendants_clean(H5F_t *f, hid_t dxpl_id, * in this case, since we know that the entry is in cache, * we can pass NULL udata. */ - if(NULL == (iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5AC_READ))) + if(NULL == (iblock = (H5HF_indirect_t *)H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, root_iblock_addr, NULL, H5C__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.") unprotect_root_iblock = TRUE; HDassert(iblock == root_iblock); @@ -2632,7 +3321,7 @@ H5HF__cache_verify_descendant_iblocks_clean(H5F_t *f, hid_t dxpl_id, /* in this case, since we know that the */ /* entry is in cache, we can pass NULL udata */ - if(NULL == (child_iblock = (H5HF_indirect_t *) H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, child_iblock_addr, NULL, H5AC_READ))) + if(NULL == (child_iblock = (H5HF_indirect_t *) H5AC_protect(f, dxpl_id, H5AC_FHEAP_IBLOCK, child_iblock_addr, NULL, H5C__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "H5AC_protect() faild.") unprotect_child_iblock = TRUE; } /* end if */ |