diff options
Diffstat (limited to 'src/H5HLcache.c')
-rw-r--r-- | src/H5HLcache.c | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/src/H5HLcache.c b/src/H5HLcache.c new file mode 100644 index 0000000..449e166 --- /dev/null +++ b/src/H5HLcache.c @@ -0,0 +1,478 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5HLcache.c + * Feb 5 2008 + * Quincey Koziol <koziol@hdfgroup.org> + * + * Purpose: Implement local heap metadata cache methods. + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5HL_PACKAGE /* Suppress error about including H5HLpkg */ + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5HLpkg.h" /* Local Heaps */ +#include "H5MFprivate.h" /* File memory management */ + + +/****************/ +/* Local Macros */ +/****************/ + +#define H5HL_VERSION 0 /* Local heap collection version */ +#define H5HL_FREE_NULL 1 /* End of free list on disk */ + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Package Typedefs */ +/********************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + +/* Local encode/decode routines */ +static herr_t H5HL_serialize(H5F_t *f, H5HL_t *heap, uint8_t *buf); + +/* Metadata cache callbacks */ +static H5HL_t *H5HL_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *udata1, + void *udata2); +static herr_t H5HL_flush(H5F_t *f, hid_t dxpl_id, hbool_t dest, haddr_t addr, H5HL_t *heap, unsigned UNUSED * flags_ptr); +static herr_t H5HL_clear(H5F_t *f, H5HL_t *heap, hbool_t destroy); + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* H5HL inherits cache-like properties from H5AC */ +const H5AC_class_t H5AC_LHEAP[1] = {{ + H5AC_LHEAP_ID, + (H5AC_load_func_t)H5HL_load, + (H5AC_flush_func_t)H5HL_flush, + (H5AC_dest_func_t)H5HL_dest, + (H5AC_clear_func_t)H5HL_clear, + (H5AC_size_func_t)H5HL_size, +}}; + + +/*------------------------------------------------------------------------- + * Function: H5HL_serialize + * + * Purpose: Serialize the heap. This function will eliminate free + * blocks at the tail of the heap and also split the block + * if it needs to be split for the file. This is so that we + * can serialize it correctly. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Bill Wendling + * wendling@ncsa.uiuc.edu + * Sept. 16, 2003 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HL_serialize(H5F_t *f, H5HL_t *heap, uint8_t *buf) +{ + H5HL_free_t *fl; + uint8_t *p; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HL_serialize) + + /* check args */ + assert(buf); + assert(heap); + + /* serialize the header */ + p = buf; + fl = heap->freelist; + HDmemcpy(p, H5HL_MAGIC, (size_t)H5_SIZEOF_MAGIC); + p += H5_SIZEOF_MAGIC; + *p++ = H5HL_VERSION; + *p++ = 0; /*reserved*/ + *p++ = 0; /*reserved*/ + *p++ = 0; /*reserved*/ + H5F_ENCODE_LENGTH(f, p, heap->heap_alloc); + H5F_ENCODE_LENGTH(f, p, fl ? fl->offset : H5HL_FREE_NULL); + H5F_addr_encode(f, &p, heap->addr); + + /* serialize the free list */ + for (; fl; fl = fl->next) { + assert (fl->offset == H5HL_ALIGN (fl->offset)); + p = heap->chunk + H5HL_SIZEOF_HDR(f) + fl->offset; + + if (fl->next) { + H5F_ENCODE_LENGTH(f, p, fl->next->offset); + } else { + H5F_ENCODE_LENGTH(f, p, H5HL_FREE_NULL); + } + + H5F_ENCODE_LENGTH(f, p, fl->size); + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL_serialize() */ + + +/*------------------------------------------------------------------------- + * Function: H5HL_load + * + * Purpose: Loads a heap from disk. + * + * Return: Success: Ptr to a local heap memory data structure. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 17 1997 + * + *------------------------------------------------------------------------- + */ +static H5HL_t * +H5HL_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * udata1, + void UNUSED * udata2) +{ + uint8_t hdr[52]; + size_t sizeof_hdr; /* Cache H5HL header size for file */ + const uint8_t *p = NULL; + H5HL_t *heap = NULL; + H5HL_free_t *fl = NULL, *tail = NULL; + size_t free_block = H5HL_FREE_NULL; + H5HL_t *ret_value; + + FUNC_ENTER_NOAPI(H5HL_load, NULL) + + /* check arguments */ + HDassert(f); + HDassert(H5F_addr_defined(addr)); + HDassert(!udata1); + HDassert(!udata2); + + /* Cache this for later */ + sizeof_hdr = H5HL_SIZEOF_HDR(f); + HDassert(sizeof_hdr <= sizeof(hdr)); + + /* Get the local heap's header */ + if(H5F_block_read(f, H5FD_MEM_LHEAP, addr, sizeof_hdr, dxpl_id, hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_READERROR, NULL, "unable to read heap header") + p = hdr; + + /* Check magic number */ + if(HDmemcmp(hdr, H5HL_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "bad heap signature") + p += H5_SIZEOF_MAGIC; + + /* Version */ + if(H5HL_VERSION != *p++) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "wrong version number in global heap") + + /* Reserved */ + p += 3; + + /* Allocate space in memory for the heap */ + if(NULL == (heap = H5FL_CALLOC(H5HL_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* heap data size */ + H5F_DECODE_LENGTH(f, p, heap->heap_alloc); + + /* free list head */ + H5F_DECODE_LENGTH(f, p, free_block); + if(free_block != H5HL_FREE_NULL && free_block >= heap->heap_alloc) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "bad heap free list") + + /* data */ + H5F_addr_decode(f, &p, &(heap->addr)); + if(NULL == (heap->chunk = H5FL_BLK_CALLOC(lheap_chunk, (sizeof_hdr + heap->heap_alloc)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + if(heap->heap_alloc && + H5F_block_read(f, H5FD_MEM_LHEAP, heap->addr, heap->heap_alloc, dxpl_id, heap->chunk + sizeof_hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "unable to read heap data") + + /* Build free list */ + while(H5HL_FREE_NULL != free_block) { + if(free_block >= heap->heap_alloc) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "bad heap free list") + if(NULL == (fl = H5FL_MALLOC(H5HL_free_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + fl->offset = free_block; + fl->prev = tail; + fl->next = NULL; + if(tail) + tail->next = fl; + tail = fl; + if(!heap->freelist) + heap->freelist = fl; + + p = heap->chunk + sizeof_hdr + free_block; + + H5F_DECODE_LENGTH(f, p, free_block); + if(free_block == 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "free block size is zero?") + + H5F_DECODE_LENGTH(f, p, fl->size); + if(fl->offset + fl->size > heap->heap_alloc) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, NULL, "bad heap free list") + } /* end while */ + + /* Set return value */ + ret_value = heap; + +done: + if(!ret_value && heap) + if(H5HL_dest(f,heap) < 0) + HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy local heap collection") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL_load() */ + + +/*------------------------------------------------------------------------- + * Function: H5HL_flush + * + * Purpose: Flushes a heap from memory to disk if it's dirty. Optionally + * deletes the heap from memory. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 17 1997 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HL_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5HL_t *heap, unsigned UNUSED * flags_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5HL_flush, FAIL) + + /* check arguments */ + HDassert(f); + HDassert(H5F_addr_defined(addr)); + HDassert(heap); + + if(heap->cache_info.is_dirty) { + haddr_t hdr_end_addr; + size_t sizeof_hdr = H5HL_SIZEOF_HDR(f); /* cache H5HL header size for file */ + + /* Write the header */ + if(H5HL_serialize(f, heap, heap->chunk) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTSERIALIZE, FAIL, "unable to serialize local heap") + + /* Copy buffer to disk */ + hdr_end_addr = addr + (hsize_t)sizeof_hdr; + + if(H5F_addr_eq(heap->addr, hdr_end_addr)) { + /* The header and data are contiguous */ + if(H5F_block_write(f, H5FD_MEM_LHEAP, addr, (sizeof_hdr + heap->heap_alloc), dxpl_id, heap->chunk) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "unable to write heap header and data to file") + } /* end if */ + else { + if(H5F_block_write(f, H5FD_MEM_LHEAP, addr, sizeof_hdr, dxpl_id, heap->chunk) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "unable to write heap header to file") + + if(H5F_block_write(f, H5FD_MEM_LHEAP, heap->addr, heap->heap_alloc, dxpl_id, heap->chunk + sizeof_hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "unable to write heap data to file") + } /* end else */ + + heap->cache_info.is_dirty = FALSE; + } /* end if */ + + /* Should we destroy the memory version? */ + if(destroy) + if(H5HL_dest(f, heap) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy local heap collection") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL_flush() */ + + +/*------------------------------------------------------------------------- + * Function: H5HL_dest + * + * Purpose: Destroys a heap in memory. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Jan 15 2003 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HL_dest(H5F_t *f, H5HL_t *heap) +{ + H5HL_free_t *fl; /* Heap object free list */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HL_dest) + + /* check arguments */ + HDassert(heap); + + /* Verify that node is clean */ + HDassert(heap->cache_info.is_dirty == FALSE); + + /* If we're going to free the space on disk, the address must be valid */ + HDassert(!heap->cache_info.free_file_space_on_destroy || H5F_addr_defined(heap->cache_info.addr)); + + /* Check for freeing file space for local heap */ + if(heap->cache_info.free_file_space_on_destroy) { + size_t sizeof_hdr; /* H5HL header size for file */ + haddr_t hdr_addr; /* Address of heap header in file */ + + /* Compute this for later */ + sizeof_hdr = H5HL_SIZEOF_HDR(f); + hdr_addr = heap->cache_info.addr; + + /* Check if the heap is contiguous on disk */ + HDassert(!H5F_addr_overflow(hdr_addr, sizeof_hdr)); + if(H5F_addr_eq(heap->addr, hdr_addr + sizeof_hdr)) { + /* Free the contiguous local heap in one call */ + /* (XXX: Nasty usage of internal DXPL value! -QAK) */ + H5_CHECK_OVERFLOW(sizeof_hdr + heap->heap_alloc, size_t, hsize_t); + if(H5MF_xfree(f, H5FD_MEM_LHEAP, H5AC_dxpl_id, hdr_addr, (hsize_t)(sizeof_hdr + heap->heap_alloc)) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free contiguous local heap") + } /* end if */ + else { + /* Free the local heap's header */ + /* (XXX: Nasty usage of internal DXPL value! -QAK) */ + H5_CHECK_OVERFLOW(sizeof_hdr, size_t, hsize_t); + if(H5MF_xfree(f, H5FD_MEM_LHEAP, H5AC_dxpl_id, hdr_addr, (hsize_t)sizeof_hdr) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free local heap header") + + /* Free the local heap's data */ + /* (XXX: Nasty usage of internal DXPL value! -QAK) */ + H5_CHECK_OVERFLOW(heap->heap_alloc, size_t, hsize_t); + if(H5MF_xfree(f, H5FD_MEM_LHEAP, H5AC_dxpl_id, heap->addr, (hsize_t)heap->heap_alloc) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free local heap data") + } /* end else */ + } /* end if */ + + /* Release resources */ + if(heap->chunk) + heap->chunk = H5FL_BLK_FREE(lheap_chunk, heap->chunk); + while(heap->freelist) { + fl = heap->freelist; + heap->freelist = fl->next; + (void)H5FL_FREE(H5HL_free_t, fl); + } /* end while */ + (void)H5FL_FREE(H5HL_t, heap); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL_dest() */ + + +/*------------------------------------------------------------------------- + * Function: H5HL_clear + * + * Purpose: Mark a local heap in memory as non-dirty. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Mar 20 2003 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HL_clear(H5F_t *f, H5HL_t *heap, hbool_t destroy) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5HL_clear) + + /* check arguments */ + HDassert(heap); + + /* Mark heap as clean */ + heap->cache_info.is_dirty = FALSE; + + if(destroy) + if(H5HL_dest(f, heap) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy local heap collection") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL_clear() */ + + +/*------------------------------------------------------------------------- + * Function: H5HL_size + * + * Purpose: Compute the size in bytes of the specified instance of + * H5HL_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 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HL_size(const H5F_t *f, const H5HL_t *heap, size_t *size_ptr) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5HL_size) + + /* check arguments */ + HDassert(f); + HDassert(heap); + HDassert(size_ptr); + + *size_ptr = H5HL_SIZEOF_HDR(f) + heap->heap_alloc; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5HL_size() */ + |