diff options
Diffstat (limited to 'src')
54 files changed, 1828 insertions, 898 deletions
@@ -28,6 +28,7 @@ #include "H5Lprivate.h" /* Links */ #include "H5Pprivate.h" /* Property lists */ #include "H5Tprivate.h" /* Datatypes */ +#include "H5SLprivate.h" /* Skip lists */ /****************/ @@ -270,6 +271,9 @@ H5_term_library(void) /* Don't shut down the ID code until other APIs which use them are shut down */ if(pending == 0) pending += DOWN(I); + /* Don't shut down the skip list code until everything that uses it is down */ + if(pending == 0) + pending += DOWN(SL); /* Don't shut down the free list code until _everything_ else is down */ if(pending == 0) pending += DOWN(FL); @@ -405,6 +409,9 @@ done: * global lists, up to 3 MB of total storage might be allocated (1MB on * each of regular, array and block type lists). * + * The settings for block free lists are duplicated to factory free lists. + * Factory free list limits cannot be set independently currently. + * * Parameters: * int reg_global_lim; IN: The limit on all "regular" free list memory used * int reg_list_lim; IN: The limit on memory used in each "regular" free list @@ -420,7 +427,9 @@ done: * Programmer: Quincey Koziol * Wednesday, August 2, 2000 * - * Modifications: + * Modifications: Neil Fortner + * Wednesday, April 8, 2009 + * Added support for factory free lists * *------------------------------------------------------------------------- */ @@ -435,7 +444,8 @@ H5set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim, arr_list_lim, blk_global_lim, blk_list_lim); /* Call the free list function to actually set the limits */ - if(H5FL_set_free_list_limits(reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim, blk_global_lim, blk_list_lim)<0) + if(H5FL_set_free_list_limits(reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim, + blk_global_lim, blk_list_lim, blk_global_lim, blk_list_lim)<0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "can't set garbage collection limits") done: @@ -589,7 +589,7 @@ H5AC_create(const H5F_t *f, if ( mpi_rank == 0 ) { aux_ptr->d_slist_ptr = - H5SL_create(H5SL_TYPE_HADDR,0.5,(size_t)16); + H5SL_create(H5SL_TYPE_HADDR); if ( aux_ptr->d_slist_ptr == NULL ) { @@ -598,7 +598,7 @@ H5AC_create(const H5F_t *f, } aux_ptr->c_slist_ptr = - H5SL_create(H5SL_TYPE_HADDR,0.5,(size_t)16); + H5SL_create(H5SL_TYPE_HADDR); if ( aux_ptr->c_slist_ptr == NULL ) { @@ -2057,7 +2057,6 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5B_get_info() */ -#ifndef H5_STRICT_FORMAT_CHECKS /*------------------------------------------------------------------------- * Function: H5B_valid @@ -2099,5 +2098,4 @@ H5B_valid(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr) done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5B_valid() */ -#endif /* H5_STRICT_FORMAT_CHECKS */ diff --git a/src/H5B2cache.c b/src/H5B2cache.c index c44820a..5ca7ed8 100644 --- a/src/H5B2cache.c +++ b/src/H5B2cache.c @@ -275,7 +275,8 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B2_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5B2_t *bt2, unsigned UNUSED * flags_ptr) +H5B2_cache_hdr_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, + H5B2_t *bt2, unsigned UNUSED * flags_ptr) { H5WB_t *wb = NULL; /* Wrapped buffer for header data */ uint8_t hdr_buf[H5B2_HDR_BUF_SIZE]; /* Buffer for header */ diff --git a/src/H5B2test.c b/src/H5B2test.c index f2cf79d..46cd510 100644 --- a/src/H5B2test.c +++ b/src/H5B2test.c @@ -456,7 +456,7 @@ H5B2_get_node_depth_test(H5F_t *f, hid_t dxpl_id, const H5B2_class_t *type, hadd HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "error looking up node info") /* Set return value */ - ret_value = ninfo.depth; + ret_value = (int)ninfo.depth; done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Bprivate.h b/src/H5Bprivate.h index 2ec2c22..716b608 100644 --- a/src/H5Bprivate.h +++ b/src/H5Bprivate.h @@ -168,9 +168,7 @@ H5_DLL H5B_shared_t *H5B_shared_new(const H5F_t *f, const H5B_class_t *type, H5_DLL herr_t H5B_shared_free(void *_shared); H5_DLL herr_t H5B_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent, int fwidth, const H5B_class_t *type, void *udata); -#ifndef H5_STRICT_FORMAT_CHECKS H5_DLL htri_t H5B_valid(H5F_t *f, hid_t dxpl_id, const H5B_class_t *type, haddr_t addr); -#endif /* H5_STRICT_FORMAT_CHECKS */ #endif /* _H5Bprivate_H */ @@ -3046,8 +3046,7 @@ H5C_create(size_t max_cache_size, "memory allocation failed") } - if ( (cache_ptr->slist_ptr = H5SL_create(H5SL_TYPE_HADDR,0.5,(size_t)16)) - == NULL ) { + if ( (cache_ptr->slist_ptr = H5SL_create(H5SL_TYPE_HADDR)) == NULL ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, NULL, "can't create skip list.") } diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index a88df43..ae90627 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -63,9 +63,6 @@ /* Local Macros */ /****************/ -/* Default skip list height for storing list of chunks */ -#define H5D_CHUNK_DEFAULT_SKIPLIST_HEIGHT 8 - /* Macros for iterating over chunks to operate on */ #define H5D_CHUNK_GET_FIRST_NODE(map) (map->use_single ? (H5SL_node_t *)(1) : H5SL_first(map->sel_chunks)) #define H5D_CHUNK_GET_NODE_INFO(map, node) (map->use_single ? map->single_chunk_info : (H5D_chunk_info_t *)H5SL_item(node)) @@ -534,7 +531,7 @@ H5D_chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info else { /* Initialize skip list for chunk selections */ if(NULL == dataset->shared->cache.chunk.sel_chunks) { - if(NULL == (dataset->shared->cache.chunk.sel_chunks = H5SL_create(H5SL_TYPE_HSIZE, 0.5, (size_t)H5D_CHUNK_DEFAULT_SKIPLIST_HEIGHT))) + if(NULL == (dataset->shared->cache.chunk.sel_chunks = H5SL_create(H5SL_TYPE_HSIZE))) HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for chunk selections") } /* end if */ fm->sel_chunks = dataset->shared->cache.chunk.sel_chunks; diff --git a/src/H5Dscatgath.c b/src/H5Dscatgath.c index bb9f46b..ed73f3c 100644 --- a/src/H5Dscatgath.c +++ b/src/H5Dscatgath.c @@ -662,6 +662,12 @@ H5D_scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed") } /* end if */ + /* Do the data transform before the type conversion (since + * transforms must be done in the memory type). */ + if(!type_info->is_xform_noop) + if(H5Z_xform_eval(dxpl_cache->data_xform_prop, type_info->tconv_buf, smine_nelmts, type_info->mem_type) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform") + /* * Perform datatype conversion. */ @@ -669,11 +675,6 @@ H5D_scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf smine_nelmts, (size_t)0, (size_t)0, type_info->tconv_buf, type_info->bkg_buf, io_info->dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed") - - /* Do the data transform after the type conversion (since we're using dataset->shared->type). */ - if(!type_info->is_xform_noop) - if(H5Z_xform_eval(dxpl_cache->data_xform_prop, type_info->tconv_buf, smine_nelmts, type_info->dset_type) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform") } /* end else */ /* @@ -893,6 +893,7 @@ H5F_new(H5F_file_t *shared, hid_t fcpl_id, hid_t fapl_id, H5FD_t *lf) f->shared->driver_addr = HADDR_UNDEF; f->shared->accum.loc = HADDR_UNDEF; f->shared->lf = lf; + f->shared->root_addr = HADDR_UNDEF; /* * Copy the file creation and file access property lists into the @@ -1369,7 +1370,7 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t d /* (This must be after the space for the superblock is allocated in * the file, since the superblock must be at offset 0) */ - if(H5G_mkroot(file, dxpl_id, NULL) < 0) + if(H5G_mkroot(file, dxpl_id, TRUE) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create/open root group") /* Write the superblock to the file */ @@ -1379,21 +1380,12 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, hid_t d if(H5F_super_write(file, dxpl_id) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to write file superblock") } else if (1 == shared->nrefs) { - H5G_loc_t root_loc; /*root location */ - H5O_loc_t root_oloc; /*root object location */ - H5G_name_t root_path; /*root group hier. path */ - - /* Set up root location to fill in */ - root_loc.oloc = &root_oloc; - root_loc.path = &root_path; - H5G_loc_reset(&root_loc); - /* Read the superblock if it hasn't been read before. */ - if(H5F_super_read(file, dxpl_id, &root_loc) < 0) + if(H5F_super_read(file, dxpl_id) < 0) HGOTO_ERROR(H5E_FILE, H5E_READERROR, NULL, "unable to read superblock") /* Open the root group */ - if(H5G_mkroot(file, dxpl_id, &root_loc) < 0) + if(H5G_mkroot(file, dxpl_id, FALSE) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to read root group") } /* end if */ @@ -52,6 +52,8 @@ static size_t H5FL_arr_glb_mem_lim=4*1024*1024; /* Default to 4MB limit on all a static size_t H5FL_arr_lst_mem_lim=4*65536; /* Default to 256KB limit on each array free list */ static size_t H5FL_blk_glb_mem_lim=16*1024*1024; /* Default to 16MB limit on all block free lists */ static size_t H5FL_blk_lst_mem_lim=1024*1024; /* Default to 1024KB (1MB) limit on each block free list */ +static size_t H5FL_fac_glb_mem_lim=16*1024*1024; /* Default to 16MB limit on all factory free lists */ +static size_t H5FL_fac_lst_mem_lim=1024*1024; /* Default to 1024KB (1MB) limit on each factory free list */ /* A garbage collection node for regular free lists */ typedef struct H5FL_reg_gc_node_t { @@ -98,6 +100,36 @@ typedef struct H5FL_blk_gc_list_t { /* The head of the list of PQs to garbage collect */ static H5FL_blk_gc_list_t H5FL_blk_gc_head={0,NULL}; +/* A garbage collection node for factory free lists */ +typedef struct H5FL_fac_gc_node_t { + H5FL_fac_head_t *list; /* Pointer to the head of the list to garbage collect */ + struct H5FL_fac_gc_node_t *next; /* Pointer to the next node in the list of things to garbage collect */ +} H5FL_fac_gc_node_t; + +/* The garbage collection head for factory free lists */ +typedef struct H5FL_fac_gc_list_t { + size_t mem_freed; /* Amount of free memory on list */ + struct H5FL_fac_gc_node_t *first; /* Pointer to the first node in the list of things to garbage collect */ +} H5FL_fac_gc_list_t; + +/* Data structure to store each block in factory free list */ +typedef struct H5FL_fac_node_t { + struct H5FL_fac_node_t *next; /* Pointer to next block in free list */ +} H5FL_fac_node_t; + +/* Data structure for free list block factory */ +struct H5FL_fac_head_t { + unsigned init; /* Whether the free list has been initialized */ + unsigned allocated; /* Number of blocks allocated */ + unsigned onlist; /* Number of blocks on free list */ + size_t size; /* Size of the blocks in the list */ + H5FL_fac_node_t *list; /* List of free blocks */ + H5FL_fac_gc_node_t *prev_gc; /* Previous garbage collection node in list */ +}; + +/* The head of the list of factory things to garbage collect */ +static H5FL_fac_gc_list_t H5FL_fac_gc_head={0,NULL}; + #ifdef H5FL_TRACK /* Extra headers needed */ @@ -114,14 +146,18 @@ static herr_t H5FL_arr_gc(void); static herr_t H5FL_arr_gc_list(H5FL_arr_head_t *head); static herr_t H5FL_blk_gc(void); static herr_t H5FL_blk_gc_list(H5FL_blk_head_t *head); -static herr_t H5FL_blk_unlink(H5FL_blk_head_t *pq); - -/* Declare a free list to manage the H5FL_fac_head_t struct */ -H5FL_DEFINE(H5FL_fac_head_t); +static herr_t H5FL_fac_gc(void); +static herr_t H5FL_fac_gc_list(H5FL_fac_head_t *head); /* Declare a free list to manage the H5FL_blk_node_t struct */ H5FL_DEFINE(H5FL_blk_node_t); +/* Declare a free list to manage the H5FL_fac_gc_node_t struct */ +H5FL_DEFINE(H5FL_fac_gc_node_t); + +/* Declare a free list to manage the H5FL_fac_head_t struct */ +H5FL_DEFINE(H5FL_fac_head_t); + /*-------------------------------------------------------------------------- NAME @@ -225,15 +261,15 @@ H5FL_reg_init(H5FL_reg_head_t *head) /* Indicate that the free list is initialized */ head->init=1; + /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */ + if(head->size<sizeof(H5FL_reg_node_t)) + head->size=sizeof(H5FL_reg_node_t); + /* Make certain there's room for tracking information, if any */ #ifdef H5FL_TRACK head->size += sizeof(H5FL_track_t); #endif /* H5FL_TRACK */ - /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */ - if(head->size<sizeof(void *)) - head->size=sizeof(void *); - done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FL_reg_init() */ @@ -259,11 +295,13 @@ H5FL_reg_free(H5FL_reg_head_t *head, void *obj) { void *ret_value=NULL; /* Return value */ - FUNC_ENTER_NOAPI(H5FL_reg_free, NULL) + /* NOINIT OK here because this must be called after H5FL_reg_malloc/calloc + * -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_reg_free) /* Double check parameters */ - assert(head); - assert(obj); + HDassert(head); + HDassert(obj); #ifdef H5FL_TRACK { @@ -294,7 +332,7 @@ H5FL_reg_free(H5FL_reg_head_t *head, void *obj) #endif /* H5FL_DEBUG */ /* Make certain that the free list is initialized */ - assert(head->init); + HDassert(head->init); /* Link into the free list */ ((H5FL_reg_node_t *)obj)->next=head->list; @@ -302,16 +340,15 @@ H5FL_reg_free(H5FL_reg_head_t *head, void *obj) /* Point free list at the node freed */ head->list=(H5FL_reg_node_t *)obj; - /* Increment the number of blocks & memory on free list */ + /* Increment the number of blocks on free list */ head->onlist++; - head->list_mem+=head->size; /* Increment the amount of "regular" freed memory globally */ H5FL_reg_gc_head.mem_freed+=head->size; /* Check for exceeding free list memory use limits */ /* First check this particular list */ - if(head->list_mem>H5FL_reg_lst_mem_lim) + if(head->onlist * head->size > H5FL_reg_lst_mem_lim) if(H5FL_reg_gc_list(head)<0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free") @@ -348,7 +385,7 @@ H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_reg_malloc, NULL) /* Double check parameters */ - assert(head); + HDassert(head); /* Make certain the list is initialized first */ if(!head->init) @@ -365,7 +402,6 @@ H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS) /* Decrement the number of blocks & memory on free list */ head->onlist--; - head->list_mem-=head->size; /* Decrement the amount of global "regular" free list memory in use */ H5FL_reg_gc_head.mem_freed-=(head->size); @@ -426,7 +462,7 @@ H5FL_reg_calloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_reg_calloc, NULL) /* Double check parameters */ - assert(head); + HDassert(head); /* Allocate the block */ if (NULL==(ret_value = H5FL_reg_malloc(head H5FL_TRACK_INFO_INT))) @@ -476,17 +512,11 @@ H5FL_reg_gc_list(H5FL_reg_head_t *head) /* Decrement the count of nodes allocated and free the node */ head->allocated--; - /* Decrement count of free memory on this list */ - head->list_mem-=head->size; - - H5MM_xfree(free_list); + H5MM_free(free_list); free_list = (H5FL_reg_node_t *)tmp; } /* end while */ - /* Double check that all the memory on this list is recycled */ - HDassert(0 == head->list_mem); - /* Indicate no free nodes on the free list */ head->list=NULL; head->onlist=0; @@ -535,7 +565,7 @@ H5FL_reg_gc(void) } /* end while */ /* Double check that all the memory on the free lists is recycled */ - assert(H5FL_reg_gc_head.mem_freed==0); + HDassert(H5FL_reg_gc_head.mem_freed==0); done: FUNC_LEAVE_NOAPI(ret_value) @@ -797,7 +827,7 @@ H5FL_blk_free_block_avail(H5FL_blk_head_t *head, size_t size) FUNC_ENTER_NOAPI(H5FL_blk_free_block_avail, FAIL) /* Double check parameters */ - assert(head); + HDassert(head); /* check if there is a free list for blocks of this size */ /* and if there are any blocks available on the list */ @@ -838,8 +868,8 @@ H5FL_blk_malloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_blk_malloc, NULL) /* Double check parameters */ - assert(head); - assert(size); + HDassert(head); + HDassert(size); /* Make certain the list is initialized first */ if(!head->init) @@ -928,8 +958,8 @@ H5FL_blk_calloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_blk_calloc, NULL) /* Double check parameters */ - assert(head); - assert(size); + HDassert(head); + HDassert(size); /* Allocate the block */ if (NULL==(ret_value = H5FL_blk_malloc(head,size H5FL_TRACK_INFO_INT))) @@ -969,11 +999,13 @@ H5FL_blk_free(H5FL_blk_head_t *head, void *block) size_t free_size; /* Size of the block freed */ void *ret_value=NULL; /* Return value */ - FUNC_ENTER_NOAPI(H5FL_blk_free, NULL) + /* NOINIT OK here because this must be called after H5FL_blk_malloc/calloc + * -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_blk_free) /* Double check parameters */ - assert(head); - assert(block); + HDassert(head); + HDassert(block); #ifdef H5FL_TRACK { @@ -1070,8 +1102,8 @@ H5FL_blk_realloc(H5FL_blk_head_t *head, void *block, size_t new_size H5FL_TRACK_ FUNC_ENTER_NOAPI(H5FL_blk_realloc, NULL) /* Double check parameters */ - assert(head); - assert(new_size); + HDassert(head); + HDassert(new_size); /* Check if we are actually re-allocating a block */ if(block!=NULL) { @@ -1119,67 +1151,6 @@ done: } /* end H5FL_blk_realloc() */ -/*-------------------------------------------------------------------------- - NAME - H5FL_blk_unlink - PURPOSE - Remove a block free list from the global list of initialized block free - lists. - USAGE - void H5FL_blk_unlink(H5FL_blk_head_t *pq) - H5FL_blk_head_t *pq; IN: Block free list to remove from global list - RETURNS - Success: Non-negative - Failure: Negative - DESCRIPTION - Search through the global list of initialized block free lists and remove - a particular free list. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5FL_blk_unlink(H5FL_blk_head_t *pq) -{ - H5FL_blk_gc_node_t *last; /* Pointer to the last garbage collection node examined */ - H5FL_blk_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5FL_blk_unlink) - - /* Find the node to remove from the global list */ - last=NULL; - tmp=H5FL_blk_gc_head.first; - while(tmp!=NULL) { - /* Check if the list has allocations outstanding */ - if(tmp->pq==pq) { - /* Unlink node from linked list */ - if(last==NULL) - H5FL_blk_gc_head.first=H5FL_blk_gc_head.first->next; - else - last->next=tmp->next; - - /* Free the block node */ - H5MM_xfree(tmp); - - /* Leave now */ - break; - } /* end if */ - - /* Advance to next node in list */ - last=tmp; - tmp=tmp->next; - } /* end while */ - - if(tmp==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't release block free list") - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FL_blk_unlink() */ - - /*------------------------------------------------------------------------- * Function: H5FL_blk_gc_list * @@ -1221,7 +1192,7 @@ H5FL_blk_gc_list(H5FL_blk_head_t *head) H5FL_blk_gc_head.mem_freed-=head->head->size; /* Free the block */ - H5MM_xfree(list); + H5MM_free(list); list = (H5FL_blk_list_t *)next; } /* end while */ @@ -1279,7 +1250,7 @@ H5FL_blk_gc(void) } /* end while */ /* Double check that all the memory on the free lists are recycled */ - assert(H5FL_blk_gc_head.mem_freed==0); + HDassert(H5FL_blk_gc_head.mem_freed==0); done: FUNC_LEAVE_NOAPI(ret_value) @@ -1334,7 +1305,7 @@ printf("H5FL_blk_term: head->name=%s, head->allocated=%d\n", H5FL_blk_gc_head.fi H5FL_blk_gc_head.first->pq->init=0; /* Free the node from the garbage collection list */ - H5MM_xfree(H5FL_blk_gc_head.first); + H5MM_free(H5FL_blk_gc_head.first); } /* end else */ H5FL_blk_gc_head.first=tmp; @@ -1422,17 +1393,19 @@ H5FL_arr_free(H5FL_arr_head_t *head, void *obj) size_t free_nelem; /* Number of elements in node being free'd */ void *ret_value=NULL; /* Return value */ - FUNC_ENTER_NOAPI(H5FL_arr_free, NULL) + /* NOINIT OK here because this must be called after H5FL_arr_malloc/calloc + * -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_arr_free) /* The H5MM_xfree code allows obj to null */ if (!obj) HGOTO_DONE (NULL) /* Double check parameters */ - assert(head); + HDassert(head); /* Make certain that the free list is initialized */ - assert(head->init); + HDassert(head->init); /* Get the pointer to the info header in front of the block to free */ temp=(H5FL_arr_list_t *)((unsigned char *)obj-sizeof(H5FL_arr_list_t)); /*lint !e826 Pointer-to-pointer cast is appropriate here */ @@ -1441,7 +1414,7 @@ H5FL_arr_free(H5FL_arr_head_t *head, void *obj) free_nelem=temp->nelem; /* Double-check that there is enough room for arrays of this size */ - assert((int)free_nelem<=head->maxelem); + HDassert((int)free_nelem<=head->maxelem); /* Link into the free list */ temp->next=head->list_arr[free_nelem].list; @@ -1500,8 +1473,8 @@ H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem) FUNC_ENTER_NOAPI(H5FL_arr_malloc, NULL) /* Double check parameters */ - assert(head); - assert(elem); + HDassert(head); + HDassert(elem); /* Make certain the list is initialized first */ if(!head->init) @@ -1509,7 +1482,7 @@ H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem) HGOTO_ERROR (H5E_RESOURCE, H5E_CANTINIT, NULL, "can't initialize 'array' blocks") /* Sanity check that the number of elements is supported */ - assert(elem<=(unsigned) head->maxelem); + HDassert(elem<=(unsigned) head->maxelem); /* Get the set of the memory block */ mem_size=head->list_arr[elem].size; @@ -1573,8 +1546,8 @@ H5FL_arr_calloc(H5FL_arr_head_t *head, size_t elem) FUNC_ENTER_NOAPI(H5FL_arr_calloc, NULL) /* Double check parameters */ - assert(head); - assert(elem); + HDassert(head); + HDassert(elem); /* Allocate the array */ if (NULL==(ret_value = H5FL_arr_malloc(head,elem))) @@ -1611,8 +1584,8 @@ H5FL_arr_realloc(H5FL_arr_head_t *head, void * obj, size_t new_elem) FUNC_ENTER_NOAPI(H5FL_arr_realloc, NULL) /* Double check parameters */ - assert(head); - assert(new_elem); + HDassert(head); + HDassert(new_elem); /* Check if we are really allocating the object */ if(obj==NULL) @@ -1621,7 +1594,7 @@ H5FL_arr_realloc(H5FL_arr_head_t *head, void * obj, size_t new_elem) H5FL_arr_list_t *temp; /* Temp. ptr to the new free list node allocated */ /* Sanity check that the number of elements is supported */ - assert((int)new_elem<=head->maxelem); + HDassert((int)new_elem<=head->maxelem); /* Get the pointer to the info header in front of the block to free */ temp=(H5FL_arr_list_t *)((unsigned char *)obj-sizeof(H5FL_arr_list_t)); /*lint !e826 Pointer-to-pointer cast is appropriate here */ @@ -1687,7 +1660,7 @@ H5FL_arr_gc_list(H5FL_arr_head_t *head) /* Decrement the count of nodes allocated and free the node */ head->allocated--; - H5MM_xfree(arr_free_list); + H5MM_free(arr_free_list); arr_free_list = (H5FL_arr_list_t *)tmp; } /* end while */ @@ -1705,7 +1678,7 @@ H5FL_arr_gc_list(H5FL_arr_head_t *head) } /* end for */ /* Double check that all the memory on this list is recycled */ - assert(head->list_mem==0); + HDassert(head->list_mem==0); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5FL_arr_gc_list() */ @@ -1746,7 +1719,7 @@ H5FL_arr_gc(void) } /* end while */ /* Double check that all the memory on the free lists are recycled */ - assert(H5FL_arr_gc_head.mem_freed==0); + HDassert(H5FL_arr_gc_head.mem_freed==0); done: FUNC_LEAVE_NOAPI(ret_value) @@ -1803,7 +1776,7 @@ printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head.fi H5FL_arr_gc_head.first->list->init=0; /* Free the node from the garbage collection list */ - H5MM_xfree(H5FL_arr_gc_head.first); + H5MM_free(H5FL_arr_gc_head.first); } /* end else */ H5FL_arr_gc_head.first=tmp; @@ -1834,14 +1807,16 @@ printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head.fi void * H5FL_seq_free(H5FL_seq_head_t *head, void *obj) { + /* NOINIT OK here because this must be called after H5FL_seq_malloc/calloc + * -NAF */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_seq_free) /* Double check parameters */ - assert(head); - assert(obj); + HDassert(head); + HDassert(obj); /* Make certain that the free list is initialized */ - assert(head->queue.init); + HDassert(head->queue.init); /* Use block routine */ H5FL_blk_free(&(head->queue),obj); @@ -1873,8 +1848,8 @@ H5FL_seq_malloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_seq_malloc, NULL) /* Double check parameters */ - assert(head); - assert(elem); + HDassert(head); + HDassert(elem); /* Use block routine */ ret_value=H5FL_blk_malloc(&(head->queue),head->size*elem H5FL_TRACK_INFO_INT); @@ -1907,8 +1882,8 @@ H5FL_seq_calloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_seq_calloc, NULL) /* Double check parameters */ - assert(head); - assert(elem); + HDassert(head); + HDassert(elem); /* Use block routine */ ret_value=H5FL_blk_calloc(&(head->queue),head->size*elem H5FL_TRACK_INFO_INT); @@ -1941,8 +1916,8 @@ H5FL_seq_realloc(H5FL_seq_head_t *head, void * obj, size_t new_elem H5FL_TRACK_P FUNC_ENTER_NOAPI(H5FL_seq_realloc, NULL) /* Double check parameters */ - assert(head); - assert(new_elem); + HDassert(head); + HDassert(new_elem); /* Use block routine */ ret_value=H5FL_blk_realloc(&(head->queue),obj,head->size*new_elem H5FL_TRACK_INFO_INT); @@ -1964,14 +1939,18 @@ done: * Wednesday, February 2, 2005 * * Modifications: + * Neil Fortner + * Friday, December 19, 2008 + * Totally rewritten to support new factory implementation * *------------------------------------------------------------------------- */ H5FL_fac_head_t * H5FL_fac_init(size_t size) { - H5FL_fac_head_t *factory; /* Pointer to new block factory */ - H5FL_fac_head_t *ret_value; /* Return value */ + H5FL_fac_gc_node_t *new_node; /* Pointer to the node for the new list to garbage collect */ + H5FL_fac_head_t *factory; /* Pointer to new block factory */ + H5FL_fac_head_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5FL_fac_init, NULL) @@ -1979,15 +1958,38 @@ H5FL_fac_init(size_t size) HDassert(size>0); /* Allocate room for the new factory */ - if(NULL==(factory=H5FL_MALLOC(H5FL_fac_head_t))) + if(NULL == (factory = (H5FL_fac_head_t *)H5FL_CALLOC(H5FL_fac_head_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for factory object") - /* Initialize block header information */ - HDmemset(&(factory->queue),0,sizeof(H5FL_blk_head_t)); - /* Set size of blocks for factory */ factory->size=size; + /* Allocate a new garbage collection node */ + if(NULL == (new_node = (H5FL_fac_gc_node_t *)H5FL_MALLOC(H5FL_fac_gc_node_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Initialize the new garbage collection node */ + new_node->list = factory; + + /* Link in to the garbage collection list */ + new_node->next=H5FL_fac_gc_head.first; + H5FL_fac_gc_head.first=new_node; + if(new_node->next) + new_node->next->list->prev_gc=new_node; + /* The new factory's prev_gc field will be set to NULL */ + + /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */ + if(factory->size<sizeof(H5FL_fac_node_t)) + factory->size=sizeof(H5FL_fac_node_t); + + /* Make certain there's room for tracking information, if any */ +#ifdef H5FL_TRACK + factory->size += sizeof(H5FL_track_t); +#endif /* H5FL_TRACK */ + + /* Indicate that the free list is initialized */ + factory->init=1; + /* Set return value */ ret_value=factory; @@ -2001,32 +2003,86 @@ done: * * Purpose: Release a block back to a factory & put on free list * - * Return: Success: Non-negative - * Failure: Negative + * Return: NULL * * Programmer: Quincey Koziol * Wednesday, February 2, 2005 * * Modifications: + * Neil Fortner + * Friday, December 19, 2008 + * Totally rewritten to support new factory implementation * *------------------------------------------------------------------------- */ void * H5FL_fac_free(H5FL_fac_head_t *head, void *obj) { - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_fac_free) + void *ret_value=NULL; /* Return value */ + + /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_free) /* Double check parameters */ - assert(head); - assert(obj); + HDassert(head); + HDassert(obj); + +#ifdef H5FL_TRACK + { + H5FL_track_t *trk = obj = ((unsigned char *)obj) - sizeof(H5FL_track_t); + + /* Free tracking information about the allocation location */ + H5CS_close_stack(trk->stack); + trk->stack = H5MM_xfree(trk->stack); + trk->file = H5MM_xfree(trk->file); + trk->func = H5MM_xfree(trk->func); + + /* Remove from "outstanding allocations" list */ + if(trk == H5FL_out_head_g) { + H5FL_out_head_g = H5FL_out_head_g->next; + if(H5FL_out_head_g) + H5FL_out_head_g->prev = NULL; + } /* end if */ + else { + trk->prev->next = trk->next; + if(trk->next) + trk->next->prev = trk->prev; + } /* end else */ + } +#endif /* H5FL_TRACK */ + +#ifdef H5FL_DEBUG + HDmemset(obj,255,head->size); +#endif /* H5FL_DEBUG */ /* Make certain that the free list is initialized */ - assert(head->queue.init); + HDassert(head->init); - /* Use block routine */ - H5FL_blk_free(&(head->queue),obj); + /* Link into the free list */ + ((H5FL_fac_node_t *)obj)->next=head->list; - FUNC_LEAVE_NOAPI(NULL) + /* Point free list at the node freed */ + head->list=(H5FL_fac_node_t *)obj; + + /* Increment the number of blocks on free list */ + head->onlist++; + + /* Increment the amount of "factory" freed memory globally */ + H5FL_fac_gc_head.mem_freed+=head->size; + + /* Check for exceeding free list memory use limits */ + /* First check this particular list */ + if(head->onlist * head->size > H5FL_fac_lst_mem_lim) + if(H5FL_fac_gc_list(head)<0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free") + + /* Then check the global amount memory on factory free lists */ + if(H5FL_fac_gc_head.mem_freed > H5FL_fac_glb_mem_lim) + if(H5FL_fac_gc()<0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free") + +done: + FUNC_LEAVE_NOAPI(ret_value) } /* end H5FL_fac_free() */ @@ -2042,6 +2098,9 @@ H5FL_fac_free(H5FL_fac_head_t *head, void *obj) * Wednesday, February 2, 2005 * * Modifications: + * Neil Fortner + * Friday, December 19, 2008 + * Totally rewritten to support new factory implementation * *------------------------------------------------------------------------- */ @@ -2050,13 +2109,54 @@ H5FL_fac_malloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS) { void *ret_value; /* Pointer to object to return */ - FUNC_ENTER_NOAPI(H5FL_fac_malloc, NULL) + /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_malloc) /* Double check parameters */ - assert(head); + HDassert(head); + HDassert(head->init); - /* Use block routine */ - ret_value=H5FL_blk_malloc(&(head->queue),head->size H5FL_TRACK_INFO_INT); + /* Check for nodes available on the free list first */ + if(head->list!=NULL) { + /* Get a pointer to the block on the free list */ + ret_value=(void *)(head->list); + + /* Remove node from free list */ + head->list=head->list->next; + + /* Decrement the number of blocks & memory on free list */ + head->onlist--; + + /* Decrement the amount of global "factory" free list memory in use */ + H5FL_fac_gc_head.mem_freed-=(head->size); + } /* end if */ + /* Otherwise allocate a node */ + else { + if (NULL==(ret_value = H5FL_malloc(head->size))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Increment the number of blocks allocated in list */ + head->allocated++; + } /* end else */ + +#ifdef H5FL_TRACK + /* Copy allocation location information */ + ((H5FL_track_t *)ret_value)->stack = H5MM_calloc(sizeof(H5CS_t)); + H5CS_copy_stack(((H5FL_track_t *)ret_value)->stack); + ((H5FL_track_t *)ret_value)->file = H5MM_strdup(call_file); + ((H5FL_track_t *)ret_value)->func = H5MM_strdup(call_func); + ((H5FL_track_t *)ret_value)->line = call_line; + + /* Add to "outstanding allocations" list */ + ((H5FL_track_t *)ret_value)->prev = NULL; + ((H5FL_track_t *)ret_value)->next = H5FL_out_head_g; + if(H5FL_out_head_g) + H5FL_out_head_g->prev = (H5FL_track_t *)ret_value; + H5FL_out_head_g = (H5FL_track_t *)ret_value; + + /* Adjust for allocation tracking information */ + ret_value = ((unsigned char *)ret_value) + sizeof(H5FL_track_t); +#endif /* H5FL_TRACK */ done: FUNC_LEAVE_NOAPI(ret_value) @@ -2075,6 +2175,9 @@ done: * Wednesday, February 2, 2005 * * Modifications: + * Neil Fortner + * Friday, December 19, 2008 + * Totally rewritten to support new factory implementation * *------------------------------------------------------------------------- */ @@ -2083,17 +2186,115 @@ H5FL_fac_calloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS) { void *ret_value; /* Pointer to object to return */ - FUNC_ENTER_NOAPI(H5FL_fac_calloc, NULL) + /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_calloc) /* Double check parameters */ - assert(head); + HDassert(head); - /* Use block routine */ - ret_value=H5FL_blk_calloc(&(head->queue),head->size H5FL_TRACK_INFO_INT); + /* Allocate the block */ + if (NULL==(ret_value = H5FL_fac_malloc(head H5FL_TRACK_INFO_INT))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Clear to zeros */ + /* (Accomodate tracking information, if present) */ + HDmemset(ret_value,0,head->size - H5FL_TRACK_SIZE); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FL_fac_calloc() */ + +/*------------------------------------------------------------------------- + * Function: H5FL_fac_gc_list + * + * Purpose: Garbage collect on a particular factory free list + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Neil Fortner + * Friday, December 19, 2008 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FL_fac_gc_list(H5FL_fac_head_t *head) +{ + H5FL_fac_node_t *free_list; /* Pointer to nodes in free list being garbage collected */ + void *tmp; /* Temporary node pointer */ + size_t total_mem; /* Total memory used on list */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_fac_gc_list) + + /* Calculate the total memory used on this list */ + total_mem=head->onlist*head->size; + + /* For each free list being garbage collected, walk through the nodes and free them */ + free_list=head->list; + while(free_list!=NULL) { + tmp=free_list->next; + + /* Decrement the count of nodes allocated and free the node */ + head->allocated--; + + H5MM_free(free_list); + + free_list = (H5FL_fac_node_t *)tmp; + } /* end while */ + + /* Indicate no free nodes on the free list */ + head->list=NULL; + head->onlist=0; + + /* Decrement global count of free memory on "factory" lists */ + H5FL_fac_gc_head.mem_freed-=total_mem; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FL_fac_gc_list() */ + + +/*------------------------------------------------------------------------- + * Function: H5FL_fac_gc + * + * Purpose: Garbage collect on all the factory free lists + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Neil Fortner + * Friday, December 19, 2008 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FL_fac_gc(void) +{ + H5FL_fac_gc_node_t *gc_node; /* Pointer into the list of things to garbage collect */ + herr_t ret_value=SUCCEED; /* return value*/ + + FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_gc) + + /* Walk through all the free lists, free()'ing the nodes */ + gc_node=H5FL_fac_gc_head.first; + while(gc_node!=NULL) { + /* Release the free nodes on the list */ + if(H5FL_fac_gc_list(gc_node->list)<0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of list failed") + + /* Go on to the next free list to garbage collect */ + gc_node=gc_node->next; + } /* end while */ + + /* Double check that all the memory on the free lists is recycled */ + HDassert(H5FL_fac_gc_head.mem_freed==0); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FL_fac_gc() */ /*------------------------------------------------------------------------- @@ -2108,29 +2309,50 @@ done: * Wednesday, February 2, 2005 * * Modifications: + * Neil Fortner + * Friday, December 19, 2008 + * Totally rewritten to support new factory implementation * *------------------------------------------------------------------------- */ herr_t H5FL_fac_term(H5FL_fac_head_t *factory) { - herr_t ret_value=SUCCEED; /* Return value */ + H5FL_fac_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */ + herr_t ret_value = SUCCEED; /* Return value */ + /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */ FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_term) /* Sanity check */ HDassert(factory); /* Garbage collect all the blocks in the factory's free list */ - if(H5FL_blk_gc_list(&(factory->queue))<0) + if(H5FL_fac_gc_list(factory)<0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of factory failed") /* Verify that all the blocks have been freed */ - if(factory->queue.allocated>0) + if(factory->allocated>0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "factory still has objects allocated") /* Unlink block free list for factory from global free list */ - H5FL_blk_unlink(&(factory->queue)); + if(factory->prev_gc) { + H5FL_fac_gc_node_t *last = factory->prev_gc; /* Garbage collection node before the one being removed */ + + HDassert(last->next->list == factory); + tmp = last->next->next; + (void)H5FL_FREE(H5FL_fac_gc_node_t, last->next); + last->next = tmp; + if(tmp) + tmp->list->prev_gc = last; + } else { + HDassert(H5FL_fac_gc_head.first->list == factory); + tmp = H5FL_fac_gc_head.first->next; + (void)H5FL_FREE(H5FL_fac_gc_node_t, H5FL_fac_gc_head.first); + H5FL_fac_gc_head.first = tmp; + if(tmp) + tmp->list->prev_gc = NULL; + } /* end else */ /* Free factory info */ (void)H5FL_FREE(H5FL_fac_head_t, factory); @@ -2141,6 +2363,52 @@ done: /*------------------------------------------------------------------------- + * Function: H5FL_fac_term_all + * + * Purpose: Terminate all block factories + * + * Return: 0. There should never be any outstanding allocations + * when this is called. + * + * Programmer: Neil Fortner + * Friday, December 19, 2008 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +H5FL_fac_term_all(void) +{ + H5FL_fac_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_fac_term_all) + + /* Free the nodes on the garbage collection list */ + while(H5FL_fac_gc_head.first != NULL) { + tmp=H5FL_fac_gc_head.first->next; + +#ifdef H5FL_DEBUG +printf("H5FL_fac_term: head->size=%d, head->allocated=%d\n", (int)H5FL_fac_gc_head.first->list->size,(int)H5FL_fac_gc_head.first->list->allocated); +#endif /* H5FL_DEBUG */ + + /* The list cannot have any allocations outstanding */ + HDassert(H5FL_fac_gc_head.first->list->allocated == 0); + + /* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */ + H5FL_fac_gc_head.first->list->init = 0; + + /* Free the node from the garbage collection list */ + (void)H5FL_FREE(H5FL_fac_gc_node_t, H5FL_fac_gc_head.first); + + H5FL_fac_gc_head.first = tmp; + } /* end while */ + + FUNC_LEAVE_NOAPI(0) +} /* end H5FL_fac_term_all() */ + + +/*------------------------------------------------------------------------- * Function: H5FL_garbage_coll * * Purpose: Garbage collect on all the free lists @@ -2160,7 +2428,7 @@ H5FL_garbage_coll(void) { herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI_NOINIT(H5FL_garbage_coll) + FUNC_ENTER_NOAPI(H5FL_garbage_coll, FAIL) /* Garbage collect the free lists for array objects */ if(H5FL_arr_gc()<0) @@ -2174,6 +2442,10 @@ H5FL_garbage_coll(void) if(H5FL_reg_gc()<0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect regular objects") + /* Garbage collect the free lists for factory objects */ + if(H5FL_fac_gc()<0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect regular objects") + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FL_garbage_coll() */ @@ -2204,13 +2476,16 @@ done: * Programmer: Quincey Koziol * Wednesday, August 2, 2000 * - * Modifications: + * Modifications: Neil Fortner + * Wednesday, April 8, 2009 + * Added support for factory free lists * *------------------------------------------------------------------------- */ herr_t H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim, - int arr_list_lim, int blk_global_lim, int blk_list_lim) + int arr_list_lim, int blk_global_lim, int blk_list_lim, int fac_global_lim, + int fac_list_lim) { herr_t ret_value = SUCCEED; @@ -2229,6 +2504,10 @@ H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_l H5FL_blk_glb_mem_lim=(blk_global_lim==-1 ? UINT_MAX : (size_t)blk_global_lim); /* limit on each block free list */ H5FL_blk_lst_mem_lim=(blk_list_lim==-1 ? UINT_MAX : (size_t)blk_list_lim); + /* limit on all factory free lists */ + H5FL_fac_glb_mem_lim=(fac_global_lim==-1 ? UINT_MAX : (size_t)fac_global_lim); + /* limit on each factory free list */ + H5FL_fac_lst_mem_lim=(fac_list_lim==-1 ? UINT_MAX : (size_t)fac_list_lim); done: FUNC_LEAVE_NOAPI(ret_value) @@ -2264,7 +2543,7 @@ H5FL_term_interface(void) /* Garbage collect any nodes on the free lists */ (void)H5FL_garbage_coll(); - ret_value=H5FL_reg_term()+H5FL_arr_term()+H5FL_blk_term(); + ret_value=H5FL_reg_term()+H5FL_fac_term_all()+H5FL_arr_term()+H5FL_blk_term(); #ifdef H5FL_TRACK /* If we haven't freed all the allocated memory, dump out the list now */ diff --git a/src/H5FLprivate.h b/src/H5FLprivate.h index a799dc4..c1a865a 100644 --- a/src/H5FLprivate.h +++ b/src/H5FLprivate.h @@ -100,7 +100,6 @@ typedef struct H5FL_reg_head_t { unsigned init; /* Whether the free list has been initialized */ unsigned allocated; /* Number of blocks allocated */ unsigned onlist; /* Number of blocks on free list */ - size_t list_mem; /* Amount of memory on free list */ const char *name; /* Name of the type */ size_t size; /* Size of the blocks in the list */ H5FL_reg_node_t *list; /* List of free blocks */ @@ -112,7 +111,7 @@ typedef struct H5FL_reg_head_t { #define H5FL_REG_NAME(t) H5_##t##_reg_free_list #ifndef H5_NO_REG_FREE_LISTS /* Common macros for H5FL_DEFINE & H5FL_DEFINE_STATIC */ -#define H5FL_DEFINE_COMMON(t) H5FL_reg_head_t H5FL_REG_NAME(t)={0,0,0,0,#t,sizeof(t),NULL} +#define H5FL_DEFINE_COMMON(t) H5FL_reg_head_t H5FL_REG_NAME(t)={0,0,0,#t,sizeof(t),NULL} /* Declare a free list to manage objects of type 't' */ #define H5FL_DEFINE(t) H5_DLL H5FL_DEFINE_COMMON(t) @@ -349,11 +348,8 @@ typedef struct H5FL_seq_head_t { #define H5FL_SEQ_REALLOC(t,obj,new_elem) (t *)H5MM_realloc(obj,(new_elem)*sizeof(t)) #endif /* H5_NO_SEQ_FREE_LISTS */ -/* Data structure for free list block factory */ -typedef struct H5FL_fac_head_t { - H5FL_blk_head_t queue; /* Priority queue of blocks */ - size_t size; /* Size of the blocks managed */ -} H5FL_fac_head_t; +/* Forward declaration of the data structure for free list block factory */ +typedef struct H5FL_fac_head_t H5FL_fac_head_t; /* * Macros for defining & using free list factories @@ -381,30 +377,42 @@ typedef struct H5FL_fac_head_t { /* * Library prototypes. */ + /* Block free lists */ H5_DLL void * H5FL_blk_malloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS); H5_DLL void * H5FL_blk_calloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS); H5_DLL void * H5FL_blk_free(H5FL_blk_head_t *head, void *block); H5_DLL void * H5FL_blk_realloc(H5FL_blk_head_t *head, void *block, size_t new_size H5FL_TRACK_PARAMS); H5_DLL htri_t H5FL_blk_free_block_avail(H5FL_blk_head_t *head, size_t size); + +/* Regular free lists */ H5_DLL void * H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS); H5_DLL void * H5FL_reg_calloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS); H5_DLL void * H5FL_reg_free(H5FL_reg_head_t *head, void *obj); + +/* Array free lists */ H5_DLL void * H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem); H5_DLL void * H5FL_arr_calloc(H5FL_arr_head_t *head, size_t elem); H5_DLL void * H5FL_arr_free(H5FL_arr_head_t *head, void *obj); H5_DLL void * H5FL_arr_realloc(H5FL_arr_head_t *head, void *obj, size_t new_elem); + +/* Sequence free lists */ H5_DLL void * H5FL_seq_malloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS); H5_DLL void * H5FL_seq_calloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS); H5_DLL void * H5FL_seq_free(H5FL_seq_head_t *head, void *obj); H5_DLL void * H5FL_seq_realloc(H5FL_seq_head_t *head, void *obj, size_t new_elem H5FL_TRACK_PARAMS); + +/* Factory free lists */ H5_DLL H5FL_fac_head_t *H5FL_fac_init(size_t size); H5_DLL void * H5FL_fac_malloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS); H5_DLL void * H5FL_fac_calloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS); H5_DLL void * H5FL_fac_free(H5FL_fac_head_t *head, void *obj); H5_DLL herr_t H5FL_fac_term(H5FL_fac_head_t *head); + +/* General free list routines */ H5_DLL herr_t H5FL_garbage_coll(void); H5_DLL herr_t H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim, - int arr_global_lim, int arr_list_lim, int blk_global_lim, int blk_list_lim); + int arr_global_lim, int arr_list_lim, int blk_global_lim, int blk_list_lim, + int fac_global_lim, int fac_list_lim); H5_DLL int H5FL_term_interface(void); #endif @@ -82,7 +82,7 @@ H5FO_create(const H5F_t *f) assert(f->shared); /* Create container used to store open object info */ - if((f->shared->open_objs = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)16)) == NULL) + if((f->shared->open_objs = H5SL_create(H5SL_TYPE_HADDR)) == NULL) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to create open object container") done: @@ -400,7 +400,7 @@ H5FO_top_create(H5F_t *f) HDassert(f); /* Create container used to store open object info */ - if((f->obj_count = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)16)) == NULL) + if((f->obj_count = H5SL_create(H5SL_TYPE_HADDR)) == NULL) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to create open object container") done: diff --git a/src/H5FSsection.c b/src/H5FSsection.c index 42c0f86..77e6d1a 100644 --- a/src/H5FSsection.c +++ b/src/H5FSsection.c @@ -45,9 +45,6 @@ /* Default starting size of section buffer */ #define H5FS_SINFO_SIZE_DEFAULT 64 -/* Max. height of the skip list holding free list nodes */ -#define H5FS_DEFAULT_SKIPLIST_HEIGHT 16 - /******************/ /* Local Typedefs */ @@ -962,7 +959,7 @@ HDfprintf(stderr, "%s: sect->size = %Hu, sect->addr = %a\n", FUNC, sect->size, s bin = H5V_log2_gen(sect->size); HDassert(bin < sinfo->nbins); if(sinfo->bins[bin].bin_list == NULL) { - if(NULL == (sinfo->bins[bin].bin_list = H5SL_create(H5SL_TYPE_HSIZE, 0.5, (size_t)H5FS_DEFAULT_SKIPLIST_HEIGHT))) + if(NULL == (sinfo->bins[bin].bin_list = H5SL_create(H5SL_TYPE_HSIZE))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for free space nodes") } /* end if */ else { @@ -979,7 +976,7 @@ HDfprintf(stderr, "%s: sect->size = %Hu, sect->addr = %a\n", FUNC, sect->size, s /* Initialize the free list size node */ fspace_node->sect_size = sect->size; fspace_node->serial_count = fspace_node->ghost_count = 0; - if(NULL == (fspace_node->sect_list = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)H5FS_DEFAULT_SKIPLIST_HEIGHT))) + if(NULL == (fspace_node->sect_list = H5SL_create(H5SL_TYPE_HADDR))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for free space nodes") /* Insert new free space size node into bin's list */ @@ -1058,7 +1055,7 @@ H5FS_sect_link_rest(H5FS_t *fspace, const H5FS_section_class_t *cls, HDfprintf(stderr, "%s: inserting object into merge list, sect->type = %u\n", FUNC, (unsigned)sect->type); #endif /* QAK */ if(fspace->sinfo->merge_list == NULL) - if(NULL == (fspace->sinfo->merge_list = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)H5FS_DEFAULT_SKIPLIST_HEIGHT))) + if(NULL == (fspace->sinfo->merge_list = H5SL_create(H5SL_TYPE_HADDR))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for merging free space sections") if(H5SL_insert(fspace->sinfo->merge_list, sect, §->addr) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into merging skip list") @@ -2101,7 +2098,7 @@ HDfprintf(stderr, "%s: to_mergable = %u\n", FUNC, to_mergable); HDfprintf(stderr, "%s: inserting object into merge list, sect->type = %u\n", FUNC, (unsigned)sect->type); #endif /* QAK */ if(fspace->sinfo->merge_list == NULL) - if(NULL == (fspace->sinfo->merge_list = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)H5FS_DEFAULT_SKIPLIST_HEIGHT))) + if(NULL == (fspace->sinfo->merge_list = H5SL_create(H5SL_TYPE_HADDR))) HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, FAIL, "can't create skip list for merging free space sections") if(H5SL_insert(fspace->sinfo->merge_list, sect, §->addr) < 0) HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space node into merging skip list") diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index 4080705..49af73e 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -158,7 +158,8 @@ typedef struct H5F_file_t { int ncwfs; /* Num entries on cwfs list */ struct H5HG_heap_t **cwfs; /* Global heap cache */ struct H5G_t *root_grp; /* Open root group */ - H5G_entry_t *root_ent; /* Root group symbol table entry */ + H5G_entry_t *root_ent; /* Root group symbol table entry */ + haddr_t root_addr; /* Root group address */ H5FO_t *open_objs; /* Open objects in file */ H5RC_t *grp_btree_shared; /* Ref-counted group B-tree node info */ @@ -225,7 +226,7 @@ H5_DLL herr_t H5F_mount_count_ids(H5F_t *f, unsigned *nopen_files, unsigned *nop /* Superblock related routines */ H5_DLL herr_t H5F_super_init(H5F_t *f, hid_t dxpl_id); H5_DLL herr_t H5F_super_write(H5F_t *f, hid_t dxpl_id); -H5_DLL herr_t H5F_super_read(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc); +H5_DLL herr_t H5F_super_read(H5F_t *f, hid_t dxpl_id); H5_DLL herr_t H5F_super_ext_size(H5F_t *f, hid_t dxpl_id, hsize_t *super_ext_info); /* Metadata accumulator routines */ @@ -247,6 +248,7 @@ H5_DLL herr_t H5F_sfile_remove(H5F_file_t *shared); #ifdef H5F_TESTING H5_DLL herr_t H5F_get_sohm_mesg_count_test(hid_t fid, unsigned type_id, size_t *mesg_count); +H5_DLL herr_t H5F_check_cached_stab_test(hid_t file_id); #endif /* H5F_TESTING */ #endif /* _H5Fpkg_H */ diff --git a/src/H5Fsuper.c b/src/H5Fsuper.c index 8040554..32541ae 100644 --- a/src/H5Fsuper.c +++ b/src/H5Fsuper.c @@ -32,6 +32,7 @@ #include "H5FDprivate.h" /* File drivers */ #include "H5Iprivate.h" /* IDs */ #include "H5MFprivate.h" /* File memory management */ +#include "H5MMprivate.h" /* Memory management */ #include "H5Pprivate.h" /* Property lists */ #include "H5SMprivate.h" /* Shared Object Header Messages */ @@ -230,7 +231,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5F_super_read(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc) +H5F_super_read(H5F_t *f, hid_t dxpl_id) { uint8_t sbuf[H5F_MAX_SUPERBLOCK_SIZE]; /* Buffer for superblock */ H5P_genplist_t *c_plist; /* File creation property list */ @@ -383,8 +384,9 @@ H5F_super_read(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc) H5F_addr_decode(f, (const uint8_t **)&p, &shared->extension_addr/*out*/); H5F_addr_decode(f, (const uint8_t **)&p, &stored_eoa/*out*/); H5F_addr_decode(f, (const uint8_t **)&p, &shared->driver_addr/*out*/); - if(H5G_obj_ent_decode(f, (const uint8_t **)&p, root_loc->oloc/*out*/, - &shared->root_ent/*out*/) < 0) + + /* Decode the symbol table entry */ + if(H5G_root_ent_decode(f, (const uint8_t **)&p) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to read root symbol entry") /* @@ -468,7 +470,6 @@ H5F_super_read(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc) } /* end if */ } /* end if */ else { - haddr_t root_addr; /* Address of root group */ uint32_t computed_chksum; /* Computed checksum */ uint32_t read_chksum; /* Checksum read from file */ @@ -499,7 +500,7 @@ H5F_super_read(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc) H5F_addr_decode(f, (const uint8_t **)&p, &shared->base_addr/*out*/); H5F_addr_decode(f, (const uint8_t **)&p, &shared->extension_addr/*out*/); H5F_addr_decode(f, (const uint8_t **)&p, &stored_eoa/*out*/); - H5F_addr_decode(f, (const uint8_t **)&p, &root_addr/*out*/); + H5F_addr_decode(f, (const uint8_t **)&p, &shared->root_addr/*out*/); /* Compute checksum for superblock */ computed_chksum = H5_checksum_metadata(sbuf, (size_t)(p - sbuf), 0); @@ -511,11 +512,6 @@ H5F_super_read(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc) if(read_chksum != computed_chksum) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "bad checksum on driver information block") - /* Create root group object location */ - H5O_loc_reset(root_loc->oloc); - root_loc->oloc->file = f; - root_loc->oloc->addr = root_addr; - /* * Check if superblock address is different from base address and * adjust base address and "end of address" address if so. @@ -930,7 +926,9 @@ H5F_super_write(H5F_t *f, hid_t dxpl_id) rel_eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_SUPER); H5F_addr_encode(f, &p, (rel_eoa + f->shared->base_addr)); H5F_addr_encode(f, &p, f->shared->driver_addr); - if(H5G_obj_ent_encode(f, &p, H5G_oloc(f->shared->root_grp)) < 0) + + /* Encode the root group object entry, including the cached stab info */ + if(H5G_root_ent_encode(f, &p) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to encode root group information") /* Encode the driver information block. */ diff --git a/src/H5Ftest.c b/src/H5Ftest.c index 1d7e514..8cbc133 100644 --- a/src/H5Ftest.c +++ b/src/H5Ftest.c @@ -32,6 +32,8 @@ #define H5F_TESTING /*suppress warning about H5F testing funcs*/ #define H5SM_PACKAGE /*suppress error about including H5SMpkg */ #define H5SM_TESTING /*suppress warning about H5SM testing funcs*/ +#define H5G_PACKAGE /*suppress error about including H5Gpkg */ +#define H5G_TESTING /*suppress warning about H5G testing funcs*/ /***********/ @@ -40,6 +42,7 @@ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fpkg.h" /* File access */ +#include "H5Gpkg.h" /* Groups */ #include "H5Iprivate.h" /* IDs */ #include "H5SMpkg.h" /* Shared object header messages */ @@ -113,3 +116,40 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5F_get_sohm_mesg_count_test() */ + +/*------------------------------------------------------------------------- + * Function: H5F_check_cached_stab_test + * + * Purpose: Check that a file's superblock contains a cached symbol + * table entry, that the entry matches that in the root + * group's object header, and check that the addresses are + * valid. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Neil Fortner + * Mar 31, 2009 + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_check_cached_stab_test(hid_t file_id) +{ + H5F_t *file; /* File info */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5F_check_cached_stab_test) + + /* Check arguments */ + if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") + + /* Verify the cached stab info */ + if(H5G_verify_cached_stab_test(H5G_oloc(file->shared->root_grp), file->shared->root_ent) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to verify cached symbol table info") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F_check_cached_stab_test() */ + @@ -817,141 +817,6 @@ H5G_term_interface(void) /*------------------------------------------------------------------------- - * Function: H5G_mkroot - * - * Purpose: Creates a root group in an empty file and opens it. If a - * root group is already open then this function immediately - * returns. If ENT is non-null then it's the symbol table - * entry for an existing group which will be opened as the root - * group. Otherwise a new root group is created and then - * opened. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 11 1997 - * - *------------------------------------------------------------------------- - */ -herr_t -H5G_mkroot(H5F_t *f, hid_t dxpl_id, H5G_loc_t *loc) -{ - H5O_loc_t new_root_oloc; /* New root object location */ - H5G_name_t new_root_path; /* New root path */ - H5G_loc_t new_root_loc; /* New root location information */ - H5G_loc_t root_loc; /* Root location information */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5G_mkroot, FAIL) - - /* check args */ - HDassert(f); - - /* Check if the root group is already initialized */ - if(f->shared->root_grp) - HGOTO_DONE(SUCCEED) - - /* Create information needed for group nodes */ - if(H5G_node_init(f) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group node info") - - /* - * If there is no root object then create one. The root group always starts - * with a hard link count of one since it's pointed to by the superblock. - */ - if(loc == NULL) { - H5P_genplist_t *fc_plist; /* File creation property list */ - H5O_ginfo_t ginfo; /* Group info parameters */ - H5O_linfo_t linfo; /* Link info parameters */ - - /* Get the file creation property list */ - /* (Which is a sub-class of the group creation property class) */ - if(NULL == (fc_plist = (H5P_genplist_t *)H5I_object(f->shared->fcpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list") - - /* Get the group info property */ - if(H5P_get(fc_plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get group info") - - /* Get the link info property */ - if(H5P_get(fc_plist, H5G_CRT_LINK_INFO_NAME, &linfo) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get link info") - - /* Set up group location for root group */ - new_root_loc.oloc = &new_root_oloc; - new_root_loc.path = &new_root_path; - H5G_loc_reset(&new_root_loc); - loc = &new_root_loc; - - /* Create root group */ - if(H5G_obj_create(f, dxpl_id, &ginfo, &linfo, f->shared->fcpl_id, loc->oloc/*out*/) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group entry") - if(1 != H5O_link(loc->oloc, 1, dxpl_id)) - HGOTO_ERROR(H5E_SYM, H5E_LINKCOUNT, FAIL, "internal error (wrong link count)") - } /* end if */ - else { - /* - * Open the root object as a group. - */ - if(H5O_open(loc->oloc) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open root group") - -#ifndef H5_STRICT_FORMAT_CHECKS - /* If symbol table information is cached, check if we should replace the - * symbol table message with the cached symbol table information */ - if((H5F_INTENT(f) & H5F_ACC_RDWR) && f->shared->root_ent - && (f->shared->root_ent->type == H5G_CACHED_STAB)) { - H5O_stab_t cached_stab; - - /* Retrieve the cached symbol table information */ - cached_stab.btree_addr = f->shared->root_ent->cache.stab.btree_addr; - cached_stab.heap_addr = f->shared->root_ent->cache.stab.heap_addr; - - /* Check if the symbol table message is valid, and replace with the - * cached symbol table if necessary */ - if(H5G_stab_valid(loc->oloc, dxpl_id, &cached_stab) < 0) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to verify symbol table") - } /* end if */ -#endif /* H5_STRICT_FORMAT_CHECKS */ - } /* end else */ - - /* Create the path names for the root group's entry */ - H5G_name_init(loc->path, "/"); - - /* - * Create the group pointer. Also decrement the open object count so we - * don't count the root group as an open object. The root group will - * never be closed. - */ - if(NULL == (f->shared->root_grp = H5FL_CALLOC(H5G_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - if(NULL == (f->shared->root_grp->shared = H5FL_CALLOC(H5G_shared_t))) { - (void)H5FL_FREE(H5G_t, f->shared->root_grp); - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") - } /* end if */ - - /* Shallow copy (take ownership) of the group object info */ - root_loc.oloc = &(f->shared->root_grp->oloc); - root_loc.path = &(f->shared->root_grp->path); - if(H5G_loc_copy(&root_loc, loc, H5_COPY_SHALLOW) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, FAIL, "can't copy group object location") - - f->shared->root_grp->shared->fo_count = 1; - /* The only other open object should be the superblock extension, if it - * exists. Don't count either the superblock extension or the root group - * in the number of open objects in the file. - */ - HDassert((1 == f->nopen_objs) || - (2 == f->nopen_objs && HADDR_UNDEF != f->shared->extension_addr)); - f->nopen_objs--; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5G_mkroot() */ - - -/*------------------------------------------------------------------------- * Function: H5G_create * * Purpose: Creates a new empty group with the specified name. The name @@ -1351,36 +1216,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5G_rootof - * - * Purpose: Return a pointer to the root group of the file. If the file - * is part of a virtual file then the root group of the virtual - * file is returned. - * - * Return: Success: Ptr to the root group of the file. Do not - * free the pointer -- it points directly into - * the file struct. - * - * Failure: NULL - * - * Programmer: Robb Matzke - * Tuesday, October 13, 1998 - * - *------------------------------------------------------------------------- - */ -H5G_t * -H5G_rootof(H5F_t *f) -{ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_rootof) - - while(f->parent) - f = f->parent; - - FUNC_LEAVE_NOAPI(f->shared->root_grp) -} /* end H5G_rootof() */ - - -/*------------------------------------------------------------------------- * Function: H5G_oloc * * Purpose: Returns a pointer to the object location for a group. @@ -1975,7 +1810,7 @@ H5G_visit(hid_t loc_id, const char *group_name, H5_index_t idx_type, udata.curr_path_len = 0; /* Create skip list to store visited object information */ - if((udata.visited = H5SL_create(H5SL_TYPE_OBJ, 0.5, (size_t)16)) == NULL) + if((udata.visited = H5SL_create(H5SL_TYPE_OBJ)) == NULL) HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create skip list for visited objects") /* Get the group's reference count and type */ diff --git a/src/H5Gobj.c b/src/H5Gobj.c index 2eb1924..08a9268 100644 --- a/src/H5Gobj.c +++ b/src/H5Gobj.c @@ -221,115 +221,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5G_obj_ent_decode - * - * Purpose: Decodes a symbol table entry into a object location - * - * Return: Success: Non-negative with *pp pointing to the first byte - * following the symbol table entry. - * - * Failure: Negative - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Sep 26 2005 - * - *------------------------------------------------------------------------- - */ -herr_t -H5G_obj_ent_decode(H5F_t *f, const uint8_t **pp, H5O_loc_t *oloc, H5G_entry_t **entp) -{ - const uint8_t *p_ret = *pp; - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5G_obj_ent_decode, FAIL) - - /* check arguments */ - HDassert(f); - HDassert(pp); - HDassert(oloc); - - if(entp) { - /* If entp is not NULL we allocate space for the symbol table entry and - * decode the entire entry. */ - if(!(*entp)) /* Only allocate space if *entp is NULL */ - if(NULL == (*entp = (H5G_entry_t *) H5MM_calloc(sizeof(H5G_entry_t)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate space for symbol table entry") - if(H5G_ent_decode_vec(f, pp, *entp, 1) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode symbol table entry") - - /* Set oloc to the correct values */ - oloc->file = (*entp)->file; - oloc->addr = (*entp)->header; - } else { - /* Set file pointer for root object location */ - oloc->file = f; - - /* decode header */ - *pp += H5F_SIZEOF_SIZE(f); /* Skip over local heap address */ - H5F_addr_decode(f, pp, &(oloc->addr)); - *pp += 4; /* Skip over "cache type" */ - *pp += 4; /* Reserved */ - } - - /* Common oloc settings */ - oloc->holding_file = FALSE; - - /* Set decode pointer */ - *pp = p_ret + H5G_SIZEOF_ENTRY(f); - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5G_obj_ent_decode() */ - - -/*------------------------------------------------------------------------- - * Function: H5G_obj_ent_encode - * - * Purpose: Encodes the specified object location into a symbol table - * entry in the buffer pointed to by *pp. - * - * Return: Success: Non-negative, with *pp pointing to the first byte - * after the symbol table entry. - * - * Failure: Negative - * - * Programmer: Quincey Koziol - * koziol@ncsa.uiuc.edu - * Sep 26 2005 - * - *------------------------------------------------------------------------- - */ -herr_t -H5G_obj_ent_encode(const H5F_t *f, uint8_t **pp, const H5O_loc_t *oloc) -{ - uint8_t *p_ret = *pp + H5G_SIZEOF_ENTRY(f); - - FUNC_ENTER_NOAPI_NOFUNC(H5G_obj_ent_encode) - - /* check arguments */ - HDassert(f); - HDassert(pp); - - /* encode header */ - H5F_ENCODE_LENGTH(f, *pp, 0); /* No name for root group */ - if(oloc) - H5F_addr_encode(f, pp, oloc->addr); - else - H5F_addr_encode(f, pp, HADDR_UNDEF); - UINT32ENCODE(*pp, H5G_NOTHING_CACHED); - UINT32ENCODE(*pp, 0); /*reserved*/ - - /* fill with zero */ - while(*pp < p_ret) - *(*pp)++ = 0; - *pp = p_ret; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5G_obj_ent_encode() */ - - -/*------------------------------------------------------------------------- * Function: H5G_obj_get_linfo * * Purpose: Retrieves the "link info" message for an object. Also diff --git a/src/H5Gpkg.h b/src/H5Gpkg.h index 38c7628..0840ee7 100644 --- a/src/H5Gpkg.h +++ b/src/H5Gpkg.h @@ -340,6 +340,12 @@ H5_DLLVAR const H5B2_class_t H5G_BT2_NAME[1]; /* The v2 B-tree class for indexing 'creation order' field on links */ H5_DLLVAR const H5B2_class_t H5G_BT2_CORDER[1]; +/* Free list for managing H5G_t structs */ +H5FL_EXTERN(H5G_t); + +/* Free list for managing H5G_shared_t structs */ +H5FL_EXTERN(H5G_shared_t); + /******************************/ /* Package Private Prototypes */ /******************************/ @@ -565,6 +571,7 @@ H5_DLL htri_t H5G_is_new_dense_test(hid_t gid); H5_DLL herr_t H5G_new_dense_info_test(hid_t gid, hsize_t *name_count, hsize_t *corder_count); H5_DLL herr_t H5G_lheap_size_test(hid_t gid, size_t *lheap_size); H5_DLL herr_t H5G_user_path_test(hid_t obj_id, char *user_path, size_t *user_path_len, unsigned *user_path_hidden); +H5_DLL herr_t H5G_verify_cached_stab_test(H5O_loc_t *grp_oloc, H5G_entry_t *ent); #endif /* H5G_TESTING */ #endif /* _H5Gpkg_H */ diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h index b1db96f..7f001e0 100644 --- a/src/H5Gprivate.h +++ b/src/H5Gprivate.h @@ -151,7 +151,7 @@ typedef struct H5G_entry_t H5G_entry_t; * Library prototypes... These are the ones that other packages routinely * call. */ -H5_DLL herr_t H5G_mkroot(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc); +H5_DLL herr_t H5G_mkroot(H5F_t *f, hid_t dxpl_id, hbool_t create_root); H5_DLL struct H5O_loc_t *H5G_oloc(H5G_t *grp); H5_DLL H5G_t *H5G_rootof(H5F_t *f); H5_DLL H5G_name_t * H5G_nameof(H5G_t *grp); @@ -181,10 +181,8 @@ H5_DLL herr_t H5G_node_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream /* * These functions operate on group object locations. */ -H5_DLL herr_t H5G_obj_ent_decode(H5F_t *f, const uint8_t **pp, - struct H5O_loc_t *oloc, H5G_entry_t **entp); -H5_DLL herr_t H5G_obj_ent_encode(const H5F_t *f, uint8_t **pp, - const struct H5O_loc_t *oloc); +H5_DLL herr_t H5G_root_ent_decode(H5F_t *f, const uint8_t **pp); +H5_DLL herr_t H5G_root_ent_encode(H5F_t *f, uint8_t **pp); /* * These functions operate on group hierarchy names. diff --git a/src/H5Groot.c b/src/H5Groot.c new file mode 100644 index 0000000..b8a1468 --- /dev/null +++ b/src/H5Groot.c @@ -0,0 +1,368 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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: H5Gobj.c + * Apr 8 2009 + * Neil Fortner <nfortne2@hdfgroup.org> + * + * Purpose: Functions for operating on the root group. + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5F_PACKAGE /*suppress error about including H5Fpkg */ +#define H5G_PACKAGE /*suppress error about including H5Gpkg */ + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fpkg.h" /* File access */ +#include "H5Gpkg.h" /* Groups */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Pprivate.h" /* Property Lists */ + + + +/*------------------------------------------------------------------------- + * Function: H5G_rootof + * + * Purpose: Return a pointer to the root group of the file. If the file + * is part of a virtual file then the root group of the virtual + * file is returned. + * + * Return: Success: Ptr to the root group of the file. Do not + * free the pointer -- it points directly into + * the file struct. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Tuesday, October 13, 1998 + * + *------------------------------------------------------------------------- + */ +H5G_t * +H5G_rootof(H5F_t *f) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_rootof) + + while(f->parent) + f = f->parent; + + FUNC_LEAVE_NOAPI(f->shared->root_grp) +} /* end H5G_rootof() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_root_ent_decode + * + * Purpose: Decodes the root group symbol table entry into the file + * structure, and updates the root group address in the file + * structure. + * + * Return: Success: Non-negative with *pp pointing to the first byte + * following the symbol table entry. + * + * Failure: Negative + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Sep 26 2005 + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_root_ent_decode(H5F_t *f, const uint8_t **pp) +{ + const uint8_t *p_ret = *pp + H5G_SIZEOF_ENTRY(f); + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5G_root_ent_decode, FAIL) + + /* check arguments */ + HDassert(f); + HDassert(pp); + + /* Allocate space for the root group symbol table entry */ + HDassert(!f->shared->root_ent); + if(NULL == (f->shared->root_ent = (H5G_entry_t *) H5MM_calloc(sizeof(H5G_entry_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate space for symbol table entry") + + /* decode the root group symbol table entry */ + if(H5G_ent_decode_vec(f, pp, f->shared->root_ent, 1) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode symbol table entry") + + /* Set the root group address to the correct value */ + f->shared->root_addr = f->shared->root_ent->header; + + /* Set decode pointer */ + *pp = p_ret; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_root_ent_decode() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_root_ent_encode + * + * Purpose: Encodes the root group symbol table entry into the buffer + * pointed to by *pp. + * + * Return: Success: Non-negative, with *pp pointing to the first byte + * after the symbol table entry. + * + * Failure: Negative + * + * Programmer: Quincey Koziol + * koziol@ncsa.uiuc.edu + * Sep 26 2005 + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_root_ent_encode(H5F_t *f, uint8_t **pp) +{ + uint8_t *p_ret = *pp + H5G_SIZEOF_ENTRY(f); + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5G_root_ent_encode, FAIL) + + /* check arguments */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->root_ent); + HDassert(pp); + + /* Encode entry */ + if(H5G_ent_encode_vec(f, pp, f->shared->root_ent, 1) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTENCODE, FAIL, "can't encode symbol table entry") + + /* Set encode pointer */ + *pp = p_ret; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_root_ent_encode() */ + + +/*------------------------------------------------------------------------- + * Function: H5G_mkroot + * + * Purpose: Creates a root group in an empty file and opens it. If a + * root group is already open then this function immediately + * returns. If ENT is non-null then it's the symbol table + * entry for an existing group which will be opened as the root + * group. Otherwise a new root group is created and then + * opened. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 11 1997 + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_mkroot(H5F_t *f, hid_t dxpl_id, hbool_t create_root) +{ + H5G_loc_t root_loc; /* Root location information */ + htri_t stab_exists = -1; /* Whether the symbol table exists */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5G_mkroot, FAIL) + + /* check args */ + HDassert(f); + + /* Check if the root group is already initialized */ + if(f->shared->root_grp) + HGOTO_DONE(SUCCEED) + + /* Create information needed for group nodes */ + if(H5G_node_init(f) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group node info") + + /* + * Create the group pointer + */ + if(NULL == (f->shared->root_grp = H5FL_CALLOC(H5G_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + if(NULL == (f->shared->root_grp->shared = H5FL_CALLOC(H5G_shared_t))) { + (void)H5FL_FREE(H5G_t, f->shared->root_grp); + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + } /* end if */ + + /* Initialize the root_loc structure to point to fields in the newly created + * f->shared->root_grp structure */ + root_loc.oloc = &(f->shared->root_grp->oloc); + root_loc.path = &(f->shared->root_grp->path); + H5G_loc_reset(&root_loc); + + /* + * If there is no root object then create one. The root group always starts + * with a hard link count of one since it's pointed to by the superblock. + */ + if(create_root) { + H5P_genplist_t *fc_plist; /* File creation property list */ + H5O_ginfo_t ginfo; /* Group info parameters */ + H5O_linfo_t linfo; /* Link info parameters */ + unsigned super_vers; /* Superblock version */ + + /* Get the file creation property list */ + /* (Which is a sub-class of the group creation property class) */ + if(NULL == (fc_plist = (H5P_genplist_t *)H5I_object(f->shared->fcpl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list") + + /* Get the group info property */ + if(H5P_get(fc_plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get group info") + + /* Get the link info property */ + if(H5P_get(fc_plist, H5G_CRT_LINK_INFO_NAME, &linfo) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get link info") + + /* Get the superblock version */ + if(H5P_get(fc_plist, H5F_CRT_SUPER_VERS_NAME, &super_vers) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get superblock version") + + /* Create root group */ + if(H5G_obj_create(f, dxpl_id, &ginfo, &linfo, f->shared->fcpl_id, root_loc.oloc/*out*/) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group entry") + if(1 != H5O_link(root_loc.oloc, 1, dxpl_id)) + HGOTO_ERROR(H5E_SYM, H5E_LINKCOUNT, FAIL, "internal error (wrong link count)") + + /* Create the root group symbol table entry */ + HDassert(!f->shared->root_ent); + if(super_vers < HDF5_SUPERBLOCK_VERSION_2) { + /* Allocate space for the root group symbol table entry */ + if(NULL == (f->shared->root_ent = (H5G_entry_t *) H5MM_calloc(sizeof(H5G_entry_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate space for symbol table entry") + + /* Initialize the root group symbol table entry */ + f->shared->root_ent->dirty = TRUE; + f->shared->root_ent->type = H5G_NOTHING_CACHED; /* We will cache the stab later */ + f->shared->root_ent->name_off = 0; /* No name (yet) */ + f->shared->root_ent->header = root_loc.oloc->addr; + f->shared->root_ent->file = root_loc.oloc->file; + } /* end if */ + } /* end if */ + else { + /* Create root group object location from f */ + root_loc.oloc->addr = f->shared->root_addr; + root_loc.oloc->file = f; + + /* + * Open the root object as a group. + */ + if(H5O_open(root_loc.oloc) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open root group") + + /* Actions to take if the symbol table information is cached */ + if(f->shared->root_ent && f->shared->root_ent->type == H5G_CACHED_STAB) { + /* Check for the situation where the symbol table is cached but does + * not exist. This can happen if, for example, an external link is + * added to the root group. */ + if((stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID, dxpl_id)) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists") + + /* Remove the cache if the stab does not exist */ + if(!stab_exists) + f->shared->root_ent->type = H5G_NOTHING_CACHED; +#ifndef H5_STRICT_FORMAT_CHECKS + /* If symbol table information is cached, check if we should replace the + * symbol table message with the cached symbol table information */ + else if(H5F_INTENT(f) & H5F_ACC_RDWR) { + H5O_stab_t cached_stab; + + /* Retrieve the cached symbol table information */ + cached_stab.btree_addr = f->shared->root_ent->cache.stab.btree_addr; + cached_stab.heap_addr = f->shared->root_ent->cache.stab.heap_addr; + + /* Check if the symbol table message is valid, and replace with the + * cached symbol table if necessary */ + if(H5G_stab_valid(root_loc.oloc, dxpl_id, &cached_stab) < 0) + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to verify symbol table") + } /* end if */ +#endif /* H5_STRICT_FORMAT_CHECKS */ + } /* end if */ + } /* end else */ + + /* Cache the root group's symbol table information in the root group symbol + * table entry. It will have been allocated by now if it needs to be + * present, so we don't need to check the superblock version. We do this if + * we have write access, the root entry has been allocated (i.e. + * super_vers < 2) and the stab info is not already cached. */ + if((H5F_INTENT(f) & H5F_ACC_RDWR) && stab_exists != FALSE && f->shared->root_ent + && f->shared->root_ent->type != H5G_CACHED_STAB) { + H5O_stab_t stab; /* Symbol table */ + + /* Check if the stab message exists. It's possible for the root group + * to use the latest version while the superblock is an old version. + * If stab_exists is not -1 then we have already checked. */ + if(stab_exists == -1 && (stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID, dxpl_id)) < 0) + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists") + + if(stab_exists) { + /* Read the root group's symbol table message */ + if(NULL == H5O_msg_read(root_loc.oloc, H5O_STAB_ID, &stab, dxpl_id)) + HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message") + + /* Update the root group symbol table entry */ + f->shared->root_ent->type = H5G_CACHED_STAB; + f->shared->root_ent->cache.stab.btree_addr = stab.btree_addr; + f->shared->root_ent->cache.stab.heap_addr = stab.heap_addr; + } /* end if */ + } /* end if */ + + /* Create the path names for the root group's entry */ + H5G_name_init(root_loc.path, "/"); + + f->shared->root_grp->shared->fo_count = 1; + /* The only other open object should be the superblock extension, if it + * exists. Don't count either the superblock extension or the root group + * in the number of open objects in the file. + */ + HDassert((1 == f->nopen_objs) || + (2 == f->nopen_objs && HADDR_UNDEF != f->shared->extension_addr)); + f->nopen_objs--; + +done: + /* In case of error, free various memory locations that may have been + * allocated */ + if(ret_value < 0) { + if(f->shared->root_grp) { + if(f->shared->root_grp->shared) + f->shared->root_grp->shared = H5FL_FREE(H5G_shared_t, f->shared->root_grp->shared); + f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp); + } /* end if */ + f->shared->root_ent = (H5G_entry_t *) H5MM_xfree(f->shared->root_ent); + H5G_name_free(root_loc.path); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_mkroot() */ + diff --git a/src/H5Gstab.c b/src/H5Gstab.c index c2df8e7..52c9d07 100644 --- a/src/H5Gstab.c +++ b/src/H5Gstab.c @@ -1011,7 +1011,8 @@ H5G_stab_valid(H5O_loc_t *grp_oloc, hid_t dxpl_id, H5O_stab_t *alt_stab) FUNC_ENTER_NOAPI(H5G_stab_valid, FAIL) /* Read the symbol table message */ - H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab, dxpl_id); + if(NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab, dxpl_id)) + HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message"); /* Check if the symbol table message's b-tree address is valid */ if(H5B_valid(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr) < 0) { diff --git a/src/H5Gtest.c b/src/H5Gtest.c index 1f09048..f3508eb 100644 --- a/src/H5Gtest.c +++ b/src/H5Gtest.c @@ -550,3 +550,59 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5G_user_path_test() */ + +/*------------------------------------------------------------------------- + * Function: H5G_verify_cached_stab_test + * + * Purpose: Check that a that the provided group entry contains a + * cached symbol table entry, that the entry matches that in + * the provided group's object header, and check that the + * addresses are valid. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Neil Fortner + * Mar 31, 2009 + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_verify_cached_stab_test(H5O_loc_t *grp_oloc, H5G_entry_t *ent) +{ + H5O_stab_t stab; /* Symbol table */ + H5HL_t *heap = NULL; /* Pointer to local heap */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5G_verify_cached_stab_test) + + /* Verify that stab info is cached in ent */ + if(ent->type != H5G_CACHED_STAB) + HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, "symbol table information is not cached") + + /* Read the symbol table message from the group */ + if(NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab, H5AC_ind_dxpl_id)) + HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message") + + /* Verify that the cached symbol table info matches the symbol table message + * in the object header */ + if((ent->cache.stab.btree_addr != stab.btree_addr) + || (ent->cache.stab.heap_addr != stab.heap_addr)) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "cached stab info does not match object header") + + /* Verify that the btree address is valid */ + if(H5B_valid(grp_oloc->file, H5AC_ind_dxpl_id, H5B_SNODE, stab.btree_addr) < 0) + HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "b-tree address is invalid") + + /* Verify that the heap address is valid */ + if(NULL == (heap = H5HL_protect(grp_oloc->file, H5AC_ind_dxpl_id, stab.heap_addr, H5AC_READ))) + HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "heap address is invalid") + +done: + /* Release resources */ + if(heap && H5HL_unprotect(grp_oloc->file, H5AC_ind_dxpl_id, heap, stab.heap_addr) < 0) + HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5G_verify_cached_stab_test() */ + @@ -1847,40 +1847,35 @@ done: /*------------------------------------------------------------------------- * Function: H5Iis_valid * - * Purpose: Check if the given id is valid. And id is valid if it is in - * use and has an application reference count of at least 1. + * Purpose: Check if the given id is valid. An id is valid if it is in + * use and has an application reference count of at least 1. * - * Return: Success: TRUE if the id is valid, FALSE otherwise. + * Return: Success: TRUE if the id is valid, FALSE otherwise. * - * Failure: Negative (never fails currently) + * Failure: Negative (never fails currently) * * Programmer: Neil Fortner * Friday, October 31, 2008 (boo) * + * Modifications: + * Raymond Lu + * 1 April 2009 (Believe it or not!) + * Moved the argument check down to H5I_find_id because other + * caller functions may pass in some invalid IDs to H5I_find_id. + * It used to do assertion check. *------------------------------------------------------------------------- */ htri_t H5Iis_valid(hid_t id) { - H5I_id_type_t *type_ptr; /* ptr to ID's type */ H5I_id_info_t *id_ptr; /* ptr to the ID */ - H5I_type_t type; /* ID's type */ htri_t ret_value = TRUE; /* Return value */ FUNC_ENTER_API(H5Iis_valid, FAIL) H5TRACE1("t", "i", id); - type = H5I_TYPE(id); - /* Check for conditions that would cause H5I_find_id to throw an assertion */ - if (type <= H5I_BADID || type >= H5I_next_type) - HGOTO_DONE(FALSE); - - type_ptr = H5I_id_type_list_g[type]; - if (!type_ptr || type_ptr->count <= 0) - ret_value = FALSE; - /* Find the ID */ - else if (NULL == (id_ptr = H5I_find_id(id))) + if (NULL == (id_ptr = H5I_find_id(id))) ret_value = FALSE; /* Check if the found id is an internal id */ @@ -2012,7 +2007,9 @@ done: * Programmer: * * Modifications: - * + * Raymond Lu + * 1 April 2009 (Believe it or not!) + * Added argument check, took away assertion check. *------------------------------------------------------------------------- */ static H5I_id_info_t * @@ -2029,10 +2026,12 @@ H5I_find_id(hid_t id) /* Check arguments */ type = H5I_TYPE(id); - HDassert(type > H5I_BADID && type < H5I_next_type); - type_ptr = H5I_id_type_list_g[type]; + if (type <= H5I_BADID || type >= H5I_next_type) + HGOTO_DONE(NULL); - HDassert(type_ptr && type_ptr->count > 0); + type_ptr = H5I_id_type_list_g[type]; + if (!type_ptr || type_ptr->count <= 0) + HGOTO_DONE(NULL); /* Get the bucket in which the ID is located */ hash_loc = (unsigned)H5I_LOC(id, type_ptr->hash_size); @@ -2057,6 +2056,7 @@ H5I_find_id(hid_t id) /* Set the return value */ ret_value = id_ptr; +done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_find_id() */ @@ -82,6 +82,7 @@ typedef struct { const char *dst_name; /* Destination name for moving object */ H5T_cset_t cset; /* Char set for new name */ H5G_loc_t *dst_loc; /* Destination location for moving object */ + unsigned dst_target_flags; /* Target flags for destination object */ hbool_t copy; /* TRUE if this is a copy operation */ hid_t lapl_id; /* LAPL to use in callback */ hid_t dxpl_id; /* DXPL to use in callback */ @@ -285,6 +286,9 @@ H5L_term_interface(void) H5L_table_g = (H5L_class_t *)H5MM_xfree(H5L_table_g); H5L_table_used_g = H5L_table_alloc_g = 0; + /* Mark the interface as uninitialized */ + H5_interface_initialize_g = 0; + FUNC_LEAVE_NOAPI(n) } /* H5L_term_interface() */ @@ -557,6 +561,8 @@ H5Lcreate_ud(hid_t link_loc_id, const char *link_name, H5L_type_t link_type, HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") if(!link_name || !*link_name) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no link name specified") + if(link_type < H5L_TYPE_UD_MIN || link_type > H5L_TYPE_MAX) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid link class") /* Create external link */ if(H5L_create_ud(&link_loc, link_name, udata, udata_size, link_type, lcpl_id, lapl_id, H5AC_dxpl_id) < 0) @@ -2528,7 +2534,8 @@ H5L_move_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t *lnk, orig_name = H5MM_xstrdup(name); /* Insert the link into its new location */ - if(H5G_traverse(udata->dst_loc, udata->dst_name, H5G_TARGET_NORMAL, H5L_move_dest_cb, &udata_out, udata->lapl_id, udata->dxpl_id) < 0) + if(H5G_traverse(udata->dst_loc, udata->dst_name, udata->dst_target_flags, + H5L_move_dest_cb, &udata_out, udata->lapl_id, udata->dxpl_id) < 0) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to follow symbolic link") /* If this is a move and not a copy operation, change the object's name and remove the old link */ @@ -2614,7 +2621,7 @@ H5L_move(H5G_loc_t *src_loc, const char *src_name, H5G_loc_t *dst_loc, const char *dst_name, hbool_t copy_flag, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id) { - unsigned target_flags = H5G_TARGET_MOUNT|H5G_TARGET_SLINK|H5G_TARGET_UDLINK; + unsigned dst_target_flags = H5G_TARGET_NORMAL; H5T_cset_t char_encoding = H5F_DEFAULT_CSET; /* Character encoding for link */ H5P_genplist_t* lc_plist; /* Link creation property list */ H5P_genplist_t* la_plist; /* Link access property list */ @@ -2641,8 +2648,9 @@ H5L_move(H5G_loc_t *src_loc, const char *src_name, H5G_loc_t *dst_loc, if(H5P_get(lc_plist, H5L_CRT_INTERMEDIATE_GROUP_NAME, &crt_intmd_group) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for creating missing groups") + /* Set target flags for source and destination */ if(crt_intmd_group > 0) - target_flags |= H5G_CRT_INTMD_GROUP; + dst_target_flags |= H5G_CRT_INTMD_GROUP; /* Get character encoding property */ if(H5P_get(lc_plist, H5P_STRCRT_CHAR_ENCODING_NAME, &char_encoding) < 0) @@ -2664,13 +2672,15 @@ H5L_move(H5G_loc_t *src_loc, const char *src_name, H5G_loc_t *dst_loc, /* Set up user data */ udata.dst_loc = dst_loc; udata.dst_name= dst_name; + udata.dst_target_flags = dst_target_flags; udata.cset = char_encoding; udata.copy = copy_flag; udata.lapl_id = lapl_copy; udata.dxpl_id = dxpl_id; /* Do the move */ - if(H5G_traverse(src_loc, src_name, target_flags, H5L_move_cb, &udata, lapl_id, dxpl_id) < 0) + if(H5G_traverse(src_loc, src_name, H5G_TARGET_MOUNT | H5G_TARGET_SLINK | H5G_TARGET_UDLINK, + H5L_move_cb, &udata, lapl_id, dxpl_id) < 0) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to find link") done: @@ -2879,7 +2879,7 @@ H5O_visit(hid_t loc_id, const char *obj_name, H5_index_t idx_type, udata.op_data = op_data; /* Create skip list to store visited object information */ - if((udata.visited = H5SL_create(H5SL_TYPE_OBJ, 0.5, (size_t)16)) == NULL) + if((udata.visited = H5SL_create(H5SL_TYPE_OBJ)) == NULL) HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create skip list for visited objects") /* If its ref count is > 1, we add it to the list of visited objects */ diff --git a/src/H5Ocopy.c b/src/H5Ocopy.c index 7b76f3d..2926c6b 100644 --- a/src/H5Ocopy.c +++ b/src/H5Ocopy.c @@ -913,7 +913,7 @@ H5O_copy_header(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, cpy_info.preserve_null = TRUE; /* Create a skip list to keep track of which objects are copied */ - if((cpy_info.map_list = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)16)) == NULL) + if((cpy_info.map_list = H5SL_create(H5SL_TYPE_HADDR)) == NULL) HGOTO_ERROR(H5E_SLIST, H5E_CANTCREATE, FAIL, "cannot make skip list") /* copy the object from the source file to the destination file */ diff --git a/src/H5Opline.c b/src/H5Opline.c index 20a9d26..070ab87 100644 --- a/src/H5Opline.c +++ b/src/H5Opline.c @@ -273,7 +273,7 @@ H5O_pline_encode(H5F_t UNUSED *f, uint8_t *p/*out*/, const void *mesg) name = NULL; } /* end if */ else { - H5Z_class_t *cls; /* Filter class */ + H5Z_class2_t *cls; /* Filter class */ /* * Get the filter name. If the pipeline message has a name in it then @@ -453,7 +453,7 @@ H5O_pline_size(const H5F_t UNUSED *f, const void *mesg) if(pline->version > H5O_PLINE_VERSION_1 && pline->filter[i].id < H5Z_FILTER_RESERVED) name_len = 0; else { - H5Z_class_t *cls; /* Filter class */ + H5Z_class2_t *cls; /* Filter class */ /* Get the name of the filter, same as done with H5O_pline_encode() */ if(NULL == (name = pline->filter[i].name) && (cls = H5Z_find(pline->filter[i].id))) diff --git a/src/H5Pdapl.c b/src/H5Pdapl.c index a4d036d..db66366 100644 --- a/src/H5Pdapl.c +++ b/src/H5Pdapl.c @@ -154,7 +154,7 @@ done: * property list. Each of thhese values can be individually unset * (or not set at all) by passing the macros: * H5D_CHUNK_CACHE_NCHUNKS_DEFAULT, - * H5D_CHUNK_CACHE_NBYTES_DEFAULT, and/or + * H5D_CHUNK_CACHE_NSLOTS_DEFAULT, and/or * H5D_CHUNK_CACHE_W0_DEFAULT * as appropriate. * diff --git a/src/H5Pdcpl.c b/src/H5Pdcpl.c index b2bd71d..853e45d 100644 --- a/src/H5Pdcpl.c +++ b/src/H5Pdcpl.c @@ -1574,7 +1574,7 @@ H5P_get_filter(const H5Z_filter_info_t *filter, unsigned int *flags/*out*/, /* If there's no name on the filter, use the class's filter name */ if(!s) { - H5Z_class_t *cls = H5Z_find(filter->id); + H5Z_class2_t *cls = H5Z_find(filter->id); if(cls) s = cls->name; diff --git a/src/H5Pint.c b/src/H5Pint.c index 799535f..56f1929 100644 --- a/src/H5Pint.c +++ b/src/H5Pint.c @@ -42,8 +42,6 @@ /* Local Macros */ /****************/ -#define H5P_DEFAULT_SKIPLIST_HEIGHT 8 - /******************/ /* Local Typedefs */ @@ -652,11 +650,11 @@ H5P_copy_plist(H5P_genplist_t *old_plist, hbool_t app_ref) new_plist->class_init = 0; /* Initially, wait until the class callback finishes to set */ /* Initialize the skip list to hold the changed properties */ - if((new_plist->props = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + if((new_plist->props = H5SL_create(H5SL_TYPE_STR)) == NULL) HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for changed properties"); /* Create the skip list for deleted properties */ - if((new_plist->del = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + if((new_plist->del = H5SL_create(H5SL_TYPE_STR)) == NULL) HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for deleted properties"); /* Create the skip list to hold names of properties already seen @@ -664,7 +662,7 @@ H5P_copy_plist(H5P_genplist_t *old_plist, hbool_t app_ref) * 'create' callback called, if a property in the class hierarchy has * already been seen) */ - if((seen = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT))== NULL) + if((seen = H5SL_create(H5SL_TYPE_STR))== NULL) HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for seen properties"); nseen = 0; @@ -1462,7 +1460,7 @@ H5P_create_class(H5P_genclass_t *par_class, const char *name, unsigned internal, pclass->revision = H5P_GET_NEXT_REV; /* Get a revision number for the class */ /* Create the skip list for properties */ - if((pclass->props = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + if((pclass->props = H5SL_create(H5SL_TYPE_STR)) == NULL) HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for properties"); /* Set callback functions and pass-along data */ @@ -1544,11 +1542,11 @@ H5P_create(H5P_genclass_t *pclass) plist->class_init = 0; /* Initially, wait until the class callback finishes to set */ /* Create the skip list for changed properties */ - if((plist->props = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + if((plist->props = H5SL_create(H5SL_TYPE_STR)) == NULL) HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for changed properties"); /* Create the skip list for deleted properties */ - if((plist->del = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + if((plist->del = H5SL_create(H5SL_TYPE_STR)) == NULL) HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for deleted properties"); /* Create the skip list to hold names of properties already seen @@ -1556,7 +1554,7 @@ H5P_create(H5P_genclass_t *pclass) * 'create' callback called, if a property in the class hierarchy has * already been seen) */ - if((seen = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + if((seen = H5SL_create(H5SL_TYPE_STR)) == NULL) HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for seen properties"); /* @@ -3147,7 +3145,7 @@ H5P_iterate_plist(hid_t plist_id, int *idx, H5P_iterate_t iter_func, void *iter_ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list"); /* Create the skip list to hold names of properties already seen */ - if((seen = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + if((seen = H5SL_create(H5SL_TYPE_STR)) == NULL) HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for seen properties"); /* Walk through the changed properties in the list */ @@ -4071,7 +4069,7 @@ H5P_close(void *_plist) * 'close' callback called, if a property in the class hierarchy has * already been seen) */ - if((seen = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + if((seen = H5SL_create(H5SL_TYPE_STR)) == NULL) HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for seen properties"); nseen = 0; @@ -16,17 +16,34 @@ /* * Purpose: Provides a skip list abstract data type. * + * (See "Deterministic Skip Lists" by Munro, Papadakis & Sedgewick) + * + * (Implementation changed to a deterministic skip list from a + * probabilistic one. This implementation uses a 1-2-3 skip list + * using arrays, as described by Munro, Papadakis & Sedgewick. + * + * Arrays are allocated using a free list factory for each size + * that is a power of two. Factories are created as soon as they + * are needed, and are never destroyed until the package is shut + * down. There is no longer a maximum level or "p" value. + * -NAF 2008/11/05) + * * (See "Skip Lists: A Probabilistic Alternative to Balanced Trees" * by William Pugh for additional information) * * (This implementation has the optimization for reducing key * key comparisons mentioned in section 3.5 of "A Skip List - * Cookbook" by William Pugh) + * Cookbook" by William Pugh + * -Removed as our implementation of this was useless for a 1-2-3 + * skip list. The implementation in that document hurts + * performance, at least for integer keys. -NAF) * * (Also, this implementation has a couple of home-grown * optimizations, including setting the "update" vector to the * actual 'forward' pointer to update, instead of the node - * containing the forward pointer -QAK) + * containing the forward pointer -QAK + * -No longer uses update vector, as insertions/deletions are now + * always at level 0. -NAF) * * (Note: This implementation does not have the information for * implementing the "Linear List Operations" (like insert/delete/ @@ -36,9 +53,6 @@ * (This implementation has an additional backward pointer, which * allows the list to be iterated in reverse) * - * (We should also look into "Deterministic Skip Lists" (see - * paper by Munro, Papadakis & Sedgewick)) - * * (There's also an article on "Alternating Skip Lists", which * are similar to deterministic skip lists, in the August 2000 * issue of Dr. Dobb's Journal) @@ -54,61 +68,28 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5FLprivate.h" /* Free Lists */ #include "H5SLprivate.h" /* Skip list routines */ +#include "H5MMprivate.h" /* Memory management */ /* Local Macros */ -/* Define the code template for insertions for the "OP" in the H5SL_LOCATE macro */ -#define H5SL_LOCATE_INSERT_FOUND(SLIST, X, UPDATE, I) \ - HGOTO_ERROR(H5E_SLIST, H5E_CANTINSERT, NULL, "can't insert duplicate key") - -/* Define the code template for removals for the "OP" in the H5SL_LOCATE macro */ -/* (NOTE: the code in H5SL_remove_first() is largely the same, fix bugs in both places) */ -#define H5SL_LOCATE_REMOVE_FOUND(SLIST,X,UPDATE,I) \ - void *tmp; \ - \ - for(I=0; I<=(int)SLIST->curr_level; I++) { \ - if(*UPDATE[I]!=X) \ - break; \ - *UPDATE[I]=X->forward[I]; \ - } /* end for */ \ - if(SLIST->last==X) \ - SLIST->last=X->backward; \ - else \ - X->forward[0]->backward=X->backward; \ - tmp=X->item; \ - H5FL_ARR_FREE(H5SL_node_ptr_t,X); \ - while(SLIST->curr_level>0 && SLIST->header->forward[SLIST->curr_level]==NULL) \ - SLIST->curr_level--; \ - SLIST->nobjs--; \ - HGOTO_DONE(tmp); - /* Define the code template for searches for the "OP" in the H5SL_LOCATE macro */ -#define H5SL_LOCATE_SEARCH_FOUND(SLIST, X, UPDATE, I) \ +#define H5SL_LOCATE_SEARCH_FOUND(SLIST, X, I) \ HGOTO_DONE(X->item); /* Define the code template for finds for the "OP" in the H5SL_LOCATE macro */ -#define H5SL_LOCATE_FIND_FOUND(SLIST, X, UPDATE, I) \ +#define H5SL_LOCATE_FIND_FOUND(SLIST, X, I) \ HGOTO_DONE(X); -/* Define a code template for "OP"s that update the "update" vector for the H5SL_LOCATE macro */ -#define H5SL_LOCATE_INSERT_UPDATE(X, UPDATE, I) \ - UPDATE[I] = &X->forward[I]; -#define H5SL_LOCATE_REMOVE_UPDATE(X, UPDATE, I) \ - UPDATE[I] = &X->forward[I]; - -/* Define a code template for "OP"s that _DON'T_ update the "update" vector for the H5SL_LOCATE macro */ -#define H5SL_LOCATE_SEARCH_UPDATE(X, UPDATE, I) -#define H5SL_LOCATE_FIND_UPDATE(X, UPDATE, I) - - /* Define a code template for comparing scalar keys for the "CMP" in the H5SL_LOCATE macro */ #define H5SL_LOCATE_SCALAR_CMP(TYPE, PNODE, PKEY, HASHVAL) \ (*(TYPE *)((PNODE)->key) < *(TYPE *)PKEY) /* Define a code template for comparing string keys for the "CMP" in the H5SL_LOCATE macro */ #define H5SL_LOCATE_STRING_CMP(TYPE, PNODE, PKEY, HASHVAL) \ - (((PNODE)->hashval == HASHVAL) ? (HDstrcmp((PNODE)->key, PKEY) < 0) : ((PNODE)->hashval < HASHVAL)) + (((PNODE)->hashval == HASHVAL) ? \ + (HDstrcmp((const char *)(PNODE)->key, (const char *)PKEY) < 0) : \ + ((PNODE)->hashval < HASHVAL)) /* Define a code template for comparing H5_obj_t keys for the "CMP" in the H5SL_LOCATE macro */ #define H5SL_LOCATE_OBJ_CMP(TYPE, PNODE, PKEY, HASHVAL) \ @@ -121,7 +102,7 @@ /* Define a code template for comparing string keys for the "EQ" in the H5SL_LOCATE macro */ #define H5SL_LOCATE_STRING_EQ(TYPE, PNODE, PKEY, HASHVAL) \ - (((PNODE)->hashval == HASHVAL) && (HDstrcmp(((PNODE)->key), PKEY) == 0)) + (((PNODE)->hashval == HASHVAL) && (HDstrcmp((const char *)(PNODE)->key, (const char *)PKEY) == 0)) /* Define a code template for comparing H5_obj_t keys for the "EQ" in the H5SL_LOCATE macro */ #define H5SL_LOCATE_OBJ_EQ(TYPE, PNODE, PKEY, HASHVAL) \ @@ -133,50 +114,358 @@ /* Define a code template for initializing the hash value for string keys for the "HASHINIT" in the H5SL_LOCATE macro */ #define H5SL_LOCATE_STRING_HASHINIT(KEY, HASHVAL) \ - HASHVAL = H5_hash_string(KEY); + HASHVAL = H5_hash_string((const char *)KEY); /* Define a code template for initializing the hash value for H5_obj_t keys for the "HASHINIT" in the H5SL_LOCATE macro */ #define H5SL_LOCATE_OBJ_HASHINIT(KEY, HASHVAL) /* Macro used to find node for operation */ -#define H5SL_LOCATE(OP, CMP, SLIST, X, UPDATE, TYPE, KEY, HASHVAL) \ +#define H5SL_LOCATE(OP, CMP, SLIST, X, TYPE, KEY, HASHVAL) \ { \ - H5SL_node_t *_checked; /* Pointer to last node checked */ \ int _i; /* Local index variable */ \ + unsigned _count; /* Num nodes searched at this height */ \ \ - _checked = NULL; \ H5_GLUE3(H5SL_LOCATE_,CMP,_HASHINIT)(KEY, HASHVAL) \ for(_i = (int)SLIST->curr_level; _i >= 0; _i--) { \ - if(X->forward[_i] != _checked) { \ - while(X->forward[_i] && H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(TYPE, X->forward[_i], KEY, HASHVAL) ) \ - X = X->forward[_i]; \ - _checked = X->forward[_i]; \ - } /* end if */ \ - H5_GLUE3(H5SL_LOCATE_,OP,_UPDATE)(X, UPDATE, _i) \ + _count = 0; \ + while(_count < 3 && X->forward[_i] && \ + H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(TYPE, X->forward[_i], KEY, HASHVAL) ) { \ + X = X->forward[_i]; \ + _count++; \ + } /* end while */ \ } /* end for */ \ X = X->forward[0]; \ if(X != NULL && H5_GLUE3(H5SL_LOCATE_,CMP,_EQ)(TYPE, X, KEY, HASHVAL) ) { \ /* What to do when a node is found */ \ - H5_GLUE3(H5SL_LOCATE_,OP,_FOUND)(SLIST, X, UPDATE, _i) \ + H5_GLUE3(H5SL_LOCATE_,OP,_FOUND)(SLIST, X, _i) \ } /* end if */ \ } -/* Macro used to insert node */ -#define H5SL_INSERT(CMP, SLIST, X, UPDATE, TYPE, KEY, HASHVAL) \ - H5SL_LOCATE(INSERT, CMP, SLIST, X, UPDATE, TYPE, KEY, HASHVAL) + +/* Macro used to grow a node by 1. Does not update pointers. LVL is the current + * level of X. Does not update LVL but does update X->lvl. */ +#define H5SL_GROW(X, LVL) \ +{ \ + /* Check if we need to increase allocation of forward pointers */ \ + if(LVL + 1 >= 1u << X->log_nalloc) { \ + H5SL_node_t **_tmp; \ + HDassert(LVL + 1 == 1u << X->log_nalloc); \ + /* Double the amount of allocated space */ \ + X->log_nalloc++; \ + \ + /* Check if we need to create a new factory */ \ + if(X->log_nalloc >= H5SL_fac_nused_g) { \ + HDassert(X->log_nalloc == H5SL_fac_nused_g); \ + \ + /* Check if we need to allocate space for the factory pointer*/ \ + if(H5SL_fac_nused_g >= H5SL_fac_nalloc_g) { \ + HDassert(H5SL_fac_nused_g == H5SL_fac_nalloc_g); \ + /* Double the size of the array of factory pointers */ \ + H5SL_fac_nalloc_g *= 2; \ + H5SL_fac_g = (H5FL_fac_head_t **)H5MM_realloc((void *)H5SL_fac_g, \ + H5SL_fac_nalloc_g * sizeof(H5FL_fac_head_t *)); \ + } /* end if */ \ + \ + /* Create the new factory */ \ + H5SL_fac_g[H5SL_fac_nused_g] = H5FL_fac_init((1u << H5SL_fac_nused_g) * sizeof(H5SL_node_t *)); \ + H5SL_fac_nused_g++; \ + } /* end if */ \ + \ + /* Allocate space for new forward pointers */ \ + if(NULL == (_tmp = (H5SL_node_t **)H5FL_FAC_MALLOC(H5SL_fac_g[X->log_nalloc]))) \ + HGOTO_ERROR(H5E_SLIST, H5E_NOSPACE, NULL, "memory allocation failed") \ + HDmemcpy((void *)_tmp, (const void *)X->forward, (LVL + 1) * sizeof(H5SL_node_t *)); \ + (void)H5FL_FAC_FREE(H5SL_fac_g[X->log_nalloc-1], (void *)X->forward); \ + X->forward = _tmp; \ + } /* end if */ \ + \ + X->level++; \ +} + + +/* Macro used to shrink a node by 1. Does not update pointers. LVL is the + * current level of X. Does not update LVL but does update X->level. */ +#define H5SL_SHRINK(X, LVL) \ +{ \ + /* Check if we can reduce the allocation of forward pointers */ \ + if(LVL <= 1u << (X->log_nalloc - 1)) { \ + H5SL_node_t **_tmp; \ + HDassert(LVL == 1u << (X->log_nalloc - 1)); \ + X->log_nalloc--; \ + \ + /* Allocate space for new forward pointers */ \ + if(NULL == (_tmp = (H5SL_node_t **)H5FL_FAC_MALLOC(H5SL_fac_g[X->log_nalloc]))) \ + HGOTO_ERROR(H5E_SLIST, H5E_NOSPACE, NULL, "memory allocation failed") \ + HDmemcpy((void *)_tmp, (const void *)X->forward, (LVL) * sizeof(H5SL_node_t *)); \ + (void)H5FL_FAC_FREE(H5SL_fac_g[X->log_nalloc+1], (void *)X->forward); \ + X->forward = _tmp; \ + } /* end if */ \ + \ + X->level--; \ +} + + +/* Macro used to grow the level of a node by 1, with appropriate changes to the + * head node if necessary. PREV is the previous node of the height that X is to + * grow to. */ +#define H5SL_PROMOTE(SLIST, X, PREV) \ +{ \ + size_t _lvl = X->level; \ + \ + H5SL_GROW(X, _lvl); \ + \ + if(_lvl == (size_t) SLIST->curr_level) { \ + HDassert(PREV == SLIST->header); \ + /* Grow the head */ \ + H5SL_GROW(PREV, _lvl); \ + SLIST->curr_level++; \ + X->forward[_lvl+1] = NULL; \ + } else { \ + HDassert(_lvl < (size_t) SLIST->curr_level); \ + X->forward[_lvl+1] = PREV->forward[_lvl+1]; \ + } /* end else */ \ + PREV->forward[_lvl+1] = X; \ +} + + +/* Macro used to reduce the level of a node by 1. Does not update the head node + * "current level". PREV is the previous node of the currrent height of X. */ +#define H5SL_DEMOTE(X, PREV) \ +{ \ + size_t _lvl = X->level; \ + \ + HDassert(PREV->forward[_lvl] == X); \ + PREV->forward[_lvl] = X->forward[_lvl]; \ + H5SL_SHRINK(X, _lvl); \ +} + + +/* Macro used to insert node. Does not actually insert the node. After running + * this macro, X will contain the node before where the new node should be + * inserted (at level 0). */ +#define H5SL_INSERT(CMP, SLIST, X, TYPE, KEY, HASHVAL) \ +{ \ + H5SL_node_t *_last = X; /* Lowest node in the current gap */ \ + H5SL_node_t *_next = NULL; /* Highest node in the currect gap */ \ + H5SL_node_t *_drop; /* Low node of the gap to drop into */ \ + int _count; /* Number of nodes in the current gap */ \ + int _i; \ + \ + H5_GLUE3(H5SL_LOCATE_,CMP,_HASHINIT)(KEY, HASHVAL) \ + for(_i = (int)SLIST->curr_level; _i >= 0; _i--) { \ + /* Search for the node to drop into, also count the number of nodes */ \ + /* of height _i in this gap */ \ + _drop = NULL; \ + for(_count = 0; ; _count++) { \ + /* Terminate if this is the last node in the gap */ \ + if(X->forward[_i] == _next) { \ + if(!_drop) \ + _drop = X; \ + break; \ + } /* end if */ \ + \ + /* Check if this node is the start of the next gap */ \ + if(!_drop && !H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(TYPE, X->forward[_i], KEY, HASHVAL)) \ + _drop = X; \ + \ + /* No need to check the last node in the gap if there are 3, as */ \ + /* there cannot be a fourth */ \ + if(_count == 2) { \ + if(!_drop) \ + _drop = X->forward[_i]; \ + _count = 3; \ + break; \ + } \ + X = X->forward[_i]; \ + } /* end for */ \ + HDassert(!_drop->forward[_i] || \ + !H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(TYPE, _drop->forward[_i], KEY, HASHVAL)); \ + \ + /* Promote the middle node if necessary */ \ + if(_count == 3) { \ + HDassert(X == _last->forward[_i]->forward[_i]); \ + H5SL_PROMOTE(SLIST, X, _last) \ + } \ + \ + /* Prepare to drop down */ \ + X = _last = _drop; \ + _next = _drop->forward[_i]; \ + } /* end for */ \ + \ + if(_next && H5_GLUE3(H5SL_LOCATE_,CMP,_EQ)(TYPE, _next, KEY, HASHVAL)) \ + HGOTO_ERROR(H5E_SLIST, H5E_CANTINSERT, NULL, "can't insert duplicate key") \ +} + /* Macro used to remove node */ -#define H5SL_REMOVE(CMP, SLIST, X, UPDATE, TYPE, KEY, HASHVAL) \ - H5SL_LOCATE(REMOVE, CMP, SLIST, X, UPDATE, TYPE, KEY, HASHVAL) +#define H5SL_REMOVE(CMP, SLIST, X, TYPE, KEY, HASHVAL) \ +{ \ + H5SL_node_t *_last = X; /* Lowest node in the current gap */ \ + H5SL_node_t *_llast = X; /* Lowest node in the previous gap */ \ + H5SL_node_t *_next = NULL; /* Highest node in the currect gap */ \ + H5SL_node_t *_drop = NULL; /* Low node of the gap to drop into */ \ + H5SL_node_t *_ldrop = NULL; /* Low node of gap before the one to drop into */ \ + H5SL_node_t *_head = SLIST->header; /* Head of the skip list */ \ + int _count; /* Number of nodes in the current gap */ \ + int _i = (int)SLIST->curr_level; \ + \ + if(_i < 0) \ + HGOTO_DONE(NULL); \ + \ + H5_GLUE3(H5SL_LOCATE_,CMP,_HASHINIT)(KEY, HASHVAL) \ + \ + /* Find the gap to drop in to at the highest level */ \ + while(X && (!X->key || H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(TYPE, X, KEY, HASHVAL))) { \ + _llast = _last; \ + _last = X; \ + X = X->forward[_i]; \ + } \ + _next = X; \ + \ + /* Main loop */ \ + for(_i--; _i >= 0; _i--) { \ + /* Search for the node to drop into, also count the number of nodes */ \ + /* of height _i in this gap and keep track of of the node before */ \ + /* the one to drop into (_ldrop will become _llast, _drop will */ \ + /* become _last). */ \ + X = _ldrop = _last; \ + _drop = NULL; \ + for(_count = 0; ; _count++) { \ + /* Terminate if this is the last node in the gap */ \ + if(X->forward[_i] == _next) { \ + if(!_drop) \ + _drop = X; \ + break; \ + } /* end if */ \ + \ + /* If we have already found the node to drop into and there is */ \ + /* more than one node in this gap, we can stop searching */ \ + if(_drop) { \ + HDassert(_count >= 1); \ + _count = 2; \ + break; \ + } else { /* !_drop */ \ + /* Check if this node is the start of the next gap */ \ + if (!H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(TYPE, X->forward[_i], KEY, HASHVAL)) { \ + _drop = X; \ + /* Again check if we can stop searching */ \ + if(_count) { \ + _count = 2; \ + break; \ + } /* end if */ \ + } /* end if */ \ + else \ + _ldrop = X; \ + } /* end else */ \ + \ + /* No need to check the last node in the gap if there are 3, as */ \ + /* there cannot be a fourth */ \ + if(_count == 2) { \ + if(!_drop) \ + _drop = X->forward[_i]; \ + break; \ + } /* end if */ \ + X = X->forward[_i]; \ + } /* end for */ \ + HDassert(_count >= 1 && _count <= 3); \ + HDassert(!_drop->forward[_i] || \ + !H5_GLUE3(H5SL_LOCATE_,CMP,_CMP)(TYPE, _drop->forward[_i], KEY, HASHVAL)); \ + \ + /* Check if we need to adjust node heights */ \ + if(_count == 1) { \ + /* Check if we are in the first gap */ \ + if(_llast == _last) { \ + /* We are in the first gap, count the number of nodes of */ \ + /* height _i in the next gap. We need only check one node */ \ + /* to see if we should promote the first node in the next */ \ + /* gap */ \ + _llast = _next->forward[_i+1]; \ + \ + /* Demote the separator node */ \ + H5SL_DEMOTE(_next, _last) \ + \ + /* If there are 2 or more nodes, promote the first */ \ + if(_next->forward[_i]->forward[_i] != _llast) { \ + X = _next->forward[_i]; \ + H5SL_PROMOTE(SLIST, X, _last) \ + } else if(!_head->forward[_i+1]) { \ + /* shrink the header */ \ + HDassert(_i == SLIST->curr_level - 1); \ + HDassert((size_t) SLIST->curr_level == _head->level); \ + \ + H5SL_SHRINK(_head, (size_t) (_i+1)) \ + SLIST->curr_level--; \ + } /* end else */ \ + } else { \ + /* We are not in the first gap, count the number of nodes */ \ + /* of height _i in the previous gap. Note we "look ahead" */ \ + /* in this loop so X has the value of the last node in the */ \ + /* previous gap. */ \ + X = _llast->forward[_i]; \ + for(_count = 1; _count < 3 && X->forward[_i] != _last; _count++) \ + X = X->forward[_i]; \ + HDassert(X->forward[_i] == _last); \ + \ + /* Demote the separator node */ \ + H5SL_DEMOTE(_last, _llast) \ + \ + /* If there are 2 or more nodes, promote the last */ \ + if(_count >= 2) \ + H5SL_PROMOTE(SLIST, X, _llast) \ + else if(!_head->forward[_i+1]) { \ + /* shrink the header */ \ + HDassert(_i == SLIST->curr_level - 1); \ + HDassert((size_t) SLIST->curr_level == _head->level); \ + \ + H5SL_SHRINK(_head, (size_t) (_i+1)) \ + SLIST->curr_level--; \ + } /* end else */ \ + } /* end else */ \ + } /* end if */ \ + \ + /* Prepare to drop down */ \ + _llast = _ldrop; \ + _last = _drop; \ + _next = _drop->forward[_i]; \ + } /* end for */ \ + \ + /* Check if we've found the node */ \ + if(_next && H5_GLUE3(H5SL_LOCATE_,CMP,_EQ)(TYPE, _next, KEY, HASHVAL)) { \ + void *tmp = _next->item; \ + X = _next; \ + \ + /* If the node has a height > 0, swap it with its (lower) neighbor */ \ + if(X->level) { \ + X = X->backward; \ + _next->key = X->key; \ + _next->item = X->item; \ + _next->hashval = X->hashval; \ + } /* end if */ \ + HDassert(!X->level); \ + \ + /* Remove the node */ \ + X->backward->forward[0] = X->forward[0]; \ + if(SLIST->last == X) \ + SLIST->last = X->backward; \ + else \ + X->forward[0]->backward = X->backward; \ + SLIST->nobjs--; \ + (void)H5FL_FAC_FREE(H5SL_fac_g[0], X->forward); \ + (void)H5FL_FREE(H5SL_node_t, X); \ + \ + HGOTO_DONE(tmp); \ + } /* end if */ \ +} + /* Macro used to search for node */ -#define H5SL_SEARCH(CMP, SLIST, X, UPDATE, TYPE, KEY, HASHVAL) \ - H5SL_LOCATE(SEARCH, CMP, SLIST, X, UPDATE, TYPE, KEY, HASHVAL) +#define H5SL_SEARCH(CMP, SLIST, X, TYPE, KEY, HASHVAL) \ + H5SL_LOCATE(SEARCH, CMP, SLIST, X, TYPE, KEY, HASHVAL) /* Macro used to find a node */ -#define H5SL_FIND(CMP, SLIST, X, UPDATE, TYPE, KEY, HASHVAL) \ - H5SL_LOCATE(FIND, CMP, SLIST, X, UPDATE, TYPE, KEY, HASHVAL) +#define H5SL_FIND(CMP, SLIST, X, TYPE, KEY, HASHVAL) \ + H5SL_LOCATE(FIND, CMP, SLIST, X, TYPE, KEY, HASHVAL) /* Private typedefs & structs */ @@ -186,6 +475,7 @@ struct H5SL_node_t { const void *key; /* Pointer to node's key */ void *item; /* Pointer to node's item */ size_t level; /* The level of this node */ + size_t log_nalloc; /* log2(Number of slots allocated in forward) */ uint32_t hashval; /* Hash value for key (only for strings, currently) */ struct H5SL_node_t **forward; /* Array of forward pointers from this node */ struct H5SL_node_t *backward; /* Backward pointer from this node */ @@ -195,9 +485,6 @@ struct H5SL_node_t { struct H5SL_t { /* Static values for each list */ H5SL_type_t type; /* Type of skip list */ - double p; /* Probability of using a higher level [0..1) */ - int p1; /* Probability converted into appropriate value for random # generator on this machine */ - size_t max_level; /* Maximum number of levels */ /* Dynamic values for each list */ int curr_level; /* Current top level used in list */ @@ -207,8 +494,7 @@ struct H5SL_t { }; /* Static functions */ -static size_t H5SL_random_level(int p1, size_t max_level); -static H5SL_node_t * H5SL_new_node(size_t lvl, void *item, const void *key, uint32_t hashval); +static H5SL_node_t * H5SL_new_node(void *item, const void *key, uint32_t hashval); static H5SL_node_t *H5SL_insert_common(H5SL_t *slist, void *item, const void *key); static herr_t H5SL_release_common(H5SL_t *slist, H5SL_operator_t op, void *op_data); static herr_t H5SL_close_common(H5SL_t *slist, H5SL_operator_t op, void *op_data); @@ -216,9 +502,13 @@ static herr_t H5SL_close_common(H5SL_t *slist, H5SL_operator_t op, void *op_data /* Declare a free list to manage the H5SL_t struct */ H5FL_DEFINE_STATIC(H5SL_t); -/* Declare a "base + array" list to manage the H5SL_node_t struct */ -typedef H5SL_node_t *H5SL_node_ptr_t; -H5FL_BARR_DEFINE_STATIC(H5SL_node_t,H5SL_node_ptr_t,H5SL_LEVEL_MAX); +/* Declare a free list to manage the H5SL_node_t struct */ +H5FL_DEFINE_STATIC(H5SL_node_t); + +/* Global variables */ +static H5FL_fac_head_t **H5SL_fac_g; +static size_t H5SL_fac_nused_g; +static size_t H5SL_fac_nalloc_g; /*-------------------------------------------------------------------------- @@ -241,13 +531,15 @@ H5FL_BARR_DEFINE_STATIC(H5SL_node_t,H5SL_node_ptr_t,H5SL_LEVEL_MAX); static herr_t H5SL_init_interface(void) { - time_t curr_time; /* Current time, for seeding random number generator */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5SL_init_interface) - /* Create randomized set of numbers */ - curr_time=HDtime(NULL); - HDsrand((unsigned)curr_time); + /* Allocate space for array of factories */ + H5SL_fac_g = (H5FL_fac_head_t **)H5MM_malloc(sizeof(H5FL_fac_head_t *)); + H5SL_fac_nalloc_g = 1; + + /* Initialize first factory */ + H5SL_fac_g[0] = H5FL_fac_init(sizeof(H5SL_node_t *)); + H5SL_fac_nused_g = 1; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5SL_init_interface() */ @@ -255,87 +547,45 @@ H5SL_init_interface(void) /*-------------------------------------------------------------------------- NAME - H5SL_random_level - PURPOSE - Generate a random level - USAGE - size_t H5SL_random_level(p,max_level) - int p1; IN: probability distribution - size_t max_level; IN: Maximum level for node height - - RETURNS - Returns non-negative level value - DESCRIPTION - Count elements in a skip list. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - Do we really need a 'random' value, or is a series of nodes with the - correct heights "good enough". We could track the state of the nodes - allocated for this list and issue node heights appropriately (i.e. 1,2, - 1,4,1,2,1,8,...) (or would that be 1,1,2,1,1,2,4,... ?) - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static size_t -H5SL_random_level(int p1, size_t max_level) -{ - size_t lvl; /* Level generated */ - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5SL_random_level); - - /* Account for starting at zero offset */ - max_level--; - - lvl=0; - while(HDrand()<p1 && lvl < max_level) - lvl++; - - FUNC_LEAVE_NOAPI(lvl); -} /* end H5SL_random_level() */ - - -/*-------------------------------------------------------------------------- - NAME H5SL_new_node PURPOSE - Create a new skip list node + Create a new skip list node of level 0 USAGE - H5SL_node_t *H5SL_new_node(lvl,item,key) - size_t lvl; IN: Level for node height + H5SL_node_t *H5SL_new_node(item,key,hasval) void *item; IN: Pointer to item info for node void *key; IN: Pointer to key info for node + uint32_t hashval; IN: Hash value for node RETURNS Returns a pointer to a skip list node on success, NULL on failure. DESCRIPTION - Create a new skip list node of the specified height, setting the item + Create a new skip list node of the height 0, setting the item and key values internally. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS This routine does _not_ initialize the 'forward' pointers - - We should set up a custom free-list for allocating & freeing these sort - of nodes. EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ static H5SL_node_t * -H5SL_new_node(size_t lvl, void *item, const void *key, uint32_t hashval) +H5SL_new_node(void *item, const void *key, uint32_t hashval) { H5SL_node_t *ret_value; /* New skip list node */ FUNC_ENTER_NOAPI_NOINIT(H5SL_new_node) /* Allocate the node */ - if(NULL == (ret_value = (H5SL_node_t *)H5FL_ARR_MALLOC(H5SL_node_ptr_t, (lvl + 1)))) + if(NULL == (ret_value = (H5SL_node_t *)H5FL_MALLOC(H5SL_node_t))) HGOTO_ERROR(H5E_SLIST, H5E_NOSPACE, NULL, "memory allocation failed") /* Initialize node */ ret_value->key = key; ret_value->item = item; - ret_value->level = lvl; + ret_value->level = 0; ret_value->hashval = hashval; - ret_value->forward = (H5SL_node_t **)((unsigned char *)ret_value + sizeof(H5SL_node_t)); + if(NULL == (ret_value->forward = (H5SL_node_t **)H5FL_FAC_MALLOC(H5SL_fac_g[0]))) + HGOTO_ERROR(H5E_SLIST, H5E_NOSPACE, NULL, "memory allocation failed") + ret_value->log_nalloc = 0; done: FUNC_LEAVE_NOAPI(ret_value) @@ -366,18 +616,16 @@ done: static H5SL_node_t * H5SL_insert_common(H5SL_t *slist, void *item, const void *key) { - H5SL_node_t **update[H5SL_LEVEL_MAX]; /* 'update' vector */ H5SL_node_t *x; /* Current node to examine */ + H5SL_node_t *prev; /* Node before the new node */ uint32_t hashval = 0; /* Hash value for key */ - size_t lvl; /* Level of new node */ - int i; /* Local index value */ H5SL_node_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5SL_insert_common); /* Check args */ - assert(slist); - assert(key); + HDassert(slist); + HDassert(key); /* Check internal consistency */ /* (Pre-condition) */ @@ -387,75 +635,60 @@ H5SL_insert_common(H5SL_t *slist, void *item, const void *key) /* Work through the forward pointers for a node, finding the node at each * level that is before the location to insert */ - x=slist->header; + prev=slist->header; switch(slist->type) { case H5SL_TYPE_INT: - H5SL_INSERT(SCALAR, slist, x, update, const int, key, -) + H5SL_INSERT(SCALAR, slist, prev, const int, key, -) break; case H5SL_TYPE_HADDR: - H5SL_INSERT(SCALAR, slist, x, update, const haddr_t, key, -) + H5SL_INSERT(SCALAR, slist, prev, const haddr_t, key, -) break; case H5SL_TYPE_STR: - H5SL_INSERT(STRING, slist, x, update, char *, key, hashval) + H5SL_INSERT(STRING, slist, prev, char *, key, hashval) break; case H5SL_TYPE_HSIZE: - H5SL_INSERT(SCALAR, slist, x, update, const hsize_t, key, -) + H5SL_INSERT(SCALAR, slist, prev, const hsize_t, key, -) break; case H5SL_TYPE_UNSIGNED: - H5SL_INSERT(SCALAR, slist, x, update, const unsigned, key, -) + H5SL_INSERT(SCALAR, slist, prev, const unsigned, key, -) break; case H5SL_TYPE_SIZE: - H5SL_INSERT(SCALAR, slist, x, update, const size_t, key, -) + H5SL_INSERT(SCALAR, slist, prev, const size_t, key, -) break; case H5SL_TYPE_OBJ: - H5SL_INSERT(OBJ, slist, x, update, const H5_obj_t, key, -) + H5SL_INSERT(OBJ, slist, prev, const H5_obj_t, key, -) break; default: HDassert(0 && "Unknown skiplist type!"); } /* end switch */ - /* 'key' must not have been found in existing list, if we get here */ - - /* Generate level for new node */ - lvl=H5SL_random_level(slist->p1,slist->max_level); - if((int)lvl>slist->curr_level) { - /* Cap the increase in the current level to just one greater */ - lvl=slist->curr_level+1; - /* Set the update pointer correctly */ - update[lvl]=&slist->header->forward[lvl]; + /* 'key' must not have been found in existing list, if we get here */ - /* Increase the maximum level of the list */ - slist->curr_level=(int)lvl; - } /* end if */ + if(slist->curr_level < 0) + slist->curr_level = 0; - /* Create new node of proper level */ - if(NULL == (x = H5SL_new_node(lvl, item, key, hashval))) + /* Create new node of level 0 */ + if(NULL == (x = H5SL_new_node(item, key, hashval))) HGOTO_ERROR(H5E_SLIST ,H5E_NOSPACE, NULL, "can't create new skip list node") - /* Update the backward links */ - if(*update[0]!=NULL) { - x->backward=(*update[0])->backward; - (*update[0])->backward=x; - } /* end if */ + /* Update the links */ + x->backward = prev; + x->forward[0] = prev->forward[0]; + prev->forward[0] = x; + if(x->forward[0]) + x->forward[0]->backward = x; else { HDassert(slist->last); - x->backward=slist->last; - slist->last=x; - } /* end else */ - - /* Link the new node into the existing forward pointers */ - for(i=0; i<=(int)lvl; i++) { - x->forward[i]=*update[i]; - *update[i]=x; - } /* end for */ + slist->last = x; + } /* Increment the number of nodes in the skip list */ slist->nobjs++; @@ -474,7 +707,7 @@ done: PURPOSE Release all nodes from a skip list, optionally calling a 'free' operator USAGE - herr_t H5SL_release_common(slist) + herr_t H5SL_release_common(slist,op,opdata) H5SL_t *slist; IN/OUT: Pointer to skip list to release nodes H5SL_operator_t op; IN: Callback function to free item & key void *op_data; IN/OUT: Pointer to application data for callback @@ -496,9 +729,9 @@ herr_t H5SL_release_common(H5SL_t *slist, H5SL_operator_t op, void *op_data) { H5SL_node_t *node, *next_node; /* Pointers to skip list nodes */ - size_t u; /* Local index variable */ + herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5SL_release_common); + FUNC_ENTER_NOAPI_NOINIT(H5SL_release_common); /* Check args */ assert(slist); @@ -516,13 +749,18 @@ H5SL_release_common(H5SL_t *slist, H5SL_operator_t op, void *op_data) /* Casting away const OK -QAK */ (void)(op)(node->item,(void *)node->key,op_data); - H5FL_ARR_FREE(H5SL_node_ptr_t,node); + (void)H5FL_FAC_FREE(H5SL_fac_g[node->log_nalloc], node->forward); + (void)H5FL_FREE(H5SL_node_t, node); node=next_node; } /* end while */ /* Reset the header pointers */ - for(u=0; u<slist->max_level; u++) - slist->header->forward[u]=NULL; + (void)H5FL_FAC_FREE(H5SL_fac_g[slist->header->log_nalloc], slist->header->forward); + if(NULL == (slist->header->forward = (H5SL_node_t **) H5FL_FAC_MALLOC(H5SL_fac_g[0]))) + HGOTO_ERROR(H5E_SLIST, H5E_NOSPACE, FAIL, "memory allocation failed") + slist->header->forward[0] = NULL; + slist->header->log_nalloc = 0; + slist->header->level = 0; /* Reset the last pointer */ slist->last=slist->header; @@ -531,7 +769,8 @@ H5SL_release_common(H5SL_t *slist, H5SL_operator_t op, void *op_data) slist->curr_level=-1; slist->nobjs=0; - FUNC_LEAVE_NOAPI(SUCCEED); +done: + FUNC_LEAVE_NOAPI(ret_value); } /* end H5SL_release_common() */ @@ -561,7 +800,9 @@ H5SL_release_common(H5SL_t *slist, H5SL_operator_t op, void *op_data) herr_t H5SL_close_common(H5SL_t *slist, H5SL_operator_t op, void *op_data) { - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5SL_close_common) + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT(H5SL_close_common) /* Check args */ HDassert(slist); @@ -570,15 +811,18 @@ H5SL_close_common(H5SL_t *slist, H5SL_operator_t op, void *op_data) /* (Pre-condition) */ /* Free skip list nodes */ - (void)H5SL_release_common(slist, op, op_data); /* always succeeds */ + if(H5SL_release_common(slist, op, op_data) < 0) + HGOTO_ERROR(H5E_SLIST, H5E_CANTFREE, FAIL, "can't release skip list nodes") /* Release header node */ - H5FL_ARR_FREE(H5SL_node_ptr_t, slist->header); + (void)H5FL_FAC_FREE(H5SL_fac_g[slist->header->log_nalloc], slist->header->forward); + (void)H5FL_FREE(H5SL_node_t, slist->header); /* Free skip list object */ (void)H5FL_FREE(H5SL_t, slist); - FUNC_LEAVE_NOAPI(SUCCEED) +done: + FUNC_LEAVE_NOAPI(ret_value) } /* end H5SL_close_common() */ @@ -588,7 +832,7 @@ H5SL_close_common(H5SL_t *slist, H5SL_operator_t op, void *op_data) PURPOSE Create a skip list USAGE - H5SL_t *H5SL_create(void) + H5SL_t *H5SL_create(H5SL_type_t type) RETURNS Returns a pointer to a skip list on success, NULL on failure. @@ -600,18 +844,15 @@ H5SL_close_common(H5SL_t *slist, H5SL_operator_t op, void *op_data) REVISION LOG --------------------------------------------------------------------------*/ H5SL_t * -H5SL_create(H5SL_type_t type, double p, size_t max_level) +H5SL_create(H5SL_type_t type) { H5SL_t *new_slist = NULL; /* Pointer to new skip list object created */ H5SL_node_t *header; /* Pointer to skip list header node */ - size_t u; /* Local index variable */ H5SL_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5SL_create,NULL); /* Check args */ - HDassert(p>0.0 && p<1.0); - HDassert(max_level>0 && max_level<=H5SL_LEVEL_MAX); HDassert(type>=H5SL_TYPE_INT && type<=H5SL_TYPE_OBJ); /* Allocate skip list structure */ @@ -620,21 +861,17 @@ H5SL_create(H5SL_type_t type, double p, size_t max_level) /* Set the static internal fields */ new_slist->type = type; - new_slist->p = p; - new_slist->p1 = (int)(p*RAND_MAX); - new_slist->max_level = max_level; /* Set the dynamic internal fields */ new_slist->curr_level = -1; new_slist->nobjs = 0; /* Allocate the header node */ - if(NULL == (header = H5SL_new_node((max_level - 1), NULL, NULL, ULONG_MAX))) + if(NULL == (header = H5SL_new_node(NULL, NULL, ULONG_MAX))) HGOTO_ERROR(H5E_SLIST ,H5E_NOSPACE, NULL, "can't create new skip list node") - /* Initialize header node's forward pointers */ - for(u = 0; u < max_level; u++) - header->forward[u] = NULL; + /* Initialize header node's forward pointer */ + header->forward[0] = NULL; /* Initialize header node's backward pointer */ header->backward = NULL; @@ -803,12 +1040,11 @@ done: void * H5SL_remove(H5SL_t *slist, const void *key) { - H5SL_node_t **update[H5SL_LEVEL_MAX]; /* 'update' vector */ H5SL_node_t *x; /* Current node to examine */ uint32_t hashval = 0; /* Hash value for key */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5SL_remove) + FUNC_ENTER_NOAPI_NOINIT(H5SL_remove) /* Check args */ HDassert(slist); @@ -825,31 +1061,31 @@ H5SL_remove(H5SL_t *slist, const void *key) x = slist->header; switch(slist->type) { case H5SL_TYPE_INT: - H5SL_REMOVE(SCALAR, slist, x, update, const int, key, -) + H5SL_REMOVE(SCALAR, slist, x, const int, key, -) break; case H5SL_TYPE_HADDR: - H5SL_REMOVE(SCALAR, slist, x, update, const haddr_t, key, -) + H5SL_REMOVE(SCALAR, slist, x, const haddr_t, key, -) break; case H5SL_TYPE_STR: - H5SL_REMOVE(STRING, slist, x, update, char *, key, hashval) + H5SL_REMOVE(STRING, slist, x, char *, key, hashval) break; case H5SL_TYPE_HSIZE: - H5SL_REMOVE(SCALAR, slist, x, update, const hsize_t, key, -) + H5SL_REMOVE(SCALAR, slist, x, const hsize_t, key, -) break; case H5SL_TYPE_UNSIGNED: - H5SL_REMOVE(SCALAR, slist, x, update, const unsigned, key, -) + H5SL_REMOVE(SCALAR, slist, x, const unsigned, key, -) break; case H5SL_TYPE_SIZE: - H5SL_REMOVE(SCALAR, slist, x, update, const size_t, key, -) + H5SL_REMOVE(SCALAR, slist, x, const size_t, key, -) break; case H5SL_TYPE_OBJ: - H5SL_REMOVE(OBJ, slist, x, update, const H5_obj_t, key, -) + H5SL_REMOVE(OBJ, slist, x, const H5_obj_t, key, -) break; default: @@ -876,8 +1112,6 @@ done: Remove first element from a skip list. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS - This algorithm is basically the same as the one in the - H5SL_LOCATE_REMOVE_FOUND macro, fix bugs in both places EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ @@ -885,8 +1119,13 @@ void * H5SL_remove_first(H5SL_t *slist) { void *ret_value = NULL; /* Return value */ + H5SL_node_t *head = slist->header; /* Skip list header */ + H5SL_node_t *tmp = slist->header->forward[0]; /* Temporary node pointer */ + H5SL_node_t *next; /* Next node to search for */ + size_t level = slist->curr_level; /* Skip list level */ + size_t i; /* Index */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5SL_remove_first) + FUNC_ENTER_NOAPI_NOINIT(H5SL_remove_first) /* Check args */ HDassert(slist); @@ -898,39 +1137,62 @@ H5SL_remove_first(H5SL_t *slist) /* Check for empty list */ if(slist->last != slist->header) { - H5SL_node_t *x; /* Current node to examine */ - int i; /* Local index value */ - /* Get pointer to first node on the list */ - x = slist->header->forward[0]; - - /* Patch forward pointers in list header around node to remove */ - for(i = 0; i <= (int)slist->curr_level; i++) { - if(slist->header->forward[i] != x) - break; - slist->header->forward[i] = x->forward[i]; - } /* end for */ + /* Assign return value */ + ret_value = tmp->item; + HDassert(level == head->level); + HDassert(0 == tmp->level); - /* Update tail/backward pointer */ - if(slist->last == x) - slist->last = x->backward; + /* Remove the first node */ + head->forward[0] = tmp->forward[0]; + if(slist->last == tmp) + slist->last = head; else - x->forward[0]->backward = x->backward; - - /* Get the item to return */ - ret_value = x->item; - - /* Free the skip list node */ - H5FL_ARR_FREE(H5SL_node_ptr_t, x); - - /* Lower the level of the list, if we removed the tallest node */ - while(slist->curr_level > 0 && slist->header->forward[slist->curr_level] == NULL) - slist->curr_level--; - - /* Decrement the # of objects in the list */ + tmp->forward[0]->backward = head; slist->nobjs--; + /* Free memory */ + (void)H5FL_FAC_FREE(H5SL_fac_g[0], tmp->forward); + (void)H5FL_FREE(H5SL_node_t, tmp); + + /* Reshape the skip list as necessary to maintain 1-2-3 condition */ + for(i=0; i < level; i++) { + next = head->forward[i+1]; + HDassert(next); + + /* Check if head->forward[i] == head->forward[i+1] (illegal) */ + if(head->forward[i] == next) { + tmp = next; + next = next->forward[i+1]; + + HDassert(tmp->level == i+1); + + /* Demote head->forward[i] */ + H5SL_DEMOTE(tmp, head) + + /* Check if we need to promote the following node to maintain + * 1-2-3 condition */ + if(tmp->forward[i]->forward[i] != next) { + HDassert(tmp->forward[i]->forward[i]->forward[i] == next || + tmp->forward[i]->forward[i]->forward[i]->forward[i] == next); + tmp = tmp->forward[i]; + H5SL_PROMOTE(slist, tmp, head); + /* In this case, since there is a node of height = i+1 here + * now (tmp), we know the skip list must be valid and can + * break */ + break; + } else if(!head->forward[i+1]) { + /* We just shrunk the largest node, shrink the header */ + HDassert(i == level - 1); + + H5SL_SHRINK(head, level) + slist->curr_level--; + } /* end else */ + } else + break; + } /* end for */ } /* end if */ +done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5SL_remove_first() */ @@ -978,31 +1240,31 @@ H5SL_search(H5SL_t *slist, const void *key) x=slist->header; switch(slist->type) { case H5SL_TYPE_INT: - H5SL_SEARCH(SCALAR, slist, x, -, const int, key, -) + H5SL_SEARCH(SCALAR, slist, x, const int, key, -) break; case H5SL_TYPE_HADDR: - H5SL_SEARCH(SCALAR, slist, x, -, const haddr_t, key, -) + H5SL_SEARCH(SCALAR, slist, x, const haddr_t, key, -) break; case H5SL_TYPE_STR: - H5SL_SEARCH(STRING, slist, x, -, char *, key, hashval) + H5SL_SEARCH(STRING, slist, x, char *, key, hashval) break; case H5SL_TYPE_HSIZE: - H5SL_SEARCH(SCALAR, slist, x, -, const hsize_t, key, -) + H5SL_SEARCH(SCALAR, slist, x, const hsize_t, key, -) break; case H5SL_TYPE_UNSIGNED: - H5SL_SEARCH(SCALAR, slist, x, -, const unsigned, key, -) + H5SL_SEARCH(SCALAR, slist, x, const unsigned, key, -) break; case H5SL_TYPE_SIZE: - H5SL_SEARCH(SCALAR, slist, x, -, const size_t, key, -) + H5SL_SEARCH(SCALAR, slist, x, const size_t, key, -) break; case H5SL_TYPE_OBJ: - H5SL_SEARCH(OBJ, slist, x, -, const H5_obj_t, key, -) + H5SL_SEARCH(OBJ, slist, x, const H5_obj_t, key, -) break; default: @@ -1063,31 +1325,31 @@ H5SL_less(H5SL_t *slist, const void *key) x=slist->header; switch(slist->type) { case H5SL_TYPE_INT: - H5SL_SEARCH(SCALAR, slist, x, -, const int, key, -) + H5SL_SEARCH(SCALAR, slist, x, const int, key, -) break; case H5SL_TYPE_HADDR: - H5SL_SEARCH(SCALAR, slist, x, -, const haddr_t, key, -) + H5SL_SEARCH(SCALAR, slist, x, const haddr_t, key, -) break; case H5SL_TYPE_STR: - H5SL_SEARCH(STRING, slist, x, -, char *, key, hashval) + H5SL_SEARCH(STRING, slist, x, char *, key, hashval) break; case H5SL_TYPE_HSIZE: - H5SL_SEARCH(SCALAR, slist, x, -, const hsize_t, key, -) + H5SL_SEARCH(SCALAR, slist, x, const hsize_t, key, -) break; case H5SL_TYPE_UNSIGNED: - H5SL_SEARCH(SCALAR, slist, x, -, const unsigned, key, -) + H5SL_SEARCH(SCALAR, slist, x, const unsigned, key, -) break; case H5SL_TYPE_SIZE: - H5SL_SEARCH(SCALAR, slist, x, -, const size_t, key, -) + H5SL_SEARCH(SCALAR, slist, x, const size_t, key, -) break; case H5SL_TYPE_OBJ: - H5SL_SEARCH(OBJ, slist, x, -, const H5_obj_t, key, -) + H5SL_SEARCH(OBJ, slist, x, const H5_obj_t, key, -) break; default: @@ -1161,31 +1423,31 @@ H5SL_greater(H5SL_t *slist, const void *key) x = slist->header; switch(slist->type) { case H5SL_TYPE_INT: - H5SL_SEARCH(SCALAR, slist, x, -, const int, key, -) + H5SL_SEARCH(SCALAR, slist, x, const int, key, -) break; case H5SL_TYPE_HADDR: - H5SL_SEARCH(SCALAR, slist, x, -, const haddr_t, key, -) + H5SL_SEARCH(SCALAR, slist, x, const haddr_t, key, -) break; case H5SL_TYPE_STR: - H5SL_SEARCH(STRING, slist, x, -, char *, key, hashval) + H5SL_SEARCH(STRING, slist, x, char *, key, hashval) break; case H5SL_TYPE_HSIZE: - H5SL_SEARCH(SCALAR, slist, x, -, const hsize_t, key, -) + H5SL_SEARCH(SCALAR, slist, x, const hsize_t, key, -) break; case H5SL_TYPE_UNSIGNED: - H5SL_SEARCH(SCALAR, slist, x, -, const unsigned, key, -) + H5SL_SEARCH(SCALAR, slist, x, const unsigned, key, -) break; case H5SL_TYPE_SIZE: - H5SL_SEARCH(SCALAR, slist, x, -, const size_t, key, -) + H5SL_SEARCH(SCALAR, slist, x, const size_t, key, -) break; case H5SL_TYPE_OBJ: - H5SL_SEARCH(OBJ, slist, x, -, const H5_obj_t, key, -) + H5SL_SEARCH(OBJ, slist, x, const H5_obj_t, key, -) break; default: @@ -1249,31 +1511,31 @@ H5SL_find(H5SL_t *slist, const void *key) x=slist->header; switch(slist->type) { case H5SL_TYPE_INT: - H5SL_FIND(SCALAR, slist, x, -, const int, key, -) + H5SL_FIND(SCALAR, slist, x, const int, key, -) break; case H5SL_TYPE_HADDR: - H5SL_FIND(SCALAR, slist, x, -, const haddr_t, key, -) + H5SL_FIND(SCALAR, slist, x, const haddr_t, key, -) break; case H5SL_TYPE_STR: - H5SL_FIND(STRING, slist, x, -, char *, key, hashval) + H5SL_FIND(STRING, slist, x, char *, key, hashval) break; case H5SL_TYPE_HSIZE: - H5SL_FIND(SCALAR, slist, x, -, const hsize_t, key, -) + H5SL_FIND(SCALAR, slist, x, const hsize_t, key, -) break; case H5SL_TYPE_UNSIGNED: - H5SL_FIND(SCALAR, slist, x, -, const unsigned, key, -) + H5SL_FIND(SCALAR, slist, x, const unsigned, key, -) break; case H5SL_TYPE_SIZE: - H5SL_FIND(SCALAR, slist, x, -, const size_t, key, -) + H5SL_FIND(SCALAR, slist, x, const size_t, key, -) break; case H5SL_TYPE_OBJ: - H5SL_FIND(OBJ, slist, x, -, const H5_obj_t, key, -) + H5SL_FIND(OBJ, slist, x, const H5_obj_t, key, -) break; default: @@ -1334,31 +1596,31 @@ H5SL_below(H5SL_t *slist, const void *key) x = slist->header; switch(slist->type) { case H5SL_TYPE_INT: - H5SL_FIND(SCALAR, slist, x, -, const int, key, -) + H5SL_FIND(SCALAR, slist, x, const int, key, -) break; case H5SL_TYPE_HADDR: - H5SL_FIND(SCALAR, slist, x, -, const haddr_t, key, -) + H5SL_FIND(SCALAR, slist, x, const haddr_t, key, -) break; case H5SL_TYPE_STR: - H5SL_FIND(STRING, slist, x, -, char *, key, hashval) + H5SL_FIND(STRING, slist, x, char *, key, hashval) break; case H5SL_TYPE_HSIZE: - H5SL_FIND(SCALAR, slist, x, -, const hsize_t, key, -) + H5SL_FIND(SCALAR, slist, x, const hsize_t, key, -) break; case H5SL_TYPE_UNSIGNED: - H5SL_FIND(SCALAR, slist, x, -, const unsigned, key, -) + H5SL_FIND(SCALAR, slist, x, const unsigned, key, -) break; case H5SL_TYPE_SIZE: - H5SL_FIND(SCALAR, slist, x, -, const size_t, key, -) + H5SL_FIND(SCALAR, slist, x, const size_t, key, -) break; case H5SL_TYPE_OBJ: - H5SL_FIND(OBJ, slist, x, -, const H5_obj_t, key, -) + H5SL_FIND(OBJ, slist, x, const H5_obj_t, key, -) break; } /* end switch */ @@ -1429,31 +1691,31 @@ H5SL_above(H5SL_t *slist, const void *key) x = slist->header; switch(slist->type) { case H5SL_TYPE_INT: - H5SL_FIND(SCALAR, slist, x, -, const int, key, -) + H5SL_FIND(SCALAR, slist, x, const int, key, -) break; case H5SL_TYPE_HADDR: - H5SL_FIND(SCALAR, slist, x, -, const haddr_t, key, -) + H5SL_FIND(SCALAR, slist, x, const haddr_t, key, -) break; case H5SL_TYPE_STR: - H5SL_FIND(STRING, slist, x, -, char *, key, hashval) + H5SL_FIND(STRING, slist, x, char *, key, hashval) break; case H5SL_TYPE_HSIZE: - H5SL_FIND(SCALAR, slist, x, -, const hsize_t, key, -) + H5SL_FIND(SCALAR, slist, x, const hsize_t, key, -) break; case H5SL_TYPE_UNSIGNED: - H5SL_FIND(SCALAR, slist, x, -, const unsigned, key, -) + H5SL_FIND(SCALAR, slist, x, const unsigned, key, -) break; case H5SL_TYPE_SIZE: - H5SL_FIND(SCALAR, slist, x, -, const size_t, key, -) + H5SL_FIND(SCALAR, slist, x, const size_t, key, -) break; case H5SL_TYPE_OBJ: - H5SL_FIND(OBJ, slist, x, -, const H5_obj_t, key, -) + H5SL_FIND(OBJ, slist, x, const H5_obj_t, key, -) break; } /* end switch */ @@ -1868,3 +2130,50 @@ H5SL_close(H5SL_t *slist) FUNC_LEAVE_NOAPI(SUCCEED); } /* end H5SL_close() */ + +/*-------------------------------------------------------------------------- + NAME + H5SL_term_interface + PURPOSE + Terminate all the H5FL factories used in this package, and clear memory + USAGE + int H5SL_term_interface() + RETURNS + Success: Positive if any action might have caused a change in some + other interface; zero otherwise. + Failure: Negative + DESCRIPTION + Release any resources allocated. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Can't report errors... + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +int H5SL_term_interface(void) +{ + size_t i; + herr_t ret; + int n = H5_interface_initialize_g ? 1 : 0; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5SL_term_interface) + + if(n) { + /* Terminate all the factories */ + for(i=0; i<H5SL_fac_nused_g; i++) { + ret = H5FL_fac_term(H5SL_fac_g[i]); + HDassert(ret >= 0); + } + H5SL_fac_nused_g = 0; + + /* Free the list of factories */ + H5SL_fac_g = (H5FL_reg_head_t **)H5MM_xfree((void *)H5SL_fac_g); + H5SL_fac_nalloc_g = 0; + + /* Mark the interface as uninitialized */ + H5_interface_initialize_g = 0; + } /* end if */ + + FUNC_LEAVE_NOAPI(n); +} /* H5SL_term_interface() */ + diff --git a/src/H5SLprivate.h b/src/H5SLprivate.h index 27bb4d1..40fbfa9 100644 --- a/src/H5SLprivate.h +++ b/src/H5SLprivate.h @@ -53,7 +53,6 @@ typedef enum { /**********/ /* Macros */ /**********/ -#define H5SL_LEVEL_MAX 32 /* (for now) */ /* Typedef for iteration operations */ typedef herr_t (*H5SL_operator_t)(void *item, void *key, @@ -62,7 +61,7 @@ typedef herr_t (*H5SL_operator_t)(void *item, void *key, /********************/ /* Private routines */ /********************/ -H5_DLL H5SL_t *H5SL_create(H5SL_type_t type, double p, size_t max_level); +H5_DLL H5SL_t *H5SL_create(H5SL_type_t type); H5_DLL size_t H5SL_count(H5SL_t *slist); H5_DLL herr_t H5SL_insert(H5SL_t *slist, void *item, const void *key); H5_DLL H5SL_node_t *H5SL_add(H5SL_t *slist, void *item, const void *key); @@ -84,6 +83,7 @@ H5_DLL herr_t H5SL_release(H5SL_t *slist); H5_DLL herr_t H5SL_free(H5SL_t *slist, H5SL_operator_t op, void *op_data); H5_DLL herr_t H5SL_close(H5SL_t *slist); H5_DLL herr_t H5SL_destroy(H5SL_t *slist, H5SL_operator_t op, void *op_data); +H5_DLL int H5SL_term_interface(void); #endif /* _H5SLprivate_H */ diff --git a/src/H5Tconv.c b/src/H5Tconv.c index 90b7a21..c621bf4 100644 --- a/src/H5Tconv.c +++ b/src/H5Tconv.c @@ -194,7 +194,7 @@ src_id, dst_id, S, D, cb_struct.user_data); \ if(except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ else if(except_ret == H5T_CONV_ABORT) \ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ @@ -203,7 +203,7 @@ src_id, dst_id, S, D, cb_struct.user_data); \ if(except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ - *((DT*)D) = (D_MIN); \ + *((DT*)D) = (DT)(D_MIN); \ else if(except_ret == H5T_CONV_ABORT) \ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ @@ -212,9 +212,9 @@ } #define H5T_CONV_Xx_NOEX_CORE(S,D,ST,DT,D_MIN,D_MAX) { \ if (*((ST*)S) > (DT)(D_MAX)) { \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ } else if (*((ST*)S) < (DT)(D_MIN)) { \ - *((DT*)D) = (D_MIN); \ + *((DT*)D) = (DT)(D_MIN); \ } else \ *((DT*)D) = (DT)(*((ST*)S)); \ } @@ -225,7 +225,7 @@ src_id, dst_id, S, D, cb_struct.user_data); \ if(except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ else if(except_ret == H5T_CONV_ABORT) \ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ @@ -234,7 +234,7 @@ } #define H5T_CONV_Ux_NOEX_CORE(S,D,ST,DT,D_MIN,D_MAX) { \ if (*((ST*)S) > (DT)(D_MAX)) { \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ } else \ *((DT*)D) = (DT)(*((ST*)S)); \ } @@ -270,12 +270,12 @@ } #define H5T_CONV_uS_CORE(S,D,ST,DT,D_MIN,D_MAX) { \ - if (sizeof(ST)==sizeof(DT) && *((ST*)S) > (D_MAX)) { \ + if (sizeof(ST)==sizeof(DT) && *((ST*)S) > (DT)(D_MAX)) { \ H5T_conv_ret_t except_ret = (cb_struct.func)(H5T_CONV_EXCEPT_RANGE_HI, \ src_id, dst_id, S, D, cb_struct.user_data); \ if(except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ else if(except_ret == H5T_CONV_ABORT) \ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ @@ -319,7 +319,7 @@ src_id, dst_id, S, D, cb_struct.user_data); \ if(except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ else if(except_ret == H5T_CONV_ABORT) \ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ @@ -330,7 +330,7 @@ if (*((ST*)S) < 0) { \ *((DT*)D) = 0; \ } else if (sizeof(ST)>sizeof(DT) && *((ST*)S) > (DT)(D_MAX)) { \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ } else \ *((DT*)D) = (DT)(*((ST*)S)); \ } @@ -384,7 +384,7 @@ src_id, dst_id, S, D, cb_struct.user_data); \ if(except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ else if(except_ret == H5T_CONV_ABORT) \ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ @@ -394,7 +394,7 @@ #define H5T_CONV_us_NOEX_CORE(S,D,ST,DT,D_MIN,D_MAX) { \ /* Assumes memory format of unsigned & signed integers is same */ \ if (*((ST*)S) > (DT)(D_MAX)) { \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ } else \ *((DT*)D) = (DT)(*((ST*)S)); \ } @@ -553,7 +553,7 @@ src_id, dst_id, S, D, cb_struct.user_data); \ if(except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ else if(except_ret == H5T_CONV_ABORT) \ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ @@ -562,7 +562,7 @@ src_id, dst_id, S, D, cb_struct.user_data); \ if(except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ - *((DT*)D) = (D_MIN); \ + *((DT*)D) = (DT)(D_MIN); \ else if(except_ret == H5T_CONV_ABORT) \ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception") \ /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ @@ -581,9 +581,9 @@ } #define H5T_CONV_Fx_NOEX_CORE(S,D,ST,DT,D_MIN,D_MAX) { \ if (*((ST*)S) > (DT)(D_MAX)) { \ - *((DT*)D) = (D_MAX); \ + *((DT*)D) = (DT)(D_MAX); \ } else if (*((ST*)S) < (DT)(D_MIN)) { \ - *((DT*)D) = (D_MIN); \ + *((DT*)D) = (DT)(D_MIN); \ } \ else \ *((DT*)D) = (DT)(*((ST*)S)); \ @@ -621,7 +621,7 @@ case H5T_CONV_INIT: \ /* Sanity check and initialize statistics */ \ cdata->need_bkg = H5T_BKG_NO; \ - if (NULL==(st=H5I_object(src_id)) || NULL==(dt=H5I_object(dst_id))) \ + if (NULL==(st=(H5T_t*)H5I_object(src_id)) || NULL==(dt=(H5T_t*)H5I_object(dst_id))) \ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, \ "unable to dereference datatype object ID") \ if (st->shared->size!=sizeof(ST) || dt->shared->size!=sizeof(DT)) \ @@ -669,7 +669,7 @@ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get conversion exception callback"); \ \ /* Get source and destination datatypes */ \ - if (NULL==(st=H5I_object(src_id)) || NULL==(dt=H5I_object(dst_id))) \ + if (NULL==(st=(H5T_t*)H5I_object(src_id)) || NULL==(dt=(H5T_t*)H5I_object(dst_id))) \ HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, \ "unable to dereference datatype object ID") \ \ @@ -714,7 +714,7 @@ } /* end if */ \ else { \ /* Single forward pass over all data */ \ - src = dst = buf; \ + src = dst = (uint8_t*)buf; \ safe=nelmts; \ } /* end else */ \ \ @@ -9755,8 +9755,8 @@ H5T_conv_f_i (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts, switch (cdata->command) { case H5T_CONV_INIT: - if (NULL==(src_p=H5I_object(src_id)) || - NULL==(dst_p=H5I_object(dst_id))) + if (NULL==(src_p=(H5T_t*)H5I_object(src_id)) || + NULL==(dst_p=(H5T_t*)H5I_object(dst_id))) HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype"); src = src_p->shared->u.atomic; dst = dst_p->shared->u.atomic; @@ -9774,8 +9774,8 @@ H5T_conv_f_i (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts, case H5T_CONV_CONV: /* Get the datatypes */ - if (NULL==(src_p=H5I_object(src_id)) || - NULL==(dst_p=H5I_object(dst_id))) + if (NULL==(src_p=(H5T_t*)H5I_object(src_id)) || + NULL==(dst_p=(H5T_t*)H5I_object(dst_id))) HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype"); src = src_p->shared->u.atomic; dst = dst_p->shared->u.atomic; @@ -10345,8 +10345,8 @@ H5T_conv_i_f (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts, switch (cdata->command) { case H5T_CONV_INIT: - if (NULL==(src_p=H5I_object(src_id)) || - NULL==(dst_p=H5I_object(dst_id))) + if (NULL==(src_p=(H5T_t*)H5I_object(src_id)) || + NULL==(dst_p=(H5T_t*)H5I_object(dst_id))) HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype"); src = src_p->shared->u.atomic; dst = dst_p->shared->u.atomic; @@ -10364,8 +10364,8 @@ H5T_conv_i_f (hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts, case H5T_CONV_CONV: /* Get the datatypes */ - if (NULL==(src_p=H5I_object(src_id)) || - NULL==(dst_p=H5I_object(dst_id))) + if (NULL==(src_p=(H5T_t*)H5I_object(src_id)) || + NULL==(dst_p=(H5T_t*)H5I_object(dst_id))) HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype"); src = src_p->shared->u.atomic; dst = dst_p->shared->u.atomic; @@ -53,7 +53,7 @@ typedef enum { /* Local variables */ static size_t H5Z_table_alloc_g = 0; static size_t H5Z_table_used_g = 0; -static H5Z_class_t *H5Z_table_g = NULL; +static H5Z_class2_t *H5Z_table_g = NULL; #ifdef H5Z_DEBUG static H5Z_stats_t *H5Z_stat_table_g = NULL; #endif /* H5Z_DEBUG */ @@ -191,7 +191,7 @@ H5Z_term_interface(void) } #endif /* H5Z_DEBUG */ /* Free the table of filters */ - H5Z_table_g = (H5Z_class_t *)H5MM_xfree(H5Z_table_g); + H5Z_table_g = (H5Z_class2_t *)H5MM_xfree(H5Z_table_g); #ifdef H5Z_DEBUG H5Z_stat_table_g = (H5Z_stats_t *)H5MM_xfree(H5Z_stat_table_g); #endif /* H5Z_DEBUG */ @@ -220,32 +220,62 @@ H5Z_term_interface(void) *------------------------------------------------------------------------- */ herr_t -H5Zregister(const H5Z_class_t *cls) +H5Zregister(const void *cls) { - herr_t ret_value=SUCCEED; /* Return value */ + const H5Z_class2_t *cls_real = (const H5Z_class2_t *) cls; /* "Real" class pointer */ + H5Z_class2_t cls_new; /* Translated class struct */ + herr_t ret_value=SUCCEED; /* Return value */ FUNC_ENTER_API(H5Zregister, FAIL) - H5TRACE1("e", "*Zc", cls); + H5TRACE1("e", "*x", cls); /* Check args */ - if (cls==NULL) + if (cls_real==NULL) HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter class") /* Check H5Z_class_t version number; this is where a function to convert * from an outdated version should be called. + * + * If the version number is invalid, we assume that the target of cls is the + * old style "H5Z_class1_t" structure, which did not contain a version + * field. In this structure, the first field is the id. Since both version + * and id are integers they will have the same value, and since id must be + * at least 256, there should be no overlap and the version of the struct + * can be determined by the value of the first field. */ - if(cls->version != H5Z_CLASS_T_VERS) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid H5Z_class_t version number"); + if(cls_real->version != H5Z_CLASS_T_VERS) { +#ifndef H5_NO_DEPRECATED_SYMBOLS + /* Assume it is an old "H5Z_class1_t" instead */ + const H5Z_class1_t *cls_old = (const H5Z_class1_t *) cls; + + /* Translate to new H5Z_class2_t */ + cls_new.version = H5Z_CLASS_T_VERS; + cls_new.id = cls_old->id; + cls_new.encoder_present = 1; + cls_new.decoder_present = 1; + cls_new.name = cls_old->name; + cls_new.can_apply = cls_old->can_apply; + cls_new.set_local = cls_old->set_local; + cls_new.filter = cls_old->filter; + + /* Set cls_real to point to the translated structure */ + cls_real = &cls_new; + +#else /* H5_NO_DEPRECATED_SYMBOLS */ + /* Deprecated symbols not allowed, throw an error */ + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid H5Z_class_t version number"); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + } /* end if */ - if (cls->id<0 || cls->id>H5Z_FILTER_MAX) + if (cls_real->id<0 || cls_real->id>H5Z_FILTER_MAX) HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identification number") - if (cls->id<H5Z_FILTER_RESERVED) + if (cls_real->id<H5Z_FILTER_RESERVED) HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "unable to modify predefined filters") - if (cls->filter==NULL) + if (cls_real->filter==NULL) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no filter function specified") /* Do it */ - if (H5Z_register (cls)<0) + if (H5Z_register (cls_real)<0) HGOTO_ERROR (H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register filter") done: @@ -269,7 +299,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5Z_register (const H5Z_class_t *cls) +H5Z_register (const H5Z_class2_t *cls) { size_t i; herr_t ret_value = SUCCEED; /* Return value */ @@ -288,7 +318,7 @@ H5Z_register (const H5Z_class_t *cls) if(i >= H5Z_table_used_g) { if(H5Z_table_used_g >= H5Z_table_alloc_g) { size_t n = MAX(H5Z_MAX_NFILTERS, 2*H5Z_table_alloc_g); - H5Z_class_t *table = (H5Z_class_t *)H5MM_realloc(H5Z_table_g, n * sizeof(H5Z_class_t)); + H5Z_class2_t *table = (H5Z_class2_t *)H5MM_realloc(H5Z_table_g, n * sizeof(H5Z_class2_t)); #ifdef H5Z_DEBUG H5Z_stats_t *stat_table = (H5Z_stats_t *)H5MM_realloc(H5Z_stat_table_g, n * sizeof(H5Z_stats_t)); #endif /* H5Z_DEBUG */ @@ -305,7 +335,7 @@ H5Z_register (const H5Z_class_t *cls) /* Initialize */ i = H5Z_table_used_g++; - HDmemcpy(H5Z_table_g+i, cls, sizeof(H5Z_class_t)); + HDmemcpy(H5Z_table_g+i, cls, sizeof(H5Z_class2_t)); #ifdef H5Z_DEBUG HDmemset(H5Z_stat_table_g+i, 0, sizeof(H5Z_stats_t)); #endif /* H5Z_DEBUG */ @@ -313,7 +343,7 @@ H5Z_register (const H5Z_class_t *cls) /* Filter already registered */ else { /* Replace old contents */ - HDmemcpy(H5Z_table_g+i, cls, sizeof(H5Z_class_t)); + HDmemcpy(H5Z_table_g+i, cls, sizeof(H5Z_class2_t)); } /* end else */ done: @@ -394,7 +424,7 @@ H5Z_unregister (H5Z_filter_t id) /* Remove filter from table */ /* Don't worry about shrinking table size (for now) */ - HDmemmove(&H5Z_table_g[i],&H5Z_table_g[i+1],sizeof(H5Z_class_t)*((H5Z_table_used_g-1)-i)); + HDmemmove(&H5Z_table_g[i],&H5Z_table_g[i+1],sizeof(H5Z_class2_t)*((H5Z_table_used_g-1)-i)); #ifdef H5Z_DEBUG HDmemmove(&H5Z_stat_table_g[i],&H5Z_stat_table_g[i+1],sizeof(H5Z_stats_t)*((H5Z_table_used_g-1)-i)); #endif /* H5Z_DEBUG */ @@ -516,7 +546,7 @@ H5Z_prelude_callback(hid_t dcpl_id, hid_t type_id, H5Z_prelude_type_t prelude_ty /* Iterate over filters */ for(u = 0; u < dcpl_pline.nused; u++) { - H5Z_class_t *fclass; /* Individual filter information */ + H5Z_class2_t *fclass; /* Individual filter information */ /* Get filter information */ if(NULL == (fclass = H5Z_find(dcpl_pline.filter[u].id))) { @@ -890,11 +920,11 @@ done: * *------------------------------------------------------------------------- */ -H5Z_class_t * +H5Z_class2_t * H5Z_find(H5Z_filter_t id) { int idx; /* Filter index in global table */ - H5Z_class_t *ret_value=NULL; /* Return value */ + H5Z_class2_t *ret_value=NULL; /* Return value */ FUNC_ENTER_NOAPI(H5Z_find, NULL) @@ -946,7 +976,7 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, { size_t i, idx, new_nbytes; int fclass_idx; /* Index of filter class in global table */ - H5Z_class_t *fclass=NULL; /* Filter class pointer */ + H5Z_class2_t *fclass=NULL; /* Filter class pointer */ #ifdef H5Z_DEBUG H5Z_stats_t *fstats=NULL; /* Filter stats pointer */ H5_timer_t timer; @@ -1242,7 +1272,7 @@ done: herr_t H5Zget_filter_info(H5Z_filter_t filter, unsigned int *filter_config_flags) { - H5Z_class_t *fclass; + H5Z_class2_t *fclass; herr_t ret_value = SUCCEED; FUNC_ENTER_API(H5Zget_filter_info, FAIL) diff --git a/src/H5Zdeflate.c b/src/H5Zdeflate.c index 56b910b..7cda2c8 100644 --- a/src/H5Zdeflate.c +++ b/src/H5Zdeflate.c @@ -37,7 +37,7 @@ static size_t H5Z_filter_deflate (unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf); /* This message derives from H5Z */ -const H5Z_class_t H5Z_DEFLATE[1] = {{ +const H5Z_class2_t H5Z_DEFLATE[1] = {{ H5Z_CLASS_T_VERS, /* H5Z_class_t version */ H5Z_FILTER_DEFLATE, /* Filter id number */ 1, /* encoder_present flag (set to true) */ diff --git a/src/H5Zfletcher32.c b/src/H5Zfletcher32.c index aa3a173..e3a77bd 100644 --- a/src/H5Zfletcher32.c +++ b/src/H5Zfletcher32.c @@ -34,7 +34,7 @@ static size_t H5Z_filter_fletcher32 (unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf); /* This message derives from H5Z */ -const H5Z_class_t H5Z_FLETCHER32[1] = {{ +const H5Z_class2_t H5Z_FLETCHER32[1] = {{ H5Z_CLASS_T_VERS, /* H5Z_class_t version */ H5Z_FILTER_FLETCHER32, /* Filter id number */ 1, /* encoder_present flag (set to true) */ diff --git a/src/H5Znbit.c b/src/H5Znbit.c index 97a00f0..6f090c3 100644 --- a/src/H5Znbit.c +++ b/src/H5Znbit.c @@ -80,7 +80,7 @@ static void H5Z_nbit_compress(unsigned char *data, unsigned d_nelmts, unsigned c size_t *buffer_size, const unsigned parms[]); /* This message derives from H5Z */ -H5Z_class_t H5Z_NBIT[1] = {{ +H5Z_class2_t H5Z_NBIT[1] = {{ H5Z_CLASS_T_VERS, /* H5Z_class_t version */ H5Z_FILTER_NBIT, /* Filter id number */ 1, /* Assume encoder present: check before registering */ diff --git a/src/H5Zpkg.h b/src/H5Zpkg.h index 9cd126e..ae33def 100644 --- a/src/H5Zpkg.h +++ b/src/H5Zpkg.h @@ -42,46 +42,46 @@ /* * Deflate filter */ -H5_DLLVAR const H5Z_class_t H5Z_DEFLATE[1]; +H5_DLLVAR const H5Z_class2_t H5Z_DEFLATE[1]; #endif /* H5_HAVE_FILTER_DEFLATE */ #ifdef H5_HAVE_FILTER_SHUFFLE /* * Shuffle filter */ -H5_DLLVAR const H5Z_class_t H5Z_SHUFFLE[1]; +H5_DLLVAR const H5Z_class2_t H5Z_SHUFFLE[1]; #endif /* H5_HAVE_FILTER_SHUFFLE */ #ifdef H5_HAVE_FILTER_FLETCHER32 /* * Fletcher32 filter */ -H5_DLLVAR const H5Z_class_t H5Z_FLETCHER32[1]; +H5_DLLVAR const H5Z_class2_t H5Z_FLETCHER32[1]; #endif /* H5_HAVE_FILTER_FLETCHER32 */ #ifdef H5_HAVE_FILTER_SZIP /* * szip filter */ -H5_DLLVAR H5Z_class_t H5Z_SZIP[1]; +H5_DLLVAR H5Z_class2_t H5Z_SZIP[1]; #endif /* H5_HAVE_FILTER_SZIP */ #ifdef H5_HAVE_FILTER_NBIT /* * nbit filter */ -H5_DLLVAR H5Z_class_t H5Z_NBIT[1]; +H5_DLLVAR H5Z_class2_t H5Z_NBIT[1]; #endif /* H5_HAVE_FILTER_NBIT */ #ifdef H5_HAVE_FILTER_SCALEOFFSET /* * scaleoffset filter */ -H5_DLLVAR H5Z_class_t H5Z_SCALEOFFSET[1]; +H5_DLLVAR H5Z_class2_t H5Z_SCALEOFFSET[1]; #endif /* H5_HAVE_FILTER_SCALEOFFSET */ /* Package-local function prototypes */ -H5_DLL void H5Z_update_class_vers(H5Z_class_t * old_vers, H5Z_class_t * curr_vers); +H5_DLL void H5Z_update_class_vers(H5Z_class2_t * old_vers, H5Z_class2_t * curr_vers); #endif /* _H5Zpkg_H */ diff --git a/src/H5Zprivate.h b/src/H5Zprivate.h index 15b7289..3ce0a0c 100644 --- a/src/H5Zprivate.h +++ b/src/H5Zprivate.h @@ -72,7 +72,8 @@ typedef struct { struct H5O_pline_t; /*forward decl*/ /* Internal API routines */ -H5_DLL herr_t H5Z_register(const H5Z_class_t *cls); +H5_DLL herr_t H5Z_init(void); +H5_DLL herr_t H5Z_register(const H5Z_class2_t *cls); H5_DLL herr_t H5Z_unregister(H5Z_filter_t id); H5_DLL herr_t H5Z_append(struct H5O_pline_t *pline, H5Z_filter_t filter, unsigned flags, size_t cd_nelmts, const unsigned int cd_values[]); @@ -83,7 +84,7 @@ H5_DLL herr_t H5Z_pipeline(const struct H5O_pline_t *pline, H5Z_EDC_t edc_read, H5Z_cb_t cb_struct, size_t *nbytes/*in,out*/, size_t *buf_size/*in,out*/, void **buf/*in,out*/); -H5_DLL H5Z_class_t *H5Z_find(H5Z_filter_t id); +H5_DLL H5Z_class2_t *H5Z_find(H5Z_filter_t id); H5_DLL herr_t H5Z_can_apply(hid_t dcpl_id, hid_t type_id); H5_DLL herr_t H5Z_set_local(hid_t dcpl_id, hid_t type_id); H5_DLL H5Z_filter_info_t *H5Z_filter_info(const struct H5O_pline_t *pline, diff --git a/src/H5Zpublic.h b/src/H5Zpublic.h index ce60650..44d2bbb 100644 --- a/src/H5Zpublic.h +++ b/src/H5Zpublic.h @@ -206,7 +206,7 @@ typedef size_t (*H5Z_func_t)(unsigned int flags, size_t cd_nelmts, * The filter table maps filter identification numbers to structs that * contain a pointers to the filter function and timing statistics. */ -typedef struct H5Z_class_t { +typedef struct H5Z_class2_t { int version; /* Version number of the H5Z_class_t struct */ H5Z_filter_t id; /* Filter ID number */ unsigned encoder_present; /* Does this filter have an encoder? */ @@ -215,13 +215,33 @@ typedef struct H5Z_class_t { H5Z_can_apply_func_t can_apply; /* The "can apply" callback for a filter */ H5Z_set_local_func_t set_local; /* The "set local" callback for a filter */ H5Z_func_t filter; /* The actual filter function */ -} H5Z_class_t; +} H5Z_class2_t; -H5_DLL herr_t H5Zregister(const H5Z_class_t *cls); +H5_DLL herr_t H5Zregister(const void *cls); H5_DLL herr_t H5Zunregister(H5Z_filter_t id); H5_DLL htri_t H5Zfilter_avail(H5Z_filter_t id); H5_DLL herr_t H5Zget_filter_info(H5Z_filter_t filter, unsigned int *filter_config_flags); +/* Symbols defined for compatibility with previous versions of the HDF5 API. + * + * Use of these symbols is deprecated. + */ +#ifndef H5_NO_DEPRECATED_SYMBOLS + +/* + * The filter table maps filter identification numbers to structs that + * contain a pointers to the filter function and timing statistics. + */ +typedef struct H5Z_class1_t { + H5Z_filter_t id; /* Filter ID number */ + const char *name; /* Comment for debugging */ + H5Z_can_apply_func_t can_apply; /* The "can apply" callback for a filter */ + H5Z_set_local_func_t set_local; /* The "set local" callback for a filter */ + H5Z_func_t filter; /* The actual filter function */ +} H5Z_class1_t; + +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + #ifdef __cplusplus } #endif diff --git a/src/H5Zscaleoffset.c b/src/H5Zscaleoffset.c index 10618c3..d59499c 100644 --- a/src/H5Zscaleoffset.c +++ b/src/H5Zscaleoffset.c @@ -80,7 +80,7 @@ static void H5Z_scaleoffset_compress(unsigned char *data, unsigned d_nelmts, uns size_t buffer_size, parms_atomic p); /* This message derives from H5Z */ -H5Z_class_t H5Z_SCALEOFFSET[1] = {{ +H5Z_class2_t H5Z_SCALEOFFSET[1] = {{ H5Z_CLASS_T_VERS, /* H5Z_class_t version */ H5Z_FILTER_SCALEOFFSET, /* Filter id number */ 1, /* Assume encoder present: check before registering */ diff --git a/src/H5Zshuffle.c b/src/H5Zshuffle.c index 3f40707..2e4f1fa 100644 --- a/src/H5Zshuffle.c +++ b/src/H5Zshuffle.c @@ -32,7 +32,7 @@ static size_t H5Z_filter_shuffle(unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf); /* This message derives from H5Z */ -const H5Z_class_t H5Z_SHUFFLE[1] = {{ +const H5Z_class2_t H5Z_SHUFFLE[1] = {{ H5Z_CLASS_T_VERS, /* H5Z_class_t version */ H5Z_FILTER_SHUFFLE, /* Filter id number */ 1, /* encoder_present flag (set to true) */ diff --git a/src/H5Zszip.c b/src/H5Zszip.c index b40c028..5da92ac 100644 --- a/src/H5Zszip.c +++ b/src/H5Zszip.c @@ -40,7 +40,7 @@ static size_t H5Z_filter_szip (unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf); /* This message derives from H5Z */ -H5Z_class_t H5Z_SZIP[1] = {{ +H5Z_class2_t H5Z_SZIP[1] = {{ H5Z_CLASS_T_VERS, /* H5Z_class_t version */ H5Z_FILTER_SZIP, /* Filter id number */ 1, /* Assume encoder present: check before registering */ diff --git a/src/H5config.h.in b/src/H5config.h.in index 1c70790..a3e879b 100644 --- a/src/H5config.h.in +++ b/src/H5config.h.in @@ -84,6 +84,9 @@ /* Define to 1 if you have the <dmalloc.h> header file. */ #undef HAVE_DMALLOC_H +/* Define if library information should be embedded in the executables */ +#undef HAVE_EMBEDDED_LIBINFO + /* Define to 1 if you have the <features.h> header file. */ #undef HAVE_FEATURES_H diff --git a/src/H5detect.c b/src/H5detect.c index b67c2b0..146750c 100644 --- a/src/H5detect.c +++ b/src/H5detect.c @@ -108,6 +108,7 @@ static void detect_C99_integers16(void); static void detect_C99_integers32(void); static void detect_C99_integers64(void); static void detect_alignments(void); +static void insert_libhdf5_settings(void); static size_t align_g[] = {1, 2, 4, 8, 16}; static jmp_buf jbuf_g; @@ -502,6 +503,64 @@ sigbus_handler(int UNUSED signo) /*------------------------------------------------------------------------- + * Function: insert_libhdf5_settings + * + * Purpose: Insert contents of libhdf5.settings so that it is included + * in all hdf5 executables. + * + * Return: void + * + * Programmer: Albert Cheng + * Apr 20, 2009 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +#define LIBSETTINGSFNAME "libhdf5.settings" +static void +insert_libhdf5_settings(void) +{ + FILE *fsettings; + char inchar; + int bol=0; /* indicates the beginning of a new line */ + + if (NULL==(fsettings=HDfopen(LIBSETTINGSFNAME, "r"))){ + perror(LIBSETTINGSFNAME); + exit(1); + } + /* print variable definition */ + printf("extern char H5libhdf5_settings[]=\n"); + bol++; + while (EOF != (inchar = getc(fsettings))){ + if (bol){ + /* Start a new line */ + printf("\t\""); + bol = 0; + } + if (inchar == '\n'){ + /* end of a line */ + printf("\\n\"\n"); + bol++; + }else{ + putchar(inchar); + } + } + if (feof(fsettings)){ + /* wrap up */ + if (!bol){ + /* EOF found without a new line */ + printf("\\n\"\n"); + }; + printf(";\n\n"); + }else{ + fprintf(stderr, "Read errors encountered with %s\n", LIBSETTINGSFNAME); + exit(1); + } +} + + +/*------------------------------------------------------------------------- * Function: print_results * * Purpose: Prints information about the detected data types. @@ -580,6 +639,11 @@ print_results(int nd, detected_t *d, int na, malign_t *misc_align) /*******************/\n\ \n"); +#ifdef H5_HAVE_EMBEDDED_LIBINFO + /* Insert content of libhdf5.settings */ + insert_libhdf5_settings(); +#endif + /* The interface initialization function */ printf("\n\ \n\ diff --git a/src/H5private.h b/src/H5private.h index 695b015..d392548 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -144,6 +144,7 @@ #define VC_EXTRALEAN /*Exclude rarely-used stuff from Windows headers */ #include <windows.h> +#include <direct.h> /* For _getcwd() */ #endif /*_WIN32*/ diff --git a/src/H5public.h b/src/H5public.h index 367e601..371847d 100644 --- a/src/H5public.h +++ b/src/H5public.h @@ -71,10 +71,10 @@ extern "C" { /* Version numbers */ #define H5_VERS_MAJOR 1 /* For major interface/format changes */ #define H5_VERS_MINOR 9 /* For minor interface/format changes */ -#define H5_VERS_RELEASE 36 /* For tweaks, bug-fixes, or development */ +#define H5_VERS_RELEASE 39 /* For tweaks, bug-fixes, or development */ #define H5_VERS_SUBRELEASE "FA_a1" /* For pre-releases like snap0 */ /* Empty string for real releases. */ -#define H5_VERS_INFO "HDF5 library version: 1.9.36-FA_a1" /* Full version string */ +#define H5_VERS_INFO "HDF5 library version: 1.9.39-FA_a1" /* Full version string */ #define H5check() H5check_version(H5_VERS_MAJOR,H5_VERS_MINOR, \ H5_VERS_RELEASE) diff --git a/src/H5trace.c b/src/H5trace.c index 4a42f0b..6e2578b 100644 --- a/src/H5trace.c +++ b/src/H5trace.c @@ -1978,7 +1978,7 @@ H5_trace (const double *returning, const char *func, const char *type, ...) fprintf(out, "NULL"); } } else { - H5Z_class_t *filter = va_arg (ap, H5Z_class_t*); /*lint !e64 Type mismatch not really occuring */ + H5Z_class2_t *filter = va_arg (ap, H5Z_class2_t*); /*lint !e64 Type mismatch not really occuring */ fprintf (out, "0x%lx", (unsigned long)filter); } break; diff --git a/src/H5vers.txt b/src/H5vers.txt index 00ab84b..18a88d9 100644 --- a/src/H5vers.txt +++ b/src/H5vers.txt @@ -71,4 +71,5 @@ FUNCTION: H5Topen; ; v10, v18 # (although not required, it's easier to compare this file with the headers # generated if the list below is in alphanumeric sort order - QAK) TYPEDEF: H5E_auto; v10, v18 +TYPEDEF: H5Z_class; v16, v18 diff --git a/src/H5version.h b/src/H5version.h index fd9e780..58de2ab 100644 --- a/src/H5version.h +++ b/src/H5version.h @@ -134,6 +134,10 @@ #define H5E_auto_t_vers 1 #endif /* !defined(H5E_auto_t_vers) */ +#if !defined(H5Z_class_t_vers) +#define H5Z_class_t_vers 1 +#endif /* !defined(H5Z_class_t_vers) */ + #endif /* H5_USE_16_API */ @@ -399,5 +403,17 @@ #error "H5E_auto_t_vers set to invalid value" #endif /* H5E_auto_t_vers */ + +#if !defined(H5Z_class_t_vers) || H5Z_class_t_vers == 2 +#ifndef H5Z_class_t_vers +#define H5Z_class_t_vers 2 +#endif /* H5Z_class_t_vers */ +#define H5Z_class_t H5Z_class2_t +#elif H5Z_class_t_vers == 1 +#define H5Z_class_t H5Z_class1_t +#else /* H5Z_class_t_vers */ +#error "H5Z_class_t_vers set to invalid value" +#endif /* H5Z_class_t_vers */ + #endif /* H5version_H */ diff --git a/src/Makefile.am b/src/Makefile.am index b2b0a98..f6d92dd 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -61,7 +61,7 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5G.c H5Gbtree2.c H5Gcache.c \ H5Gcompact.c H5Gdense.c H5Gdeprec.c H5Gent.c \ H5Gint.c H5Glink.c \ - H5Gloc.c H5Gname.c H5Gnode.c H5Gobj.c H5Goh.c H5Gstab.c H5Gtest.c \ + H5Gloc.c H5Gname.c H5Gnode.c H5Gobj.c H5Goh.c H5Groot.c H5Gstab.c H5Gtest.c \ H5Gtraverse.c \ H5HF.c H5HFbtree2.c H5HFcache.c H5HFdbg.c H5HFdblock.c H5HFdtable.c \ H5HFhdr.c H5HFhuge.c H5HFiblock.c H5HFiter.c H5HFman.c H5HFsection.c \ diff --git a/src/Makefile.in b/src/Makefile.in index a437a3e..57a4cc8 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.10.1 from Makefile.am. +# Makefile.in generated by automake 1.10.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -97,9 +97,9 @@ am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \ H5FScache.lo H5FSdbg.lo H5FSsection.lo H5FSstat.lo H5FStest.lo \ H5G.lo H5Gbtree2.lo H5Gcache.lo H5Gcompact.lo H5Gdense.lo \ H5Gdeprec.lo H5Gent.lo H5Gint.lo H5Glink.lo H5Gloc.lo \ - H5Gname.lo H5Gnode.lo H5Gobj.lo H5Goh.lo H5Gstab.lo H5Gtest.lo \ - H5Gtraverse.lo H5HF.lo H5HFbtree2.lo H5HFcache.lo H5HFdbg.lo \ - H5HFdblock.lo H5HFdtable.lo H5HFhdr.lo H5HFhuge.lo \ + H5Gname.lo H5Gnode.lo H5Gobj.lo H5Goh.lo H5Groot.lo H5Gstab.lo \ + H5Gtest.lo H5Gtraverse.lo H5HF.lo H5HFbtree2.lo H5HFcache.lo \ + H5HFdbg.lo H5HFdblock.lo H5HFdtable.lo H5HFhdr.lo H5HFhuge.lo \ H5HFiblock.lo H5HFiter.lo H5HFman.lo H5HFsection.lo \ H5HFspace.lo H5HFstat.lo H5HFtest.lo H5HFtiny.lo H5HG.lo \ H5HGcache.lo H5HGdbg.lo H5HL.lo H5HLcache.lo H5HLdbg.lo \ @@ -409,7 +409,7 @@ CHECK_CLEANFILES = *.chkexe *.chklog *.clog # Add libtool shared library version numbers to the HDF5 library # See libtool versioning documentation online. LT_VERS_INTERFACE = 6 -LT_VERS_REVISION = 26 +LT_VERS_REVISION = 29 LT_VERS_AGE = 0 H5detect_CFLAGS = -g @@ -445,7 +445,7 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5G.c H5Gbtree2.c H5Gcache.c \ H5Gcompact.c H5Gdense.c H5Gdeprec.c H5Gent.c \ H5Gint.c H5Glink.c \ - H5Gloc.c H5Gname.c H5Gnode.c H5Gobj.c H5Goh.c H5Gstab.c H5Gtest.c \ + H5Gloc.c H5Gname.c H5Gnode.c H5Gobj.c H5Goh.c H5Groot.c H5Gstab.c H5Gtest.c \ H5Gtraverse.c \ H5HF.c H5HFbtree2.c H5HFcache.c H5HFdbg.c H5HFdblock.c H5HFdtable.c \ H5HFhdr.c H5HFhuge.c H5HFiblock.c H5HFiter.c H5HFman.c H5HFsection.c \ @@ -525,8 +525,8 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ @@ -711,6 +711,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gnode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gobj.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Goh.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Groot.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gstab.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gtest.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Gtraverse.Plo@am__quote@ @@ -936,7 +937,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ - $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS |