diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2008-01-03 18:24:01 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2008-01-03 18:24:01 (GMT) |
commit | 04d73e7a0c69839922cf78adcb04e2617fc0f5b9 (patch) | |
tree | e5fa979c46410c6b81cb5709d47381672becdd3e /src/H5FDspace.c | |
parent | 35694d44ae9aedaeed71850222ce014606ed3572 (diff) | |
download | hdf5-04d73e7a0c69839922cf78adcb04e2617fc0f5b9.zip hdf5-04d73e7a0c69839922cf78adcb04e2617fc0f5b9.tar.gz hdf5-04d73e7a0c69839922cf78adcb04e2617fc0f5b9.tar.bz2 |
[svn-r14363] Description:
Refactor file space allocation routines into separate source module.
Tested on:
FreeBSD/32 6.2 (duty) in debug mode
Mac OS X/32 10.4.10 (amazon) in debug mode
Diffstat (limited to 'src/H5FDspace.c')
-rw-r--r-- | src/H5FDspace.c | 1738 |
1 files changed, 1738 insertions, 0 deletions
diff --git a/src/H5FDspace.c b/src/H5FDspace.c new file mode 100644 index 0000000..7bd72cc --- /dev/null +++ b/src/H5FDspace.c @@ -0,0 +1,1738 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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: H5FDspace.c + * Jan 3 2008 + * Quincey Koziol <koziol@hdfgroup.org> + * + * Purpose: Space allocation routines for the file. + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5FD_PACKAGE /*suppress error about including H5FDpkg */ + +/* Interface initialization */ +#define H5_INTERFACE_INIT_FUNC H5FD_space_init_interface + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fprivate.h" /* File access */ +#include "H5FDpkg.h" /* File Drivers */ +#include "H5FDmulti.h" /* Usage-partitioned file family */ +#include "H5MMprivate.h" /* Memory management */ + + +/****************/ +/* Local Macros */ +/****************/ + +/* Define this to display information about file allocations */ +/* #define H5FD_ALLOC_DEBUG */ + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Package Typedefs */ +/********************/ + + +/********************/ +/* Local Prototypes */ +/********************/ +static haddr_t H5FD_alloc_from_free_list(H5FD_t *file, H5FD_mem_t type, + hsize_t size); +static haddr_t H5FD_aggr_alloc(H5FD_t *file, H5FD_blk_aggr_t *aggr, + H5FD_blk_aggr_t *other_aggr, H5FD_mem_t type, hid_t dxpl_id, hsize_t size); +static herr_t H5FD_aggr_adjoin(const H5FD_t *file, H5FD_blk_aggr_t *aggr, + H5FD_free_t *last); +static htri_t H5FD_aggr_can_extend(const H5FD_t *file, const H5FD_blk_aggr_t *aggr, + haddr_t eoa, haddr_t end); +static herr_t H5FD_aggr_shift(H5FD_blk_aggr_t *aggr, hsize_t extra); +static herr_t H5FD_aggr_query(const H5FD_t *file, const H5FD_blk_aggr_t *aggr, + haddr_t *addr, hsize_t *size); +static haddr_t H5FD_real_alloc(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size); +static haddr_t H5FD_update_eoa(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size); + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* Declare a free list to manage the H5FD_free_t struct */ +H5FL_DEFINE(H5FD_free_t); + +/* Declare a PQ free list to manage the metadata accumulator buffer */ +H5FL_BLK_DEFINE(meta_accum); + + + +/*-------------------------------------------------------------------------- +NAME + H5FD_space_init_interface -- Initialize interface-specific information +USAGE + herr_t H5FD_space_init_interface() + +RETURNS + Non-negative on success/Negative on failure +DESCRIPTION + Initializes any interface-specific data or routines. (Just calls + H5FD_init_iterface currently). + +--------------------------------------------------------------------------*/ +static herr_t +H5FD_space_init_interface(void) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_space_init_interface) + + FUNC_LEAVE_NOAPI(H5FD_init()) +} /* H5FD_space_init_interface() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_free_freelist + * + * Purpose: Split off from H5FD_close(). Free the elements in the + * free list for this file driver. + * + * Return: Success: SUCCEED + * Failure: Never fails + * + * Programmer: Bill Wendling + * 17. February 2003 + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_free_freelist(H5FD_t *file) +{ + H5FD_mem_t i; +#ifdef H5FD_ALLOC_DEBUG + unsigned nblocks = 0; + hsize_t nbytes = 0; +#endif /* H5FD_ALLOC_DEBUG */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_free_freelist) + + /* check args */ + HDassert(file && file->cls); + + /* + * Free all free-lists, leaking any memory thus described. Also leaks + * file space allocated but not used when metadata aggregation is + * turned on. + */ + for(i = H5FD_MEM_DEFAULT; i < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, i)) { + H5FD_free_t *cur, *next; + + for( cur = file->fl[i]; cur; cur = next) { +#ifdef H5FD_ALLOC_DEBUG + ++nblocks; + nbytes += cur->size; +#endif /* H5FD_ALLOC_DEBUG */ + next = cur->next; + H5FL_FREE(H5FD_free_t, cur); + } /* end for */ + + file->fl[i] = NULL; + } /* end for */ + +#ifdef H5FD_ALLOC_DEBUG + if(nblocks) + HDfprintf(stderr, "%s: leaked %Hu bytes of file memory in %u blocks\n", + "H5FD_free_freelist", nbytes, nblocks); +#endif /* H5FD_ALLOC_DEBUG */ + + /* Check if we need to reset the metadata accumulator information */ + if(file->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) { + /* Free the buffer */ + if(file->meta_accum) + file->meta_accum = H5FL_BLK_FREE(meta_accum, file->meta_accum); + + /* Reset the buffer sizes & location */ + file->accum_buf_size = file->accum_size = 0; + file->accum_loc = HADDR_UNDEF; + file->accum_dirty = 0; + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FD_free_freelist() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_alloc + * + * Purpose: Private version of H5FDalloc(). + * + * Return: Success: The format address of the new file memory. + * Failure: The undefined address HADDR_UNDEF + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + *------------------------------------------------------------------------- + */ +haddr_t +H5FD_alloc(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size) +{ + haddr_t ret_value = HADDR_UNDEF; + + FUNC_ENTER_NOAPI(H5FD_alloc, HADDR_UNDEF) +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: type = %u, size = %Hu\n", FUNC, (unsigned)type, size); +#endif /* H5FD_ALLOC_DEBUG */ + + /* check args */ + assert(file); + assert(file->cls); + assert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES); + assert(size > 0); + +#ifdef H5F_DEBUG + if(H5DEBUG(F)) + HDfprintf(H5DEBUG(F), "%s: alignment=%Hd, threshold=%Hd, size=%Hd\n", + FUNC, file->alignment, file->threshold, size); +#endif /* H5F_DEBUG */ + + /* Try to allocate from the free list first */ + if((ret_value = H5FD_alloc_from_free_list(file, type, size)) != HADDR_UNDEF) + HGOTO_DONE(ret_value) + +#ifdef H5F_DEBUG + if(H5DEBUG(F)) + HDfprintf(H5DEBUG(F), "%s: Could not allocate from freelists\n", FUNC); +#endif /* H5F_DEBUG */ + + if(type != H5FD_MEM_DRAW) { + /* Handle metadata differently from "raw" data */ + if(HADDR_UNDEF == (ret_value = H5FD_aggr_alloc(file, &(file->meta_aggr), &(file->sdata_aggr), type, dxpl_id, size))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate metadata") + } /* end if */ + else { + /* Allocate "raw" data */ + if(HADDR_UNDEF == (ret_value = H5FD_aggr_alloc(file, &(file->sdata_aggr), &(file->meta_aggr), type, dxpl_id, size))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate raw data") + } /* end else */ + +done: +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: ret_value = %a\n", FUNC, ret_value); +#endif /* H5FD_ALLOC_DEBUG */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_alloc() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_alloc_from_free_list + * + * Purpose: Try to allocate SIZE bytes of memory from the free list + * if possible. + * + * This is split from H5FD_alloc(). + * + * Return: Success: The format address of the new file memory. + * Failure: The undefined address HADDR_UNDEF + * + * Programmer: Bill Wendling + * 02. December, 2002 + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_alloc_from_free_list(H5FD_t *file, H5FD_mem_t type, hsize_t size) +{ + H5FD_mem_t mapped_type; + haddr_t ret_value = HADDR_UNDEF; + + FUNC_ENTER_NOAPI(H5FD_alloc_from_free_list, HADDR_UNDEF) +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: type = %u, size = %Hu\n", FUNC, (unsigned)type, size); +#endif /* H5FD_ALLOC_DEBUG */ + + assert(file); + assert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES); + assert(size > 0); + + /* Map the allocation request to a free list */ + if(H5FD_MEM_DEFAULT == file->cls->fl_map[type]) + mapped_type = type; + else + mapped_type = file->cls->fl_map[type]; + + /* + * Try to satisfy the request from the free list. Only perform the + * search if the free list has the potential of satisfying the + * request. + * + * Here, aligned requests are requests that are >= threshold and + * alignment > 1. + * + * For non-aligned request, first try to find an exact match, + * otherwise use the best match which is the smallest size that meets + * the requested size. + * + * For aligned address request, find a block in the following order + * of preferences: + * + * 1. block address is aligned and exact match in size; + * 2. block address is aligned with smallest size > requested size; + * 3. block address is not aligned with smallest size >= requested size. + */ + if(mapped_type >= H5FD_MEM_DEFAULT && (file->maxsize == 0 || size <= file->maxsize)) { + H5FD_free_t *prev = NULL, *best = NULL; + H5FD_free_t *cur = file->fl[mapped_type]; + hbool_t found_aligned = FALSE; + hbool_t need_aligned; + hsize_t head; + + need_aligned = file->alignment > 1 && size >= file->threshold; + + while(cur) { + if(cur->size > file->maxsize) + file->maxsize = cur->size; + + if(need_aligned) { + if((head = cur->addr % file->alignment) == 0) { + /* + * Aligned address + */ + if(cur->size >= size) { + if(cur->size == size) { + /* exact match */ + ret_value = cur->addr; + + /* + * Make certain we don't hand out a block of raw data + * from the free list which overlaps with the metadata + * aggregation buffer (if it's turned on) + */ + if(type == H5FD_MEM_DRAW && + (file->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && + H5F_addr_overlap(ret_value, size, + file->accum_loc, file->accum_size)) { + ret_value = HADDR_UNDEF; + } else { + if(prev) + prev->next = cur->next; + else + file->fl[mapped_type] = cur->next; + + H5FL_FREE(H5FD_free_t, cur); + + if(size == file->maxsize) + file->maxsize = 0; /*unknown*/ + +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: Exact size match (aligned)\n", FUNC); +#endif /* H5FD_ALLOC_DEBUG */ + HGOTO_DONE(ret_value) + } + } + else + /* Favor smallest block, that's closest to the beginning of the file */ + if(!best || !found_aligned || cur->size < best->size || + (cur->size == best->size && H5F_addr_lt(cur->addr, best->addr))) { + best = cur; + found_aligned = TRUE; + } + } /* end if */ + } else { + /* + * Non-aligned address + * + * Check to see if this block is big enough to skip + * to the next aligned address and is still big + * enough for the requested size. The extra + * (cur->size > head) is for preventing unsigned + * underflow. (This could be improved by checking for + * an exact match after excluding the head. Such + * match is as good as the found_aligned case above.) + */ + head = file->alignment - head; /* actual head size */ + + if(!found_aligned && cur->size > head && cur->size-head >= size) { + /* Favor smallest block, that's closest to the beginning of the file */ + if(!best || cur->size < best->size || + (cur->size == best->size && H5F_addr_lt(cur->addr, best->addr))) + best = cur; + } /* end if */ + } /* end else */ + } else { + /* !need_aligned */ + if(cur->size >= size) { + if(cur->size == size) { + /* exact match */ + ret_value = cur->addr; + + /* + * Make certain we don't hand out a block of raw data + * from the free list which overlaps with the metadata + * aggregation buffer (if it's turned on) + */ + if(type == H5FD_MEM_DRAW && + (file->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && + H5F_addr_overlap(ret_value, size, file->accum_loc, + file->accum_size)) { + ret_value = HADDR_UNDEF; + } else { + if(prev) + prev->next = cur->next; + else + file->fl[mapped_type] = cur->next; + + H5FL_FREE(H5FD_free_t, cur); + + if(size == file->maxsize) + file->maxsize = 0; /*unknown*/ + +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: Exact size match (unaligned)\n", FUNC); +#endif /* H5FD_ALLOC_DEBUG */ + HGOTO_DONE(ret_value) + } + } /* end if */ + else { + /* Favor smallest block, that's closest to the beginning of the file */ + if(!best || cur->size < best->size || + (cur->size == best->size && H5F_addr_lt(cur->addr, best->addr))) + best = cur; + } /* end else */ + } /* end if */ + } /* end else */ + + prev = cur; + cur = cur->next; + } /* end while */ + + /* Couldn't find exact match, use best fitting piece found */ + if(best) { +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: Splitting %Hu byte sized block\n", FUNC, best->size); +#endif /* H5FD_ALLOC_DEBUG */ + if(best->size == file->maxsize) + file->maxsize = 0; /*unknown*/ + + if(!need_aligned || found_aligned) { + /* free only tail */ + ret_value = best->addr; + + /* + * Make certain we don't hand out a block of raw data + * from the free list which overlaps with the metadata + * aggregation buffer (if it's turned on) + */ + if(type == H5FD_MEM_DRAW && + (file->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && + H5F_addr_overlap(ret_value, size, file->accum_loc, + file->accum_size)) { + ret_value = HADDR_UNDEF; + } else { + best->addr += size; /* Reduce size of block on free list */ + best->size -= size; + HGOTO_DONE(ret_value) + } + } else { + /* + * Split into 3 pieces. Keep the the head and tail in the + * freelist. + */ + H5FD_free_t *tmp = NULL; + + head = file->alignment - (best->addr % file->alignment); + ret_value = best->addr + head; + + /* + * Make certain we don't hand out a block of raw data + * from the free list which overlaps with the metadata + * aggregation buffer (if it's turned on) + */ + if(type == H5FD_MEM_DRAW && + (file->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && + H5F_addr_overlap(ret_value, size, file->accum_loc, file->accum_size)) { + ret_value = HADDR_UNDEF; + } else { + /* Attempt to allocate memory for temporary node */ + if((tmp = H5FL_MALLOC(H5FD_free_t))==NULL) + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "free block allocation failed") + + if((tmp->size = (best->size - (head + size)))!=0) { + tmp->addr = best->addr + (head + size); + tmp->next = best->next; + best->next = tmp; + } else { + /* no tail piece */ + H5FL_FREE(H5FD_free_t,tmp); + } + + best->size = head; + HGOTO_DONE(ret_value) + } /* end else */ + } /* end else */ + } /* end if */ + } /* end if */ + +done: +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: ret_value = %a\n", FUNC, ret_value); +#endif /* H5FD_ALLOC_DEBUG */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_alloc_from_free_list() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_aggr_alloc + * + * Purpose: Try to allocate SIZE bytes of memory from an aggregator + * block if possible. + * + * This is split from H5FD_alloc(). + * + * Return: Success: The format address of the new file memory. + * Failure: The undefined address HADDR_UNDEF + * + * Programmer: Bill Wendling + * 2. December, 2002 + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_aggr_alloc(H5FD_t *file, H5FD_blk_aggr_t *aggr, H5FD_blk_aggr_t *other_aggr, + H5FD_mem_t type, hid_t dxpl_id, hsize_t size) +{ + haddr_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5FD_aggr_alloc) +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: type = %u, size = %Hu\n", FUNC, (unsigned)type, size); +#endif /* H5FD_ALLOC_DEBUG */ + + /* check args */ + HDassert(file); + HDassert(aggr); + HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA); + HDassert(other_aggr); + HDassert(other_aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || other_aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA); + HDassert(other_aggr->feature_flag != aggr->feature_flag); + HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES); + HDassert(size > 0); + + /* + * If the aggregation feature is enabled for this VFL + * driver, allocate "generic" space and sub-allocate out of + * that, if possible. Otherwise just allocate through + * H5FD_real_alloc() + */ + if(file->feature_flags & aggr->feature_flag) { +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: aggr = {%a, %Hu, %Hu}\n", FUNC, aggr->addr, aggr->tot_size, aggr->size); +#endif /* H5FD_ALLOC_DEBUG */ + /* Check if the space requested is larger than the space left in the block */ + if(size > aggr->size) { + haddr_t new_space; /* Address for newly allocated space */ + + /* Check if the block asked for is too large for 'normal' aggregator block */ + if(size >= aggr->alloc_size) { + /* Allocate more room for this new block the regular way */ + if(HADDR_UNDEF == (new_space = H5FD_real_alloc(file, type, dxpl_id, size))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate aggregation block") + + /* Check if the new space is at the end of the current block */ + if((aggr->addr + aggr->size) == new_space) { + /* + * Treat the allocation request as if the current block + * grew by the amount allocated and just update the address. + * + * Don't bother updating the block's size since it will + * just grow and shrink by the same amount. + * + * _Do_ add to the total size aggregated. + * + */ + ret_value = aggr->addr; + aggr->addr += size; + aggr->tot_size += size; + } /* end if */ + else { + /* Check if the new space is at the end of the _other_ block */ + if(other_aggr->size > 0 && (other_aggr->addr + other_aggr->size) == new_space) { +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: New block is at end of 'other' block: other_aggr = {%a, %Hu, %Hu}\n", FUNC, other_aggr->addr, other_aggr->tot_size, other_aggr->size); +#endif /* H5FD_ALLOC_DEBUG */ + /* If the other block has used at least the + * 'allocation' amount for that block, shift the + * newly allocated space down over the remainder + * in the 'other block', shift the 'other block' + * up by the same amount and free it. (Which + * should amount to "bubbling" the remainder in + * the 'other block' to the end of the file and + * then "popping" the bubble by shrinking the + * file) + */ + if((other_aggr->tot_size - other_aggr->size) >= other_aggr->alloc_size) { + H5FD_mem_t alloc_type = (other_aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ? H5FD_MEM_DEFAULT : H5FD_MEM_DRAW); /* Type of file memory to work with */ + haddr_t free_addr = (new_space + size) - other_aggr->size; /* Address of free space in 'other block' shifted toward end of the file */ + hsize_t free_size = other_aggr->size; /* Size of the free space in 'other block' */ + +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: Freeing 'other' block\n", FUNC); +#endif /* H5FD_ALLOC_DEBUG */ + /* Reset 'other' block's info */ + other_aggr->addr = 0; + other_aggr->tot_size = 0; + other_aggr->size = 0; + + /* Shift newly allocated space down */ + new_space -= free_size; + + /* Return the unused portion of the 'other' block to a free list */ + if(H5FD_free(file, alloc_type, dxpl_id, free_addr, free_size) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, HADDR_UNDEF, "can't free aggregation block") + } /* end if */ + } /* end if */ + + /* Use the new space allocated, leaving the old block */ + ret_value = new_space; + } /* end else */ + } /* end if */ + else { + H5FD_mem_t alloc_type = (aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ? H5FD_MEM_DEFAULT : H5FD_MEM_DRAW); /* Type of file memory to work with */ + + /* Allocate another block */ +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: Allocating block\n", FUNC); +#endif /* H5FD_ALLOC_DEBUG */ + if(HADDR_UNDEF == (new_space = H5FD_real_alloc(file, alloc_type, dxpl_id, aggr->alloc_size))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate aggregation block") + + /* Check if the new space is at the end of the current block */ + if(aggr->addr + aggr->size == new_space) { + aggr->size += aggr->alloc_size; + aggr->tot_size += aggr->alloc_size; + } /* end if */ + else { + hsize_t new_size; /* Size of new aggregator block */ + + /* Return the unused portion of the block to a free list */ + if(aggr->size > 0) + if(H5FD_free(file, alloc_type, dxpl_id, aggr->addr, aggr->size) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, HADDR_UNDEF, "can't free aggregation block") + + /* Check if the new space is at the end of the _other_ block */ + if(other_aggr->size > 0 && (other_aggr->addr + other_aggr->size) == new_space) { +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: New block is at end of 'other' block: other_aggr = {%a, %Hu, %Hu}\n", FUNC, other_aggr->addr, other_aggr->tot_size, other_aggr->size); +#endif /* H5FD_ALLOC_DEBUG */ +#ifdef QAK + /* If the other block has used at least the + * 'allocation' amount for that block, give the + * remaining free space in the 'other' block to + * the new space allocated for 'this' block. + */ + if((other_aggr->tot_size - other_aggr->size) >= other_aggr->alloc_size) { +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: Absorbing 'other' block\n", FUNC); +#endif /* H5FD_ALLOC_DEBUG */ + /* Absorb the remaining free space into newly allocated block */ + new_space -= other_aggr->size; + new_size = aggr->alloc_size + other_aggr->size; + + /* Reset the info for the 'other' block */ + other_aggr->addr = 0; + other_aggr->tot_size = 0; + other_aggr->size = 0; + } /* end if */ + else + new_size = aggr->alloc_size; +#else /* QAK */ + /* If the other block has used at least the + * 'allocation' amount for that block, shift the + * newly allocated space down over the remainder + * in the 'other block', shift the 'other block' + * up by the same amount and free it. (Which + * should amount to "bubbling" the remainder in + * the 'other block' to the end of the file and + * then "popping" the bubble by shrinking the + * file) + */ + if((other_aggr->tot_size - other_aggr->size) >= other_aggr->alloc_size) { + H5FD_mem_t other_type = (other_aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ? H5FD_MEM_DEFAULT : H5FD_MEM_DRAW); /* Type of file memory to work with */ + haddr_t free_addr = (new_space + aggr->alloc_size) - other_aggr->size; /* Address of free space in 'other block' shifted toward end of the file */ + hsize_t free_size = other_aggr->size; /* Size of the free space in 'other block' */ + +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: Freeing 'other' block\n", FUNC); +#endif /* H5FD_ALLOC_DEBUG */ + /* Reset 'other' block's info */ + other_aggr->addr = 0; + other_aggr->tot_size = 0; + other_aggr->size = 0; + + /* Shift newly allocated space down */ + new_space -= free_size; + + /* Return the unused portion of the 'other' block to a free list */ + if(H5FD_free(file, other_type, dxpl_id, free_addr, free_size) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, HADDR_UNDEF, "can't free aggregation block") + } /* end if */ + new_size = aggr->alloc_size; +#endif /* QAK */ + } /* end if */ + else + new_size = aggr->alloc_size; + + /* Point the aggregator at the newly allocated block */ + aggr->addr = new_space; + aggr->size = new_size; + aggr->tot_size = new_size; + } /* end else */ + + /* Allocate space out of the metadata block */ + ret_value = aggr->addr; + aggr->size -= size; + aggr->addr += size; + } /* end else */ + } /* end if */ + else { + /* Allocate space out of the block */ + ret_value = aggr->addr; + aggr->size -= size; + aggr->addr += size; + } + } /* end if */ + else { + /* Allocate data the regular way */ + if(HADDR_UNDEF == (ret_value = H5FD_real_alloc(file, type, dxpl_id, size))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space") + } /* end else */ + +done: +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: ret_value = %a\n", FUNC, ret_value); +#endif /* H5FD_ALLOC_DEBUG */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_aggr_alloc() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_aggr_adjoin + * + * Purpose: Check if a newly freed block of space in the file adjoins an + * aggregator block + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Thursday, December 13, 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_aggr_adjoin(const H5FD_t *file, H5FD_blk_aggr_t *aggr, H5FD_free_t *last) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_aggr_adjoin) + + /* Check args */ + HDassert(file); + HDassert(file->cls); + HDassert(aggr); + HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA); + HDassert(last); + + /* Check if this free block adjoins the aggregator */ + if((file->feature_flags & aggr->feature_flag) && aggr->size > 0) { + hbool_t adjoins = FALSE; /* Whether the block adjoined the aggregator */ + + /* Does the newly freed space adjoin the end of the aggregator */ + if((aggr->addr + aggr->size) == last->addr) { + last->addr = aggr->addr; + adjoins = TRUE; + } /* end if */ + /* Does the newly freed space adjoin the beginning of the aggregator */ + else if((last->addr + last->size) == aggr->addr) + adjoins = TRUE; + + /* Reset aggregator information, if adjoined */ + if(adjoins) { +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: Adjoined flag = %lx aggregator\n", "H5FD_aggr_adjoin", aggr->feature_flag); +#endif /* H5FD_ALLOC_DEBUG */ + last->size += aggr->size; + aggr->addr = 0; + aggr->size = 0; + } /* end if */ + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FD_aggr_adjoin() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_aggr_can_extend + * + * Purpose: Check is an aggregator block can be extended + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Thursday, December 13, 2007 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5FD_aggr_can_extend(const H5FD_t *file, const H5FD_blk_aggr_t *aggr, haddr_t eoa, + haddr_t end) +{ + htri_t ret_value = FALSE; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_aggr_can_extend) + + /* Check args */ + HDassert(file); + HDassert(aggr); + HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA); + + /* Check if this aggregator is active */ + if(file->feature_flags & aggr->feature_flag) { + /* If the aggregator block is at the end of the file, and the block to + * test adjoins the beginning of the aggregator block, then it's + * extendable + */ + if((aggr->addr + aggr->size) == eoa && end == aggr->addr) + HGOTO_DONE(TRUE) + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_aggr_can_extend() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_aggr_extend + * + * Purpose: Shift an aggregator block in the file + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Thursday, December 13, 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_aggr_shift(H5FD_blk_aggr_t *aggr, hsize_t extra) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_aggr_shift) + + /* Check args */ + HDassert(aggr); + HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA); + + /* Shift the aggregator block by the extra amount */ + aggr->addr += extra; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FD_aggr_shift() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_aggr_query + * + * Purpose: Query a block aggregator's current address & size info + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Thursday, December 13, 2007 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_aggr_query(const H5FD_t *file, const H5FD_blk_aggr_t *aggr, haddr_t *addr, + hsize_t *size) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_aggr_query) + + /* Check args */ + HDassert(file); + HDassert(aggr); + HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA); + + /* Check if this aggregator is active */ + if(file->feature_flags & aggr->feature_flag) { + *addr = aggr->addr; + *size = aggr->size; + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FD_aggr_query() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_aggr_reset + * + * Purpose: Reset a block aggregator, returning any space back to file + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Thursday, December 13, 2007 + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_aggr_reset(H5FD_t *file, H5FD_blk_aggr_t *aggr, hid_t dxpl_id) +{ + H5FD_mem_t alloc_type; /* Type of file memory to work with */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_aggr_reset, FAIL) + + /* Check args */ + HDassert(file); + HDassert(aggr); + HDassert(aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA || aggr->feature_flag == H5FD_FEAT_AGGREGATE_SMALLDATA); + + /* Set the type of memory in the file */ + alloc_type = (aggr->feature_flag == H5FD_FEAT_AGGREGATE_METADATA ? H5FD_MEM_DEFAULT : H5FD_MEM_DRAW); /* Type of file memory to work with */ + + /* Check if this aggregator is active */ + if(file->feature_flags & aggr->feature_flag) { + /* Return the unused portion of the metadata block to a free list */ + if(aggr->size > 0) + if(H5FD_free(file, alloc_type, dxpl_id, aggr->addr, aggr->size) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "can't free aggregator block") + + /* Reset aggregator block information */ + aggr->tot_size = 0; + aggr->addr = 0; + aggr->size = 0; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_aggr_reset() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_real_alloc + * + * Purpose: Double private version of H5FDalloc() :-) + * + * Return: Success: The format address of the new file memory. + * Failure: The undefined address HADDR_UNDEF + * + * Programmer: Quincey Koziol + * Friday, August 25, 2000 + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_real_alloc(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size) +{ + haddr_t ret_value = HADDR_UNDEF; + + FUNC_ENTER_NOAPI_NOINIT(H5FD_real_alloc) +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: type = %u, size = %Hu\n", FUNC, (unsigned)type, size); +#endif /* H5FD_ALLOC_DEBUG */ + + /* check args */ + assert(file); + assert(file->cls); + assert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES); + assert(size > 0); + + /* + * Dispatch to driver `alloc' callback or extend the end-of-address + * marker + */ + if(file->cls->alloc) { + if((ret_value = (file->cls->alloc)(file, type, dxpl_id, size)) == HADDR_UNDEF) + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "driver allocation request failed") + } else { + if((ret_value = H5FD_update_eoa(file, type, dxpl_id, size)) == HADDR_UNDEF) + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "driver eoa update request failed") + } + +done: +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: ret_value = %a\n", FUNC, ret_value); +#endif /* H5FD_ALLOC_DEBUG */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_real_alloc() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_update_eoa + * + * Purpose: Update the EOA field of the file's memory. + * + * This was split off from the H5FD_real_alloc function to + * make life easier for all. + * + * Return: Success: The format address of the new file memory. + * Failure: The undefined address HADDR_UNDEF + * + * Programmer: Bill Wendling + * Wednesday, 04. December, 2002 + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_update_eoa(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size) +{ + haddr_t eoa, oldeoa = 0; + hsize_t wasted; + haddr_t ret_value = HADDR_UNDEF; + + FUNC_ENTER_NOAPI_NOINIT(H5FD_update_eoa) + + /* check args */ + assert(file); + assert(file->cls); + assert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES); + assert(size > 0); + + eoa = file->cls->get_eoa(file, type); + +#ifdef H5F_DEBUG + if(file->alignment * file->threshold != 1 && H5DEBUG(F)) + HDfprintf(H5DEBUG(F), + "%s: alignment=%Hd, threshold=%Hd, size=%Hd, Begin eoa=%a\n", + FUNC, file->alignment, file->threshold, size, eoa); +#endif /* H5F_DEBUG */ + + /* Wasted is 0 if not exceeding threshold or eoa happens to be aligned */ + wasted = (size >= file->threshold) ? (eoa % file->alignment) : 0; + if(wasted) { + wasted = file->alignment - wasted; /* actual waste */ + oldeoa = eoa; /* save it for later freeing */ + + /* Advance eoa to the next alignment by allocating the wasted */ + if(H5F_addr_overflow(eoa, size) || (eoa + wasted) > file->maxaddr) + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "file allocation request failed") + + eoa += wasted; + + if(file->cls->set_eoa(file, type, eoa) < 0) + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "file allocation request failed") + } /* end if */ + + /* allocate the aligned memory */ + if(H5F_addr_overflow(eoa, size) || eoa + size > file->maxaddr) + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "file allocation request failed") + + ret_value = eoa; + eoa += size; + + if(file->cls->set_eoa(file, type, eoa) < 0) + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "file allocation request failed") + + /* Free the wasted memory */ + if(wasted) { + if(H5FD_free(file, type, dxpl_id, oldeoa, wasted) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, HADDR_UNDEF, "file deallocation request failed") + } /* end if */ + +#ifdef H5F_DEBUG + if(file->alignment * file->threshold != 1 && H5DEBUG(F)) + HDfprintf(H5DEBUG(F), + "%s: ret_value=%a, wasted=%Hd, Ended eoa=%a\n", + FUNC, ret_value, wasted, eoa); +#endif /* H5F_DEBUG */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_update_eoa() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_free + * + * Purpose: Private version of H5FDfree() + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_free(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size) +{ + H5FD_mem_t mapped_type; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_free, FAIL) + + /* Check args */ + HDassert(file); + HDassert(file->cls); + HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES); + +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)type, addr, size); +#endif /* H5FD_ALLOC_DEBUG */ + + if(!H5F_addr_defined(addr) || addr > file->maxaddr || + H5F_addr_overflow(addr, size) || (addr + size) > file->maxaddr) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid region") + + /* Allow 0-sized free's to occur without penalty */ + if(0 == size) + HGOTO_DONE(SUCCEED) + + /* Map request type to free list */ + if(H5FD_MEM_DEFAULT==file->cls->fl_map[type]) + mapped_type = type; + else + mapped_type = file->cls->fl_map[type]; +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: mapped_type = %u\n", FUNC, (unsigned)mapped_type); +#endif /* H5FD_ALLOC_DEBUG */ + + /* + * If the request maps to a free list then add memory to the free list + * without ever telling the driver that it was freed. Otherwise let the + * driver deallocate the memory. + */ + if(mapped_type >= H5FD_MEM_DEFAULT) { + H5FD_free_t *last; /* Last merged node */ + H5FD_free_t *last_prev = NULL;/* Pointer to node before merged node */ + H5FD_free_t *curr; /* Current free block being inspected */ + H5FD_free_t *prev; /* Previous free block being inspected */ + + /* Adjust the metadata accumulator to remove the freed block, if it overlaps */ + if((file->feature_flags&H5FD_FEAT_ACCUMULATE_METADATA) + && H5F_addr_overlap(addr, size, file->accum_loc, file->accum_size)) { + size_t overlap_size; /* Size of overlap with accumulator */ + + /* Check for overlapping the beginning of the accumulator */ + if(H5F_addr_le(addr, file->accum_loc)) { + /* Check for completely overlapping the accumulator */ + if(H5F_addr_ge(addr + size, file->accum_loc + file->accum_size)) { + /* Reset the entire accumulator */ + file->accum_loc=HADDR_UNDEF; + file->accum_size=FALSE; + file->accum_dirty=FALSE; + } /* end if */ + /* Block to free must end within the accumulator */ + else { + size_t new_accum_size; /* Size of new accumulator buffer */ + + /* Calculate the size of the overlap with the accumulator, etc. */ + H5_ASSIGN_OVERFLOW(overlap_size,(addr+size)-file->accum_loc,haddr_t,size_t); + new_accum_size=file->accum_size-overlap_size; + + /* Move the accumulator buffer information to eliminate the freed block */ + HDmemmove(file->meta_accum,file->meta_accum+overlap_size,new_accum_size); + + /* Adjust the accumulator information */ + file->accum_loc+=overlap_size; + file->accum_size=new_accum_size; + } /* end else */ + } /* end if */ + /* Block to free must start within the accumulator */ + else { + /* Calculate the size of the overlap with the accumulator */ + H5_ASSIGN_OVERFLOW(overlap_size,(file->accum_loc+file->accum_size)-addr,haddr_t,size_t); + + /* Block to free is in the middle of the accumulator */ + if(H5F_addr_lt((addr + size), file->accum_loc + file->accum_size)) { + haddr_t tail_addr; + size_t tail_size; + + /* Calculate the address & size of the tail to write */ + tail_addr=addr+size; + H5_ASSIGN_OVERFLOW(tail_size,(file->accum_loc+file->accum_size)-tail_addr,haddr_t,size_t); + + /* Write out the part of the accumulator after the block to free */ + /* (Use the driver's write call directly - to avoid looping back and writing to metadata accumulator) */ + if((file->cls->write)(file, H5FD_MEM_DEFAULT, dxpl_id, tail_addr, tail_size, file->meta_accum+(tail_addr-file->accum_loc)) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file write request failed") + } /* end if */ + + /* Adjust the accumulator information */ + file->accum_size=file->accum_size-overlap_size; + } /* end else */ + } /* end if */ + + /* Scan through the existing blocks for the mapped type to see if we can extend one */ + curr = file->fl[mapped_type]; + last = prev = NULL; + while(curr != NULL) { + /* Check if the block to free adjoins the start of the current block */ + if((addr + size) == curr->addr) { + /* If we previously found & merged a node, eliminate it from the list & free it */ + if(last != NULL) { + /* Check if there was a previous block in the list */ + if(last_prev != NULL) + /* Eliminate the merged block from the list */ + last_prev->next = last->next; + /* No previous block, this must be the head of the list */ + else + /* Eliminate the merged block from the list */ + file->fl[mapped_type] = last->next; + + /* Check for eliminating the block before the 'current' one */ + if(last == prev) + prev = last_prev; + + /* Free the memory for the merged block */ + H5FL_FREE(H5FD_free_t, last); + } /* end if */ + + /* Adjust the address and size of the block found */ + curr->addr = addr; + curr->size += size; + + /* Adjust the information about to memory block to include the merged block */ + addr = curr->addr; + size = curr->size; + + /* Update the information about the merged node */ + last = curr; + last_prev = prev; + } /* end if */ + else { + /* Check if the block to free adjoins the end of the current block */ + if((curr->addr + curr->size) == addr) { + /* If we previously found & merged a node, eliminate it from the list & free it */ + if(last != NULL) { + /* Check if there was a previous block in the list */ + if(last_prev != NULL) + /* Eliminate the merged block from the list */ + last_prev->next = last->next; + /* No previous block, this must be the head of the list */ + else + /* Eliminate the merged block from the list */ + file->fl[mapped_type] = last->next; + + /* Check for eliminating the block before the 'current' one */ + if(last == prev) + prev = last_prev; + + /* Free the memory for the merged block */ + H5FL_FREE(H5FD_free_t, last); + } /* end if */ + + /* Adjust the size of the block found */ + curr->size += size; + + /* Adjust the information about to memory block to include the merged block */ + addr = curr->addr; + size = curr->size; + + /* Update the information about the merged node */ + last = curr; + last_prev = prev; + } /* end if */ + } /* end else */ + + /* Advance to next node in list */ + prev = curr; + curr = curr->next; + } /* end while */ + + /* Check if we adjusted an existing block */ + if(last != NULL) { + /* Move the node found to the front, if it wasn't already there */ + if(last_prev != NULL) { + last_prev->next = last->next; + last->next = file->fl[mapped_type]; + file->fl[mapped_type] = last; + } /* end if */ + } /* end if */ + else { + /* Allocate a new node to hold the free block's information */ + if(NULL == (last = H5FL_MALLOC(H5FD_free_t))) + HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, FAIL, "can't allocate node for free space info") + + last->addr = addr; + last->size = size; + last->next = file->fl[mapped_type]; + file->fl[mapped_type] = last; + } /* end else */ +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: mapped_type = %u, last = {%a, %Hu}\n", FUNC, (unsigned)mapped_type, last->addr, last->size); +#endif /* H5FD_ALLOC_DEBUG */ + + /* Check if we increased the size of the largest block on the list */ + file->maxsize = MAX(file->maxsize, last->size); + + /* Check if this free block adjoins the "metadata aggregator" */ + if(H5FD_aggr_adjoin(file, &(file->meta_aggr), last) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "aggregator deallocation request failed") + + /* Check if this free block adjoins the "small data aggregator" */ + if(H5FD_aggr_adjoin(file, &(file->sdata_aggr), last) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "aggregator deallocation request failed") + + /* Check if this free block is at the end of file allocated space. + * Truncate it if this is true. */ + if(file->cls->get_eoa) { + haddr_t eoa; + + eoa = file->cls->get_eoa(file, type); +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: eoa = %a\n", FUNC, eoa); +#endif /* H5FD_ALLOC_DEBUG */ + if(eoa == (last->addr + last->size)) { +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: Reducing file size to = %a\n", FUNC, last->addr); +#endif /* H5FD_ALLOC_DEBUG */ + if(file->cls->set_eoa(file, type, last->addr) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "set end of space allocation request failed") + + /* Remove this free block from the list */ + file->fl[mapped_type] = last->next; + if(file->maxsize == last->size) + file->maxsize = 0; /*unknown*/ + H5FL_FREE(H5FD_free_t, last); + } /* end if */ + } /* end if */ + } else if(file->cls->free) { +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: Letting VFD free space\n", FUNC); +#endif /* H5FD_ALLOC_DEBUG */ + if((file->cls->free)(file, type, dxpl_id, addr, size) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver free request failed") + } else { + /* leak memory */ +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: LEAKED MEMORY!!! type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)type, addr, size); +#endif /* H5FD_ALLOC_DEBUG */ + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_free() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_realloc + * + * Purpose: Private version of H5FDrealloc() + * + * Return: Success: New address of the block of memory, not + * necessarily the same as the original address. + * Failure: HADDR_UNDEF + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + *------------------------------------------------------------------------- + */ +haddr_t +H5FD_realloc(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t old_addr, hsize_t old_size, + hsize_t new_size) +{ + haddr_t new_addr=old_addr; + uint8_t _buf[8192]; + uint8_t *buf=_buf; + haddr_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_realloc, HADDR_UNDEF) + + if(new_size == old_size) { + /*nothing to do*/ + } else if(0 == old_size) { + /* allocate memory */ + HDassert(!H5F_addr_defined(old_addr)); + if(HADDR_UNDEF == (new_addr = H5FD_alloc(file, type, dxpl_id, new_size))) + HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed") + } else if(0==new_size) { + /* free memory */ + HDassert(H5F_addr_defined(old_addr)); + if(H5FD_free(file, type, dxpl_id, old_addr, old_size) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, HADDR_UNDEF, "file deallocation request failed") + new_addr = HADDR_UNDEF; + } else if(new_size<old_size) { + /* free the end of the block */ + if(H5FD_free(file, type, dxpl_id, old_addr+old_size, old_size-new_size) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, HADDR_UNDEF, "file deallocation request failed") + } else { + /* move memory to new location */ + /* Note! This may fail if sizeof(hsize_t)>sizeof(size_t) and the + * object on disk is too large to read into a memory buffer all at one + * time. This chunk of code would have to be re-written using a loop + * to move pieces of the realloced data through a fixed size buffer, etc. + * -QAK, 6/20/01 + */ + if(HADDR_UNDEF == (new_addr = H5FD_alloc(file, type, dxpl_id, new_size))) + HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed") + H5_CHECK_OVERFLOW(old_size,hsize_t,size_t); + if(old_size > sizeof(_buf) && NULL == (buf = H5MM_malloc((size_t)old_size))) { + (void)H5FD_free(file, type, dxpl_id, new_addr, new_size); + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "memory allocation failed") + } /* end if */ + if(H5FD_read(file, type, dxpl_id, old_addr, (size_t)old_size, buf) < 0 || + H5FD_write(file, type, dxpl_id, new_addr, (size_t)old_size, buf) < 0) { + (void)H5FD_free(file, type, dxpl_id, new_addr, new_size); + if(buf != _buf) + H5MM_xfree(buf); + HGOTO_ERROR(H5E_FILE, H5E_READERROR, HADDR_UNDEF, "unable to move file block") + } /* end if */ + + if(buf != _buf) + H5MM_xfree(buf); + if(H5FD_free(file, type, dxpl_id, old_addr, old_size) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, HADDR_UNDEF, "file deallocation request failed") + } /* end else */ + + /* Set return value */ + ret_value = new_addr; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_realloc() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_can_extend + * + * Purpose: Check if a block in the file can be extended. + * + * Return: Success: TRUE(1)/FALSE(0) + * Failure: FAIL + * + * Programmer: Quincey Koziol + * Friday, June 11, 2004 + * + *------------------------------------------------------------------------- + */ +htri_t +H5FD_can_extend(const H5FD_t *file, H5FD_mem_t type, haddr_t addr, hsize_t size, hsize_t extra_requested) +{ + haddr_t end; /* End of block in file */ + haddr_t eoa; /* End of address space in the file */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_can_extend, FAIL) + + /* Retrieve the end of the address space */ + if(HADDR_UNDEF == (eoa = H5FD_get_eoa(file, type))) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed") + + /* Compute end of block */ + end = addr + size; + + /* Check if the block is exactly at the end of the file */ + if(end == eoa) + HGOTO_DONE(TRUE) + else { + H5FD_free_t *curr; /* Current free block being inspected */ + H5FD_mem_t mapped_type; /* Memory type, after mapping */ + + /* Map request type to free list */ + if(H5FD_MEM_DEFAULT==file->cls->fl_map[type]) + mapped_type = type; + else + mapped_type = file->cls->fl_map[type]; + + /* Check if block is inside the metadata or small data aggregator */ + if(mapped_type!=H5FD_MEM_DRAW) { + /* Check for test block able to extend metadata aggregation block */ + if((ret_value = H5FD_aggr_can_extend(file, &(file->meta_aggr), eoa, end)) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't determine if metadata aggregation block can be extended") + else if(ret_value > 0) + HGOTO_DONE(TRUE) + } /* end if */ + else { + /* Check for test block able to extend metadata aggregation block */ + if((ret_value = H5FD_aggr_can_extend(file, &(file->sdata_aggr), eoa, end)) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't determine if 'small data' aggregation block can be extended") + else if(ret_value > 0) + HGOTO_DONE(TRUE) + } /* end else */ + + /* Scan through the existing blocks for the mapped type to see if we can extend one */ + if(mapped_type >= H5FD_MEM_DEFAULT) { + curr = file->fl[mapped_type]; + while(curr != NULL) { + if(end == curr->addr) { + if(extra_requested <= curr->size) + HGOTO_DONE(TRUE) + else + HGOTO_DONE(FALSE) + } /* end if */ + + /* Advance to next node in list */ + curr=curr->next; + } /* end while */ + } /* end if */ + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_can_extend() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_extend + * + * Purpose: Extend a block in the file. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Quincey Koziol + * Saturday, June 12, 2004 + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_extend(H5FD_t *file, H5FD_mem_t type, haddr_t addr, hsize_t size, hsize_t extra_requested) +{ + haddr_t eoa; /* End of address space in the file */ + haddr_t end; /* End of block in file */ + hbool_t update_eoma=FALSE; /* Whether we need to update the eoma */ + hbool_t update_eosda=FALSE; /* Whether we need to update the eosda */ + hbool_t at_end=FALSE; /* Block is at end of file */ + H5FD_mem_t mapped_type; /* Memory type, after mapping */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_extend, FAIL) +#ifdef H5FD_ALLOC_DEBUG +HDfprintf(stderr, "%s: type = %u, addr = %a, size = %Hu, extra_requested = %Hu\n", FUNC, (unsigned)type, addr, size, extra_requested); +#endif /* H5FD_ALLOC_DEBUG */ + + /* Retrieve the end of the address space */ + if(HADDR_UNDEF==(eoa=H5FD_get_eoa(file, type))) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed") + + /* Map request type to free list */ + if(H5FD_MEM_DEFAULT==file->cls->fl_map[type]) + mapped_type = type; + else + mapped_type = file->cls->fl_map[type]; + + /* Compute end of block */ + end = addr + size; + + /* Check if the block is exactly at the end of the file */ + if(end == eoa) + at_end = TRUE; + else { + /* (Check if block is inside the metadata or small data accumulator) */ + if(mapped_type!=H5FD_MEM_DRAW) { + /* Check for test block able to extend metadata aggregation block */ + if((ret_value = H5FD_aggr_can_extend(file, &(file->meta_aggr), eoa, end)) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't determine if metadata aggregation block can be extended") + else if(ret_value > 0) + update_eoma = TRUE; + } /* end if */ + else { + /* Check for test block able to extend metadata aggregation block */ + if((ret_value = H5FD_aggr_can_extend(file, &(file->sdata_aggr), eoa, end)) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't determine if metadata aggregation block can be extended") + else if(ret_value > 0) + update_eosda = TRUE; + } /* end else */ + } /* end else */ + + /* Block is at end of file, we are extending the eoma or eosda */ + if(update_eoma || update_eosda || at_end) { + /* Check for overflowing the file */ + if(H5F_addr_overflow(eoa, extra_requested) || eoa + extra_requested > file->maxaddr) + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, FAIL, "file allocation request failed") + + /* Extend the file */ + eoa += extra_requested; + if(file->cls->set_eoa(file, type, eoa) < 0) + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, FAIL, "file allocation request failed") + + /* Update the metadata and/or small data block */ + HDassert(!(update_eoma && update_eosda)); + if(update_eoma) + H5FD_aggr_shift(&(file->meta_aggr), extra_requested); + if(update_eosda) + H5FD_aggr_shift(&(file->sdata_aggr), extra_requested); + } /* end if */ + /* If the block we are extending isn't at the end of the file, find a free block to extend into */ + else { + H5FD_free_t *curr; /* Current free block being inspected */ + H5FD_free_t *prev; /* Current free block being inspected */ + + /* Walk through free list, looking for block to merge with */ + curr = file->fl[mapped_type]; + prev = NULL; + while(curr!=NULL) { + /* Found block that ajoins end of block to extend */ + if(end == curr->addr) { + /* Check if free space is large enough */ + if(extra_requested <= curr->size) { + /* Check for exact match */ + if(extra_requested == curr->size) { + /* Unlink node from free list */ + if(prev == NULL) + file->fl[mapped_type] = curr->next; + else + prev->next = curr->next; + + /* Free the memory for the used block */ + H5FL_FREE(H5FD_free_t, curr); + } /* end if */ + else { + curr->addr += extra_requested; + curr->size -= extra_requested; + } /* end else */ + + /* Leave now */ + break; + } /* end if */ + else + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, FAIL, "can't extend block") + } /* end if */ + + /* Advance to next node in list */ + prev = curr; + curr = curr->next; + } /* end while */ + + /* Couldn't find block to extend */ + if(curr == NULL) + HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, FAIL, "can't extend block") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_extend() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_get_freespace + * + * Purpose: Retrieve the amount of free space in a file. + * + * Return: Success: Amount of free space in file + * Failure: Negative + * + * Programmer: Quincey Koziol + * Monday, October 6, 2003 + * + * Note: + * Raymond Lu + * 5 January 2007 + * Due to the complexity EOA for Multi driver, this function + * is made failed for now. + * + *------------------------------------------------------------------------- + */ +hssize_t +H5FD_get_freespace(const H5FD_t *file) +{ + H5FD_free_t *free_node; /* Pointer to node on free list */ + H5FD_mem_t type; /* Type of memory */ + haddr_t ma_addr = HADDR_UNDEF; /* Base "metadata aggregator" address */ + hsize_t ma_size = 0; /* Size of "metadata aggregator" */ + haddr_t sda_addr = HADDR_UNDEF; /* Base "small data aggregator" address */ + hsize_t sda_size = 0; /* Size of "small data aggregator" */ + haddr_t eoa = 0; /* End of allocated space in the file */ + hssize_t ret_value = 0; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_get_freespace, FAIL) + + /* check args */ + HDassert(file); + HDassert(file->cls); + + /* Multi driver doesn't support this function because of the complexity. + * It doesn't have eoa for the whole file. */ + if(file->driver_id == H5FD_MULTI) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "Multi driver doesn't support this function") + + /* Retrieve the 'eoa' for the file */ + eoa = file->cls->get_eoa(file, H5FD_MEM_DEFAULT); + + /* Retrieve metadata aggregator info, if available */ + H5FD_aggr_query(file, &(file->meta_aggr), &ma_addr, &ma_size); + + /* Retrieve 'small data' aggregator info, if available */ + H5FD_aggr_query(file, &(file->sdata_aggr), &sda_addr, &sda_size); + + /* Iterate over all the types of memory, to retrieve amount of free space for each */ + for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t,type)) { + /* Iterate through the free list, accumulating the amount of free space for this type */ + free_node = file->fl[type]; + while(free_node) { + /* Check for current node adjoining the metadata & small data aggregators */ + if(H5F_addr_eq(free_node->addr + free_node->size, ma_addr)) { + ma_addr -= free_node->size; + ma_size += free_node->size; + } else if(H5F_addr_eq(free_node->addr + free_node->size, sda_addr)) { + sda_addr -= free_node->size; + sda_size += free_node->size; + } else if(H5F_addr_eq(ma_addr + ma_size, free_node->addr)) + ma_size += free_node->size; + else if(H5F_addr_eq(sda_addr + sda_size, free_node->addr)) + sda_size += free_node->size; + else + ret_value += (hssize_t)free_node->size; + free_node = free_node->next; + } /* end while */ + } /* end for */ + + /* Check for aggregating metadata allocations */ + if(ma_size > 0) { + /* Add in the reserved space for metadata to the available free space */ + /* (if it's not at the tail of the file) */ + if(H5F_addr_ne(ma_addr + ma_size, eoa)) + ret_value += ma_size; + } /* end if */ + + /* Check for aggregating small data allocations */ + if(sda_size > 0) { + /* Add in the reserved space for metadata to the available free space */ + /* (if it's not at the tail of the file) */ + if(H5F_addr_ne(sda_addr + sda_size, eoa)) + ret_value += sda_size; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_get_freespace() */ + |