diff options
Diffstat (limited to 'src/H5HG.c')
-rw-r--r-- | src/H5HG.c | 887 |
1 files changed, 887 insertions, 0 deletions
diff --git a/src/H5HG.c b/src/H5HG.c new file mode 100644 index 0000000..63b41a3 --- /dev/null +++ b/src/H5HG.c @@ -0,0 +1,887 @@ +/* + * Copyright (C) 1998 NCSA + * All rights reserved. + * + * Programmer: Robb Matzke <matzke@llnl.gov> + * Friday, March 27, 1998 + * + * Purpose: Operations on the global heap. The global heap is the set of + * all collections and each collection contains one or more + * global heap objects. An object belongs to exactly one + * collection. A collection is treated as an atomic entity for + * the purposes of I/O and caching. + * + * Each file has a small cache of global heap collections called + * the CWFS list and recently accessed collections with free + * space appear on this list. As collections are accessed the + * collection is moved toward the front of the list. New + * collections are added to the front of the list while old + * collections are added to the end of the list. + * + * The collection model reduces the overhead which would be + * incurred if the global heap were a single object, and the + * CWFS list allows the library to cheaply choose a collection + * for a new object based on object size, amount of free space + * in the collection, and temporal locality. + */ +#include <H5private.h> /*library */ +#include <H5ACprivate.h> /*caching */ +#include <H5Eprivate.h> /*error handling */ +#include <H5HGprivate.h> /*global heaps */ +#include <H5MFprivate.h> /*file memory management */ +#include <H5MMprivate.h> /*memory management */ + +#define PABLO_MASK H5HG_mask + +struct H5HG_t { + haddr_t addr; /*address of collection */ + intn idx; /*object ID within collection */ +}; + +typedef struct H5HG_obj_t { + intn nrefs; /*reference count */ + size_t size; /*total size of object */ + uint8 *begin; /*ptr to object into heap->chunk*/ +} H5HG_obj_t; + +typedef struct H5HG_heap_t { + haddr_t addr; /*collection address */ + hbool_t dirty; /*does heap need to be saved? */ + size_t size; /*total size of collection */ + uint8 *chunk; /*the collection, incl. header */ + intn nalloc; /*numb object slots allocated */ + H5HG_obj_t *obj; /*array of object descriptions */ +} H5HG_heap_t; + +/* PRIVATE PROTOTYPES */ +static H5HG_heap_t *H5HG_load(H5F_t *f, const haddr_t *addr, + const void *udata1, void *udata2); +static herr_t H5HG_flush(H5F_t *f, hbool_t dest, const haddr_t *addr, + H5HG_heap_t *heap); + +/* + * H5HG inherits cache-like properties from H5AC + */ +static const H5AC_class_t H5AC_GHEAP[1] = {{ + H5AC_GHEAP_ID, + (void *(*)(H5F_t*, const haddr_t*, const void*, void*))H5HG_load, + (herr_t (*)(H5F_t*, hbool_t, const haddr_t*, void*))H5HG_flush, +}}; + +/* Interface initialization */ +static intn interface_initialize_g = FALSE; +#define INTERFACE_INIT NULL + + +/*------------------------------------------------------------------------- + * Function: H5HG_create + * + * Purpose: Creates a global heap collection of the specified size. If + * SIZE is less than some minimum it will be readjusted. The + * new collection is allocated in the file and added to the + * beginning of the CWFS list. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, March 27, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5HG_create (H5F_t *f, size_t size) +{ + H5HG_heap_t *heap = NULL; + herr_t ret_value = FAIL; + uint8 *p = NULL; + haddr_t addr; + + FUNC_ENTER (H5HG_create, FAIL); + + /* Check args */ + assert (f); + if (size<H5HG_MINSIZE) size = H5HG_MINSIZE; + + /* Create it */ + if (H5MF_alloc (f, H5MF_META, size, &addr/*out*/)<0) { + HGOTO_ERROR (H5E_HEAP, H5E_CANTINIT, FAIL, + "unable to allocate file space for global heap"); + } + heap = H5MM_xcalloc (1, sizeof(H5HG_heap_t)); + heap->addr = addr; + heap->size = size; + heap->dirty = TRUE; + heap->chunk = H5MM_xmalloc (size); + heap->nalloc = H5HG_NOBJS (f, size); + heap->obj = H5MM_xcalloc (heap->nalloc, sizeof(H5HG_obj_t)); + + /* Initialize the header */ + HDmemcpy (heap->chunk, H5HG_MAGIC, H5HG_SIZEOF_MAGIC); + p = heap->chunk + H5HG_SIZEOF_MAGIC; + *p++ = H5HG_VERSION; + p += 3; /*reserved*/ + H5F_encode_length (f, p, size); + + /* The freespace object */ + heap->obj[0].size = size - H5HG_SIZEOF_HDR (f); + heap->obj[0].begin = p; + UINT16ENCODE (p, 0); /*object ID*/ + UINT16ENCODE (p, 0); /*reference count*/ + H5F_encode_length (f, p, heap->obj[0].size); + HDmemset (p, 0, (heap->chunk+heap->nalloc) - p); + + /* Add the heap to the cache */ + if (H5AC_set (f, H5AC_GHEAP, &addr, heap)<0) { + HGOTO_ERROR (H5E_HEAP, H5E_CANTINIT, FAIL, + "unable to cache global heap collection"); + } + + /* Add this heap to the beginning of the CWFS list */ + if (NULL==f->shared->cwfs) { + f->shared->cwfs = H5MM_xmalloc (H5HG_NCWFS * sizeof(H5HG_heap_t*)); + f->shared->cwfs[0] = heap; + f->shared->ncwfs = 1; + } else { + HDmemmove (f->shared->cwfs+1, f->shared->cwfs, + MIN (f->shared->ncwfs, H5HG_NCWFS-1)*sizeof(H5HG_heap_t*)); + f->shared->cwfs[0] = heap; + f->shared->ncwfs = MIN (H5HG_NCWFS, f->shared->ncwfs+1); + } + + ret_value = SUCCEED; + + done: + if (ret_value<0 && heap) { + H5MM_xfree (heap->chunk); + H5MM_xfree (heap->obj); + H5MM_xfree (heap); + } + FUNC_LEAVE (ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5HG_load + * + * Purpose: Loads a global heap collection from disk. + * + * Return: Success: Ptr to a global heap collection. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Friday, March 27, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static H5HG_heap_t * +H5HG_load (H5F_t *f, const haddr_t *addr, const void *udata1, void *udata2) +{ + H5HG_heap_t *heap = NULL; + H5HG_heap_t *ret_value = NULL; + uint8 *p = NULL; + intn i; + + FUNC_ENTER (H5HG_load, NULL); + + /* check arguments */ + assert (f); + assert (addr && H5F_addr_defined (addr)); + assert (!udata1); + assert (!udata2); + + /* Read the initial 4k page */ + heap = H5MM_xcalloc (1, sizeof(H5HG_heap_t)); + heap->addr = *addr; + heap->chunk = H5MM_xmalloc (H5HG_MINSIZE); + if (H5F_block_read (f, addr, H5HG_MINSIZE, heap->chunk)<0) { + HGOTO_ERROR (H5E_HEAP, H5E_READERROR, NULL, + "unable to read global heap collection"); + } + + /* Magic number */ + if (HDmemcmp (heap->chunk, H5HG_MAGIC, H5HG_SIZEOF_MAGIC)) { + HGOTO_ERROR (H5E_HEAP, H5E_CANTLOAD, NULL, + "bad global heap collection signature"); + } + p = heap->chunk + H5HG_SIZEOF_MAGIC; + + /* Version */ + if (H5HG_VERSION!=*p++) { + HGOTO_ERROR (H5E_HEAP, H5E_CANTLOAD, NULL, + "wrong version number in global heap"); + } + + /* Reserved */ + p += 3; + + /* Size */ + H5F_decode_length (f, p, heap->size); + assert (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; + H5F_addr_inc (&next_addr, H5HG_MINSIZE); + heap->chunk = H5MM_xrealloc (heap->chunk, heap->size); + if (H5F_block_read (f, &next_addr, heap->size-H5HG_MINSIZE, + heap->chunk+H5HG_MINSIZE)<0) { + HGOTO_ERROR (H5E_HEAP, H5E_READERROR, NULL, + "unable to read global heap collection"); + } + } + + /* Decode each object */ + p = heap->chunk + H5HG_SIZEOF_HDR (f); + heap->nalloc = H5HG_NOBJS (f, heap->size); + heap->obj = H5MM_xcalloc (heap->nalloc, sizeof(H5HG_obj_t)); + 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. + */ + assert (NULL==heap->obj[0].begin); + heap->obj[0].size = (heap->chunk+heap->size) - p; + heap->obj[0].begin = p; + p += heap->obj[0].size; + } else { + intn idx; + uint8 *begin = p; + UINT16DECODE (p, idx); + assert (idx<heap->nalloc); + assert (NULL==heap->obj[idx].begin); + UINT16DECODE (p, heap->obj[idx].nrefs); + H5F_decode_length (f, p, heap->obj[idx].size); + heap->obj[idx].begin = begin; + p += heap->obj[idx].size; + } + } + assert (p==heap->chunk+heap->size); + + /* + * Add the new heap to the CWFS list, removing some other entry if + * necessary to make room. We remove the right-most entry that has less + * free space than this heap. + */ + if (heap->obj[0].size>0) { + if (!f->shared->cwfs) { + f->shared->cwfs = H5MM_xmalloc (H5HG_NCWFS*sizeof(H5HG_heap_t*)); + f->shared->ncwfs = 1; + f->shared->cwfs[0] = heap; + } else if (H5HG_NCWFS==f->shared->ncwfs) { + for (i=H5HG_NCWFS-1; i>=0; --i) { + if (f->shared->cwfs[i]->obj[0].size < heap->obj[0].size) { + HDmemcpy (f->shared->cwfs+1, f->shared->cwfs, + i * sizeof(H5HG_heap_t*)); + f->shared->cwfs[0] = heap; + break; + } + } + } else { + HDmemcpy (f->shared->cwfs+1, f->shared->cwfs, + f->shared->ncwfs*sizeof(H5HG_heap_t*)); + f->shared->ncwfs += 1; + f->shared->cwfs[0] = heap; + } + } + + ret_value = heap; + + done: + if (!ret_value && heap) { + H5MM_xfree (heap->chunk); + H5MM_xfree (heap->obj); + H5MM_xfree (heap); + } + FUNC_LEAVE (ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5HG_flush + * + * Purpose: Flushes a global heap collection from memory to disk if it's + * dirty. Optionally deletes teh heap from memory. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, March 27, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HG_flush (H5F_t *f, hbool_t destroy, const haddr_t *addr, H5HG_heap_t *heap) +{ + int i; + + FUNC_ENTER (H5HG_flush, FAIL); + + /* Check arguments */ + assert (f); + assert (addr && H5F_addr_defined (addr)); + assert (H5F_addr_eq (addr, &(heap->addr))); + assert (heap); + + if (heap->dirty) { + if (H5F_block_write (f, addr, heap->size, heap->chunk)<0) { + HRETURN_ERROR (H5E_HEAP, H5E_WRITEERROR, FAIL, + "unable to write global heap collection to file"); + } + heap->dirty = 0; + } + + if (destroy) { + for (i=0; i<f->shared->ncwfs; i++) { + if (f->shared->cwfs[i]==heap) { + f->shared->ncwfs -= 1; + HDmemmove (f->shared->cwfs+i, f->shared->cwfs+i+1, + (f->shared->ncwfs-i) * sizeof(H5HG_heap_t*)); + break; + } + } + heap->chunk = H5MM_xfree (heap->chunk); + heap->obj = H5MM_xfree (heap->obj); + H5MM_xfree (heap); + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5HG_alloc + * + * Purpose: Given a heap with enough free space, this function will split + * the free space to make a new empty heap object and initialize + * the header. + * + * Return: Success: The heap object ID of the new object. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, March 27, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static intn +H5HG_alloc (H5F_t *f, H5HG_heap_t *heap, int cwfsno, size_t size) +{ + int idx; + uint8 *p = NULL; + + FUNC_ENTER (H5HG_alloc, FAIL); + + /* Check args */ + assert (heap); + assert (heap->obj[0].size>=size); + + /* + * Find an ID for the new object. ID zero is reserved for the free space + * object. + */ + for (idx=1; idx<heap->nalloc; idx++) { + if (NULL==heap->obj[idx].begin) break; + } + assert (idx < heap->nalloc); + + /* Initialize the new object */ + heap->obj[idx].nrefs = 0; + heap->obj[idx].size = size; + heap->obj[idx].begin = heap->obj[0].begin; + p = heap->obj[idx].begin; + UINT16ENCODE (p, idx); + UINT16ENCODE (p, 0); /*nrefs*/ + H5F_encode_length (f, p, size); + + /* Fix the free space object */ + if (size==heap->obj[0].size) { + /* + * All free space has been exhausted from this collection. Remove the + * heap from the CWFS list. + */ + heap->obj[0].size = 0; + heap->obj[0].begin = NULL; + if (cwfsno>=0) { + f->shared->ncwfs -= 1; + HDmemmove (f->shared->cwfs+cwfsno, f->shared->cwfs+cwfsno+1, + (f->shared->ncwfs-cwfsno)*sizeof(H5HG_heap_t*)); + } + + } else if (heap->obj[0].size-size >= H5HG_SIZEOF_OBJHDR (f)) { + /* + * Some free space remains and it's larger than a heap object header, + * so write the new free heap object header to the heap. + */ + heap->obj[0].size -= size; + heap->obj[0].begin += size; + p = heap->obj[0].begin; + UINT16ENCODE (p, 0); /*id*/ + UINT16ENCODE (p, 0); /*nrefs*/ + H5F_encode_length (f, p, heap->obj[0].size); + + } else { + /* + * Some free space remains but it's smaller than a heap object header, + * so we don't write the header. + */ + heap->obj[0].size -= size; + heap->obj[0].begin += size; + } + + heap->dirty = 1; + FUNC_LEAVE (idx); +} + + +/*------------------------------------------------------------------------- + * Function: H5HG_insert + * + * Purpose: A new object is inserted into the global heap. It will be + * placed in the first collection on the CWFS list which has + * enough free space and that collection will be advanced one + * position in the list. If no collection on the CWFS list has + * enough space then a new collection will be created. + * + * It is legal to push a zero-byte object onto the heap to get + * the reference count features of heap objects. + * + * Return: Success: SUCCEED, and a heap object handle returned + * through the HOBJ pointer. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, March 27, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5HG_insert (H5F_t *f, size_t size, void *obj, H5HG_t *hobj/*out*/) +{ + size_t need; /*total space needed for object */ + intn cwfsno, idx; + H5HG_heap_t *heap = NULL; + + FUNC_ENTER (H5HG_insert, FAIL); + + /* Check args */ + assert (f); + assert (0==size || obj); + assert (hobj); + + /* Find a large enough collection on the CWFS list */ + need = size + H5HG_SIZEOF_OBJHDR (f); + for (cwfsno=0; cwfsno<f->shared->ncwfs; cwfsno++) { + if (f->shared->cwfs[cwfsno]->obj[0].size>=need) { + /* + * Found. Move the collection forward in the CWFS list. + */ + heap = f->shared->cwfs[cwfsno]; + if (cwfsno>0) { + H5HG_heap_t *tmp = f->shared->cwfs[cwfsno]; + f->shared->cwfs[cwfsno] = f->shared->cwfs[cwfsno-1]; + f->shared->cwfs[cwfsno-1] = tmp; + --cwfsno; + break; + } + } + } + + /* + * If we didn't find any collection with enough free space then allocate a + * new collection large enough for the message plus the collection header. + */ + if (cwfsno>=f->shared->ncwfs) { + if (H5HG_create (f, need+H5HG_SIZEOF_HDR (f))<0) { + HRETURN_ERROR (H5E_HEAP, H5E_CANTINIT, FAIL, + "unable to allocate a global heap collection"); + } + assert (f->shared->ncwfs>0); + assert (f->shared->cwfs[0]->obj[0].size >= need+H5HG_SIZEOF_HDR(f)); + cwfsno = 0; + } + + /* Split the free space to make room for the new object */ + idx = H5HG_alloc (f, heap, cwfsno, need); + assert (idx>0); + + /* Copy data into the heap */ + HDmemcpy (heap->obj[idx].begin+H5HG_SIZEOF_OBJHDR(f), obj, size); + heap->dirty = TRUE; + + /* Return value */ + hobj->addr = heap->addr; + hobj->idx = idx; + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5HG_peek + * + * Purpose: Given an ID for a global heap object return a pointer to the + * beginning of that object. This is intended for quick and + * dirty access to the object; otherwise use H5HG_read(). + * + * Return: Success: Ptr directly into the H5AC layer for the + * specified object of the global heap. The + * pointer is guaranteed to be valid only until + * some other hdf5 library function is called. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Monday, March 30, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void * +H5HG_peek (H5F_t *f, H5HG_t *hobj) +{ + H5HG_heap_t *heap = NULL; + void *retval = NULL; + intn i; + + FUNC_ENTER (H5HG_peek, NULL); + + /* Check args */ + assert (f); + assert (hobj); + + /* Load the heap and return a pointer to the object */ + if (NULL==(heap=H5AC_find (f, H5AC_GHEAP, &(hobj->addr), NULL, NULL))) { + HRETURN_ERROR (H5E_HEAP, H5E_CANTLOAD, NULL, "unable to load heap"); + } + assert (hobj->idx>0 && hobj->idx<heap->nalloc); + retval = heap->obj[hobj->idx].begin + H5HG_SIZEOF_OBJHDR (f); + assert (retval); + + /* + * Advance the heap in the CWFS list. We might have done this already + * with the H5AC_find(), but it won't hurt to do it twice. + */ + if (heap->obj[0].begin) { + for (i=0; i<f->shared->ncwfs; i++) { + if (f->shared->cwfs[i]==heap) { + if (i) { + f->shared->cwfs[i] = f->shared->cwfs[i-1]; + f->shared->cwfs[i-1] = heap; + } + break; + } + } + } + + FUNC_LEAVE (retval); +} + + +/*------------------------------------------------------------------------- + * Function: H5HG_read + * + * Purpose: Reads the specified global heap object into the buffer OBJECT + * supplied by the caller. If the caller doesn't supply a + * buffer then one will be allocated. The buffer should be + * large enough to hold the result. + * + * Return: Success: The buffer containing the result. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Monday, March 30, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void * +H5HG_read (H5F_t *f, H5HG_t *hobj, void *object/*out*/) +{ + H5HG_heap_t *heap = NULL; + intn i; + size_t size; + uint8 *p = NULL; + + FUNC_ENTER (H5HG_read, NULL); + + /* Check args */ + assert (f); + assert (hobj); + + /* Load the heap */ + if (NULL==(heap=H5AC_find (f, H5AC_GHEAP, &(hobj->addr), NULL, NULL))) { + HRETURN_ERROR (H5E_HEAP, H5E_CANTLOAD, NULL, "unable to load heap"); + } + assert (hobj->idx>0 && hobj->idx<heap->nalloc); + assert (heap->obj[hobj->idx].begin); + size = heap->obj[hobj->idx].size - H5HG_SIZEOF_OBJHDR (f); + p = heap->obj[hobj->idx].begin + H5HG_SIZEOF_OBJHDR (f); + if (!object) object = H5MM_xmalloc (size); + HDmemcpy (object, p, size); + + /* + * Advance the heap in the CWFS list. We might have done this already + * with the H5AC_find(), but it won't hurt to do it twice. + */ + if (heap->obj[0].begin) { + for (i=0; i<f->shared->ncwfs; i++) { + if (f->shared->cwfs[i]==heap) { + if (i) { + f->shared->cwfs[i] = f->shared->cwfs[i-1]; + f->shared->cwfs[i-1] = heap; + } + break; + } + } + } + + FUNC_LEAVE (object); +} + + +/*------------------------------------------------------------------------- + * Function: H5HG_link + * + * Purpose: Adjusts the link count for a global heap object by adding + * ADJUST to the current value. This function will fail if the + * new link count would overflow. Nothing special happens when + * the link count reaches zero; in order for a heap object to be + * removed one must call H5HG_remove(). + * + * Return: Success: Number of links present after the adjustment. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Monday, March 30, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +intn +H5HG_link (H5F_t *f, H5HG_t *hobj, intn adjust) +{ + H5HG_heap_t *heap = NULL; + + FUNC_ENTER (H5HG_link, FAIL); + + /* Check args */ + assert (f); + assert (hobj); + + /* Load the heap */ + if (NULL==(heap=H5AC_find (f, H5AC_GHEAP, &(hobj->addr), NULL, NULL))) { + HRETURN_ERROR (H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to load heap"); + } + assert (hobj->idx>0 && hobj->idx<heap->nalloc); + assert (heap->obj[hobj->idx].begin); + if (heap->obj[hobj->idx].nrefs+adjust<0) { + HRETURN_ERROR (H5E_HEAP, H5E_BADRANGE, FAIL, + "new link count would be out of range"); + } + if (heap->obj[hobj->idx].nrefs+adjust>H5HG_MAXLINK) { + HRETURN_ERROR (H5E_HEAP, H5E_BADVALUE, FAIL, + "new link count would be out of range"); + } + heap->obj[hobj->idx].nrefs += adjust; + if (adjust) heap->dirty = TRUE; + + FUNC_LEAVE (heap->obj[hobj->idx].nrefs); +} + + +/*------------------------------------------------------------------------- + * Function: H5HG_remove + * + * Purpose: Removes the specified object from the global heap. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Monday, March 30, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5HG_remove (H5F_t *f, H5HG_t *hobj) +{ + uint8 *p=NULL, *obj_start=NULL; + H5HG_heap_t *heap = NULL; + size_t size; + intn i; + + FUNC_ENTER (H5HG_remove, FAIL); + + /* Check args */ + assert (f); + assert (hobj); + + /* Load the heap */ + if (NULL==(heap=H5AC_find (f, H5AC_GHEAP, &(hobj->addr), NULL, NULL))) { + HRETURN_ERROR (H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to load heap"); + } + assert (hobj->idx>0 && hobj->idx<heap->nalloc); + assert (heap->obj[hobj->idx].begin); + obj_start = heap->obj[hobj->idx].begin; + size = heap->obj[hobj->idx].size; + + /* Move the new free space to the end of the heap */ + for (i=0; i<heap->nalloc; i++) { + if (heap->obj[i].begin > heap->obj[hobj->idx].begin) { + heap->obj[i].begin -= size; + } + } + if (NULL==heap->obj[0].begin) { + heap->obj[0].begin = heap->chunk + (heap->size-size); + heap->obj[0].size = size; + heap->obj[0].nrefs = 0; + } + HDmemmove (obj_start, obj_start+size, + heap->size-((obj_start+size)-heap->chunk)); + if (heap->obj[0].size>=H5HG_SIZEOF_OBJHDR (f)) { + p = heap->obj[0].begin; + UINT32ENCODE (p, 0); /*id*/ + UINT32ENCODE (p, 0); /*nrefs*/ + H5F_encode_length (f, p, size); + } + HDmemset (heap->obj+hobj->idx, 0, sizeof(H5HG_obj_t)); + heap->dirty = 1; + + if (heap->obj[0].size+H5HG_SIZEOF_HDR(f)==heap->size) { + /* + * The collection is empty. Remove it from the CWFS list and return it + * to the file free list. + */ + heap->dirty = FALSE; + H5MF_free (f, &(heap->addr), heap->size); + H5AC_flush (f, H5AC_GHEAP, &(heap->addr), TRUE); + heap = NULL; + } else { + /* + * If the heap is in the CWFS list then advance it one position. The + * H5AC_find() might have done that too, but that's okay. If the + * heap isn't on the CWFS list then add it to the end. + */ + for (i=0; i<f->shared->ncwfs; i++) { + if (f->shared->cwfs[i]==heap) { + if (i) { + f->shared->cwfs[i] = f->shared->cwfs[i-1]; + f->shared->cwfs[i-1] = heap; + } + break; + } + } + if (i>=f->shared->ncwfs) { + f->shared->ncwfs = MIN (f->shared->ncwfs+1, H5HG_NCWFS); + f->shared->cwfs[f->shared->ncwfs-1] = heap; + } + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5HG_debug + * + * Purpose: Prints debugging information about a global heap collection. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Mar 27, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5HG_debug(H5F_t *f, const haddr_t *addr, FILE *stream, intn indent, + intn fwidth) +{ + int i, nused, maxobj; + H5HG_heap_t *h = NULL; + char buf[64]; + + FUNC_ENTER(H5HG_debug, FAIL); + + /* check arguments */ + assert(f); + if (addr && H5F_addr_defined (addr)); + assert(stream); + assert(indent >= 0); + assert(fwidth >= 0); + + if (NULL == (h = H5AC_find(f, H5AC_GHEAP, addr, NULL, NULL))) { + HRETURN_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, + "unable to load global heap collection"); + } + fprintf(stream, "%*sGlobal Heap Collection...\n", indent, ""); + fprintf(stream, "%*s%-*s %d\n", indent, "", fwidth, + "Dirty:", + (int)(h->dirty)); + fprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth, + "Total collection size in file:", + (unsigned long)(h->size)); + + for (i=1, nused=0, maxobj=-1; i<h->nalloc; i++) { + if (h->obj[i].begin) { + nused++; + if (i>maxobj) maxobj = i; + } + } + fprintf (stream, "%*s%-*s %d/%d/", indent, "", fwidth, + "Objects defined/allocated/max:", + nused, h->nalloc); + fprintf (stream, nused?"%d\n":"NA\n", maxobj); + + fprintf (stream, "%*s%-*s %lu\n", indent, "", fwidth, + "Free space:", + (unsigned long)(h->obj[0].size)); + + for (i=1; i<h->nalloc; i++) { + if (h->obj[i].begin) { + sprintf (buf, "Object %d", i); + fprintf (stream, "%*s%-*s:\n", indent, "", fwidth, buf); + fprintf (stream, "%*s%-*s %d\n", indent+3, "", MIN(fwidth-3, 0), + "Reference count:", + h->obj[i].nrefs); + fprintf (stream, "%*s%-*s %lu\n", indent+3, "", MIN(fwidth-3, 0), + "Size of object body:", + (unsigned long)(h->obj[i].size)); + } + } + + FUNC_LEAVE(SUCCEED); +} |