diff options
Diffstat (limited to 'src/H5HGcache.c')
-rw-r--r-- | src/H5HGcache.c | 498 |
1 files changed, 260 insertions, 238 deletions
diff --git a/src/H5HGcache.c b/src/H5HGcache.c index aac73ed..5c6bee1 100644 --- a/src/H5HGcache.c +++ b/src/H5HGcache.c @@ -62,12 +62,14 @@ /********************/ /* Metadata cache callbacks */ -static H5HG_heap_t *H5HG_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata); -static herr_t H5HG_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, - H5HG_heap_t *heap, unsigned H5_ATTR_UNUSED * flags_ptr); -static herr_t H5HG_dest(H5F_t *f, H5HG_heap_t *heap); -static herr_t H5HG_clear(H5F_t *f, H5HG_heap_t *heap, hbool_t destroy); -static herr_t H5HG_size(const H5F_t *f, const H5HG_heap_t *heap, size_t *size_ptr); +static herr_t H5HG__cache_heap_get_load_size(const void *udata, size_t *image_len); +static void *H5HG__cache_heap_deserialize(const void *image, size_t len, + void *udata, hbool_t *dirty); +static herr_t H5HG__cache_heap_image_len(const void *thing, size_t *image_len, + hbool_t *compressed_ptr, size_t *compressed_image_len_ptr); +static herr_t H5HG__cache_heap_serialize(const H5F_t *f, void *image, + size_t len, void *thing); +static herr_t H5HG__cache_heap_free_icr(void *thing); /*********************/ @@ -76,13 +78,19 @@ static herr_t H5HG_size(const H5F_t *f, const H5HG_heap_t *heap, size_t *size_pt /* H5HG inherits cache-like properties from H5AC */ const H5AC_class_t H5AC_GHEAP[1] = {{ - H5AC_GHEAP_ID, - (H5AC_load_func_t)H5HG_load, - (H5AC_flush_func_t)H5HG_flush, - (H5AC_dest_func_t)H5HG_dest, - (H5AC_clear_func_t)H5HG_clear, - (H5AC_notify_func_t)NULL, - (H5AC_size_func_t)H5HG_size, + H5AC_GHEAP_ID, /* Metadata client ID */ + "global heap", /* Metadata client name (for debugging) */ + H5FD_MEM_GHEAP, /* File space memory type for client */ + H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ + H5HG__cache_heap_get_load_size, /* 'get_load_size' callback */ + H5HG__cache_heap_deserialize, /* 'deserialize' callback */ + H5HG__cache_heap_image_len, /* 'image_len' callback */ + NULL, /* 'pre_serialize' callback */ + H5HG__cache_heap_serialize, /* 'serialize' callback */ + NULL, /* 'notify' callback */ + H5HG__cache_heap_free_icr, /* 'free_icr' callback */ + NULL, /* 'clear' callback */ + NULL, /* 'fsf_size' callback */ }}; @@ -98,162 +106,204 @@ const H5AC_class_t H5AC_GHEAP[1] = {{ /*------------------------------------------------------------------------- - * Function: H5HG_load + * Function: H5HG__cache_heap_get_load_size() * - * Purpose: Loads a global heap collection from disk. + * Purpose: Return the initial speculative read size to the metadata + * cache. This size will be used in the initial attempt to read + * the global heap. If this read is too small, the cache will + * try again with the correct value obtained from + * H5HG__cache_heap_image_len(). * - * Return: Success: Ptr to a global heap collection. + * Return: Success: SUCCEED + * Failure: FAIL * - * Failure: NULL + * Programmer: John Mainzer + * 7/27/14 * - * Programmer: Robb Matzke - * Friday, March 27, 1998 + *------------------------------------------------------------------------- + */ +static herr_t +H5HG__cache_heap_get_load_size(const void H5_ATTR_UNUSED *_udata, size_t *image_len) +{ + FUNC_ENTER_STATIC_NOERR + + HDassert(image_len); + + *image_len = (size_t)H5HG_MINSIZE; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HG__cache_heap_get_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5HG__cache_heap_deserialize + * + * Purpose: Given a buffer containing the on disk image of the global + * heap, deserialize it, load its contents into a newly allocated + * instance of H5HG_heap_t, and return a pointer to the new instance. + * + * Note that this heap client uses speculative reads. If the supplied + * buffer is too small, we simply make note of the correct size, and + * wait for the metadata cache to try again. + * + * Return: Success: Pointer to in core representation + * Failure: NULL + * + * Programmer: John Mainzer + * 7/27/14 * *------------------------------------------------------------------------- */ -static H5HG_heap_t * -H5HG_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *udata) +static void * +H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, + hbool_t H5_ATTR_UNUSED *dirty) { - H5HG_heap_t *heap = NULL; - uint8_t *p; - size_t nalloc, need; - size_t max_idx = 0; /* The maximum index seen */ - H5HG_heap_t *ret_value = NULL; /* Return value */ + H5F_t *f = (H5F_t *)_udata; /* File pointer -- obtained from user data */ + H5HG_heap_t *heap = NULL; /* New global heap */ + uint8_t *image; /* Pointer to image to decode */ + void *ret_value; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC - /* check arguments */ + /* Sanity checks */ + HDassert(_image); + HDassert(len >= (size_t)H5HG_MINSIZE); HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(udata); + HDassert(dirty); - /* Read the initial 4k page */ + /* Allocate a new global heap */ if(NULL == (heap = H5FL_CALLOC(H5HG_heap_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") heap->shared = H5F_SHARED(f); - if(NULL == (heap->chunk = H5FL_BLK_MALLOC(gheap_chunk, (size_t)H5HG_MINSIZE))) + if(NULL == (heap->chunk = H5FL_BLK_MALLOC(gheap_chunk, len))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - if(H5F_block_read(f, H5FD_MEM_GHEAP, addr, (size_t)H5HG_MINSIZE, dxpl_id, heap->chunk) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "unable to read global heap collection") - p = heap->chunk; + + /* copy the image buffer into the newly allocate chunk */ + HDmemcpy(heap->chunk, _image, len); + + image = heap->chunk; /* Magic number */ - if(HDmemcmp(p, H5HG_MAGIC, (size_t)H5_SIZEOF_MAGIC)) - HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "bad global heap collection signature") - p += H5_SIZEOF_MAGIC; + if(HDmemcmp(image, H5HG_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "bad global heap collection signature") + image += H5_SIZEOF_MAGIC; /* Version */ - if(H5HG_VERSION != *p++) - HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "wrong version number in global heap") + if(H5HG_VERSION != *image++) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "wrong version number in global heap") /* Reserved */ - p += 3; + image += 3; /* Size */ - H5F_DECODE_LENGTH(f, p, heap->size); + H5F_DECODE_LENGTH(f, image, heap->size); HDassert(heap->size >= H5HG_MINSIZE); - - /* - * If we didn't read enough in the first try, then read the rest of the - * collection now. - */ - if(heap->size > H5HG_MINSIZE) { - haddr_t next_addr = addr + (hsize_t)H5HG_MINSIZE; - - if(NULL == (heap->chunk = H5FL_BLK_REALLOC(gheap_chunk, heap->chunk, heap->size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - if(H5F_block_read(f, H5FD_MEM_GHEAP, next_addr, (heap->size - H5HG_MINSIZE), dxpl_id, heap->chunk + H5HG_MINSIZE) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "unable to read global heap collection") - } /* end if */ - - /* Decode each object */ - p = heap->chunk + H5HG_SIZEOF_HDR(f); - nalloc = H5HG_NOBJS(f, heap->size); - - /* Calloc the obj array because the file format spec makes no guarantee - * about the order of the objects, and unused slots must be set to zero. - */ - if(NULL == (heap->obj = H5FL_SEQ_CALLOC(H5HG_obj_t, nalloc))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - heap->nalloc = nalloc; - while(p < (heap->chunk + heap->size)) { - if((p + H5HG_SIZEOF_OBJHDR(f)) > (heap->chunk + heap->size)) { - /* - * The last bit of space is too tiny for an object header, so we - * assume that it's free space. - */ - HDassert(NULL == heap->obj[0].begin); - heap->obj[0].size = (size_t)(((const uint8_t *)heap->chunk + heap->size) - p); - heap->obj[0].begin = p; - p += heap->obj[0].size; - } /* end if */ - else { - unsigned idx; - uint8_t *begin = p; - - UINT16DECODE(p, idx); - - /* Check if we need more room to store heap objects */ - if(idx >= heap->nalloc) { - size_t new_alloc; /* New allocation number */ - H5HG_obj_t *new_obj; /* New array of object descriptions */ - - /* Determine the new number of objects to index */ - new_alloc = MAX(heap->nalloc * 2, (idx + 1)); - HDassert(idx < new_alloc); - - /* Reallocate array of objects */ - if(NULL == (new_obj = H5FL_SEQ_REALLOC(H5HG_obj_t, heap->obj, new_alloc))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - /* Clear newly allocated space */ - HDmemset(&new_obj[heap->nalloc], 0, (new_alloc - heap->nalloc) * sizeof(heap->obj[0])); - - /* Update heap information */ - heap->nalloc = new_alloc; - heap->obj = new_obj; - HDassert(heap->nalloc > heap->nused); + HDassert((len == H5HG_MINSIZE) /* first try */ || + ((len == heap->size) && (len > H5HG_MINSIZE))); /* second try */ + + if(len == heap->size) { /* proceed with the deserialize */ + size_t max_idx = 0; + size_t nalloc; + + /* Decode each object */ + image = heap->chunk + H5HG_SIZEOF_HDR(f); + nalloc = H5HG_NOBJS(f, heap->size); + + /* Calloc the obj array because the file format spec makes no guarantee + * about the order of the objects, and unused slots must be set to zero. + */ + if(NULL == (heap->obj = H5FL_SEQ_CALLOC(H5HG_obj_t, nalloc))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + heap->nalloc = nalloc; + + while(image < (heap->chunk + heap->size)) { + if((image + H5HG_SIZEOF_OBJHDR(f)) > (heap->chunk + heap->size)) { + /* + * The last bit of space is too tiny for an object header, so + * we assume that it's free space. + */ + HDassert(NULL == heap->obj[0].begin); + heap->obj[0].size = (size_t)(((const uint8_t *)heap->chunk + heap->size) - image); + heap->obj[0].begin = image; + image += heap->obj[0].size; } /* end if */ - - UINT16DECODE(p, heap->obj[idx].nrefs); - p += 4; /*reserved*/ - H5F_DECODE_LENGTH(f, p, heap->obj[idx].size); - heap->obj[idx].begin = begin; - - /* - * The total storage size includes the size of the object header - * and is zero padded so the next object header is properly - * aligned. The entire obj array was calloc'ed, so no need to zero - * the space here. The last bit of space is the free space object - * whose size is never padded and already includes the object - * header. - */ - if(idx > 0) { - need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(heap->obj[idx].size); - - if(idx > max_idx) - max_idx = idx; - } /* end if */ - else - need = heap->obj[idx].size; - p = begin + need; - } /* end else */ - } /* end while */ - HDassert(p == heap->chunk + heap->size); - HDassert(H5HG_ISALIGNED(heap->obj[0].size)); - - /* Set the next index value to use */ - if(max_idx > 0) - heap->nused = max_idx + 1; + else { + size_t need; + unsigned idx; + uint8_t *begin = image; + + UINT16DECODE(image, idx); + + /* Check if we need more room to store heap objects */ + if(idx >= heap->nalloc) { + size_t new_alloc; /* New allocation number */ + H5HG_obj_t *new_obj; /* New array of object descriptions */ + + /* Determine the new number of objects to index */ + new_alloc = MAX(heap->nalloc * 2, (idx + 1)); + HDassert(idx < new_alloc); + + /* Reallocate array of objects */ + if(NULL == (new_obj = H5FL_SEQ_REALLOC(H5HG_obj_t, heap->obj, new_alloc))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Clear newly allocated space */ + HDmemset(&new_obj[heap->nalloc], 0, (new_alloc - heap->nalloc) * sizeof(heap->obj[0])); + + /* Update heap information */ + heap->nalloc = new_alloc; + heap->obj = new_obj; + HDassert(heap->nalloc > heap->nused); + } /* end if */ + + UINT16DECODE(image, heap->obj[idx].nrefs); + image += 4; /*reserved*/ + H5F_DECODE_LENGTH(f, image, heap->obj[idx].size); + heap->obj[idx].begin = begin; + + /* + * The total storage size includes the size of the object + * header and is zero padded so the next object header is + * properly aligned. The entire obj array was calloc'ed, + * so no need to zero the space here. The last bit of space + * is the free space object whose size is never padded and + * already includes the object header. + */ + if(idx > 0) { + need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(heap->obj[idx].size); + if(idx > max_idx) + max_idx = idx; + } /* end if */ + else + need = heap->obj[idx].size; + + image = begin + need; + } /* end else */ + } /* end while */ + + HDassert(image == heap->chunk + heap->size); + HDassert(H5HG_ISALIGNED(heap->obj[0].size)); + + /* Set the next index value to use */ + if(max_idx > 0) + heap->nused = max_idx + 1; + else + heap->nused = 1; + + HDassert(max_idx < heap->nused); + + /* Add the new heap to the CWFS list for the file */ + if(H5F_cwfs_add(f, heap) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "unable to add global heap collection to file's CWFS") + } /* end if ( len == heap->size ) */ else - heap->nused = 1; - - HDassert(max_idx < heap->nused); - - /* Add the new heap to the CWFS list for the file */ - if(H5F_cwfs_add(f, heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "unable to add global heap collection to file's CWFS") + /* if len is less than heap size, then the initial speculative + * read was too small. In this case we return without reporting + * failure. H5C_load_entry() will call H5HG__cache_heap_image_len() + * to get the actual read size, and then repeat the read with the + * correct size, and call this function a second time. + */ + HDassert(len < heap->size); ret_value = heap; @@ -263,154 +313,126 @@ done: HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy global heap collection") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HG_load() */ +} /* end H5HG__cache_heap_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5HG_flush + * Function: H5HG__cache_heap_image_len * - * Purpose: Flushes a global heap collection from memory to disk if it's - * dirty. Optionally deletes teh heap from memory. + * Purpose: Return the on disk image size of the global heap to the + * metadata cache via the image_len. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Robb Matzke - * Friday, March 27, 1998 + * Programmer: John Mainzer + * 7/27/14 * *------------------------------------------------------------------------- */ static herr_t -H5HG_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HG_heap_t *heap, unsigned H5_ATTR_UNUSED * flags_ptr) +H5HG__cache_heap_image_len(const void *_thing, size_t *image_len, + hbool_t H5_ATTR_UNUSED *compressed_ptr, size_t H5_ATTR_UNUSED *compressed_image_len_ptr) { - herr_t ret_value = SUCCEED; /* Return value */ + const H5HG_heap_t *heap = (const H5HG_heap_t *)_thing; - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* Check arguments */ - HDassert(f); - HDassert(H5F_addr_defined(addr)); - HDassert(H5F_addr_eq(addr, heap->addr)); + /* Sanity checks */ HDassert(heap); + HDassert(heap->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(heap->cache_info.type == H5AC_GHEAP); + HDassert(heap->size >= H5HG_MINSIZE); + HDassert(image_len); - if(heap->cache_info.is_dirty) { - if(H5F_block_write(f, H5FD_MEM_GHEAP, addr, heap->size, dxpl_id, heap->chunk) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "unable to write global heap collection to file") - heap->cache_info.is_dirty = FALSE; - } /* end if */ + *image_len = heap->size; - if(destroy) - if(H5HG_dest(f, heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy global heap collection") + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HG__cache_heap_image_len() */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5HG_flush() */ +/**************************************/ +/* no H5HG_cache_heap_pre_serialize() */ +/**************************************/ /*------------------------------------------------------------------------- - * Function: H5HG_dest + * Function: H5HG__cache_heap_serialize + * + * Purpose: Given an appropriately sized buffer and an instance of + * H5HG_heap_t, serialize the global heap for writing to file, + * and copy the serialized verion into the buffer. * - * Purpose: Destroys a global heap collection in memory * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Quincey Koziol - * Wednesday, January 15, 2003 + * Programmer: John Mainzer + * 7/27/14 * *------------------------------------------------------------------------- */ static herr_t -H5HG_dest(H5F_t *f, H5HG_heap_t *heap) +H5HG__cache_heap_serialize(const H5F_t *f, void *image, size_t len, + void *_thing) { - herr_t ret_value = SUCCEED; /* Return value */ + H5HG_heap_t *heap = (H5HG_heap_t *)_thing; - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR - /* Check arguments */ + HDassert(f); + HDassert(image); HDassert(heap); + HDassert(heap->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(heap->cache_info.type == H5AC_GHEAP); + HDassert(heap->size == len); + HDassert(heap->chunk); - /* Verify that node is clean */ - HDassert(heap->cache_info.is_dirty == FALSE); + /* copy the image into the buffer */ + HDmemcpy(image, heap->chunk, len); - /* If we're going to free the space on disk, the address must be valid */ - HDassert(!heap->cache_info.free_file_space_on_destroy || H5F_addr_defined(heap->cache_info.addr)); - - /* Check for freeing file space for globalheap */ - if(heap->cache_info.free_file_space_on_destroy) { - /* Release the space on disk */ - /* (XXX: Nasty usage of internal DXPL value! -QAK) */ - if(H5MF_xfree(f, H5FD_MEM_GHEAP, H5AC_dxpl_id, heap->cache_info.addr, (hsize_t)heap->size) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free global heap") - } /* end if */ - - /* Destroy global heap collection */ - if(H5HG_free(heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy global heap collection") + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HG__cache_heap_serialize() */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5HG_dest() */ +/****************************************/ +/* no H5HG_cache_heap_notify() function */ +/****************************************/ /*------------------------------------------------------------------------- - * Function: H5HG_clear + * Function: H5HG__cache_heap_free_icr * - * Purpose: Mark a global heap in memory as non-dirty. + * Purpose: Free the in memory representation of the supplied global heap. * - * 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 - * Thursday, March 20, 2003 + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: John Mainzer + * 7/27/14 * *------------------------------------------------------------------------- */ static herr_t -H5HG_clear(H5F_t *f, H5HG_heap_t *heap, hbool_t destroy) +H5HG__cache_heap_free_icr(void *_thing) { + H5HG_heap_t *heap = (H5HG_heap_t *)_thing; herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Sanity checks */ HDassert(heap); + HDassert(heap->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC); + HDassert(heap->cache_info.type == H5AC_GHEAP); - /* Mark heap as clean */ - heap->cache_info.is_dirty = FALSE; - - if(destroy) - if(H5HG_dest(f, heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy global heap collection") + /* Destroy global heap collection */ + if(H5HG_free(heap) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy global heap collection") done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5HG_clear() */ - - -/*------------------------------------------------------------------------- - * Function: H5HG_size - * - * Purpose: Compute the size in bytes of the specified instance of - * H5HG_heap_t on disk, and return it in *len_ptr. On failure, - * the value of *len_ptr is undefined. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: John Mainzer - * 5/13/04 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5HG_size(const H5F_t H5_ATTR_UNUSED *f, const H5HG_heap_t *heap, size_t *size_ptr) -{ - FUNC_ENTER_NOAPI_NOINIT_NOERR - - /* Check arguments */ - HDassert(heap); - HDassert(size_ptr); - - *size_ptr = heap->size; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5HG_size() */ +} /* end H5HG__cache_heap_free_icr() */ |