diff options
Diffstat (limited to 'src/H5MV.c')
-rw-r--r-- | src/H5MV.c | 518 |
1 files changed, 518 insertions, 0 deletions
diff --git a/src/H5MV.c b/src/H5MV.c new file mode 100644 index 0000000..d0cca9f --- /dev/null +++ b/src/H5MV.c @@ -0,0 +1,518 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5MV.c + * + * Purpose: Free-space manager for VFD SWMR's metadata file + * + *------------------------------------------------------------------------- + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5F_FRIEND /*suppress error about including H5Fpkg */ +#define H5FS_FRIEND /*suppress error about including H5Fpkg */ +#include "H5MVmodule.h" /* This source code file is part of the H5MV module */ + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fpkg.h" /* File access */ +#include "H5FSpkg.h" /* File free space */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MVpkg.h" /* File memory management */ +#include "H5VMprivate.h" /* Vectors and arrays */ + + +/****************/ +/* Local Macros */ +/****************/ + +#define H5MV_FSPACE_SHRINK 80 /* Percent of "normal" size to shrink serialized free space size */ +#define H5MV_FSPACE_EXPAND 120 /* Percent of "normal" size to expand serialized free space size */ +#define H5MV_FSPACE_THRHD_DEF 1 /* Default: no alignment threshold */ +#define H5MV_FSPACE_ALIGN_DEF 1 /* Default: no alignment */ + +/******************/ +/* Local Typedefs */ +/******************/ + +/* User data for section info iterator callback for iterating over free space sections */ +typedef struct { + H5F_sect_info_t *sects; /* section info to be retrieved */ + size_t sect_count; /* # of sections requested */ + size_t sect_idx; /* the current count of sections */ +} H5MV_sect_iter_ud_t; + + +/********************/ +/* Package Typedefs */ +/********************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + + +/*********************/ +/* Package Variables */ +/*********************/ + +/* Package initialization variable */ +hbool_t H5_PKG_INIT_VAR = FALSE; + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + + +/*------------------------------------------------------------------------- + * Function: H5MV__create() + * + * Purpose: Create free space manager for the metadata file by creating + * a free-space structure + * + * Return: Success: non-negative + * Failure: negative + * + *------------------------------------------------------------------------- + */ +herr_t +H5MV__create(H5F_t *f) +{ + /* Free space section classes implemented for file */ + const H5FS_section_class_t *classes[] = { H5MV_FSPACE_SECT_CLS_SIMPLE }; + H5FS_create_t fs_create; /* Free space creation parameters */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* + * Check arguments. + */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->fs_state_md == H5F_FS_STATE_CLOSED); + + /* Set the free space creation parameters */ + fs_create.client = H5FS_CLIENT_MD_VFD_ID; + fs_create.shrink_percent = H5MV_FSPACE_SHRINK; + fs_create.expand_percent = H5MV_FSPACE_EXPAND; + fs_create.max_sect_addr = 1 + H5VM_log2_gen((uint64_t)f->shared->maxaddr); + fs_create.max_sect_size = f->shared->maxaddr; + + if(NULL == (f->shared->fs_man_md = H5FS_create(f, NULL, &fs_create, NELMTS(classes), classes, f, H5MV_FSPACE_ALIGN_DEF, H5MV_FSPACE_THRHD_DEF))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info") + + /* Set the state for the free space manager to "open", if it is now */ + if(f->shared->fs_man_md) + f->shared->fs_state_md = H5F_FS_STATE_OPEN; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5MV__create() */ + + +/*------------------------------------------------------------------------- + * Function: H5MV_close + * + * Purpose: Close the free space manager for the metadata file + * + * Return: Success: non-negative + * Failure: negative + * + *------------------------------------------------------------------------- + */ +herr_t +H5MV_close(H5F_t *f) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* + * Check arguments. + */ + HDassert(f); + HDassert(f->shared); +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Trying to close free space manager\n", FUNC); +#endif + + /* Close an existing free space structure for the file */ + if(f->shared->fs_man_md) { +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Going to close free space manager\n", FUNC); +#endif + HDassert(f->shared->fs_state_md != H5F_FS_STATE_CLOSED); + + if(H5FS_close(f, f->shared->fs_man_md) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free space info") + } + + f->shared->fs_man_md = NULL; + f->shared->fs_state_md = H5F_FS_STATE_CLOSED; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5MV_close() */ + + + +/*------------------------------------------------------------------------- + * Function: H5MV__find_sect + * + * Purpose: To find a section from the specified free-space manager + * to fulfill the request. + * If found, re-add the left-over space back to the manager. + * + * Return: TRUE if a section is found to fulfill the request + * FALSE if not + * + *------------------------------------------------------------------------- + */ +htri_t +H5MV__find_sect(H5F_t *f, hsize_t size, H5FS_t *fspace, haddr_t *addr) +{ + H5MV_free_section_t *node; /* Free space section pointer */ + htri_t ret_value = FAIL; /* Whether an existing free list node was found */ + + FUNC_ENTER_PACKAGE + + HDassert(f); + HDassert(fspace); + + /* Try to get a section from the free space manager */ + if((ret_value = H5FS_sect_find(f, fspace, size, (H5FS_section_info_t **)&node)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "error locating free space in file") + +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: section found = %t\n", FUNC, ret_value); +#endif + + /* Check for actually finding section */ + if(ret_value) { + /* Sanity check */ + HDassert(node); + + /* Retrieve return value */ + if(addr) + *addr = node->sect_info.addr; + + /* Check for eliminating the section */ + if(node->sect_info.size == size) { +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: freeing node\n", FUNC); +#endif + + /* Free section node */ + if(H5MV__sect_free((H5FS_section_info_t *)node) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node") + } /* end if */ + else { + /* Adjust information for section */ + node->sect_info.addr += size; + node->sect_info.size -= size; + +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: adding node, node->sect_info.addr = %a, node->sect_info.size = %Hu\n", FUNC, node->sect_info.addr, node->sect_info.size); +#endif + + /* Re-add the section to the free-space manager */ + if(H5FS_sect_add(f, fspace, (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, f) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space") + } /* end else */ + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5MV__find_sect() */ + + +/*------------------------------------------------------------------------- + * Function: H5MV_alloc + * + * Purpose: Allocate SIZE bytes of file memory and return the relative + * address where that contiguous chunk of file memory exists. + * + * Return: Success: The file address of new chunk. + * Failure: HADDR_UNDEF + * + *------------------------------------------------------------------------- + */ +haddr_t +H5MV_alloc(H5F_t *f, hsize_t size) +{ + haddr_t ret_value = HADDR_UNDEF; /* Return value */ + + FUNC_ENTER_NOAPI(HADDR_UNDEF) +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: size = %Hu\n", FUNC, size); +#endif + + /* check arguments */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->vfd_swmr_md_fd >= 0); + HDassert(size > 0); + + /* Search for large enough space in the free space manager */ + if(f->shared->fs_man_md != NULL) { + if(H5MV__find_sect(f, size, f->shared->fs_man_md, &ret_value) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "error locating a node") + } + + /* If no space is found from the free-space manager or no free-space manager, extend md's EOF */ + if(!H5F_addr_defined(ret_value)) { + if(HADDR_UNDEF == (ret_value = H5F__alloc_md(f, size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed") + } /* end if */ + HDassert(H5F_addr_defined(ret_value)); + +done: +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Leaving: ret_value = %a, size = %Hu\n", FUNC, ret_value, size); +#endif + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5MV_alloc() */ + + + +/*------------------------------------------------------------------------- + * Function: H5MV_free + * + * Purpose: Frees part of a file, making that part of the file + * available for reuse. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5MV_free(H5F_t *f, haddr_t addr, hsize_t size) +{ + H5MV_free_section_t *node = NULL; /* Free space section pointer */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Entering - addr = %a, size = %Hu\n", FUNC, addr, size); +#endif + + /* check arguments */ + HDassert(f); + if(!H5F_addr_defined(addr) || 0 == size) + HGOTO_DONE(SUCCEED) + HDassert(addr != 0); + + + /* Check if the free space manager for the file has been initialized */ + if(f->shared->fs_man_md == NULL) { + /* If there's no free space manager for objects of this type, + * see if we can avoid creating one by checking if the freed + * space is at the end of the file + */ +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: fs_addr = %a\n", FUNC, f->shared->fs_man_md); +#endif + htri_t status; /* "can absorb" status for section into */ + +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Trying to avoid starting up free space manager\n", FUNC); +#endif + /* Try to shrink the file */ + if((status = H5MV_try_shrink(f, addr, size)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check for absorbing block") + else if(status > 0) + /* Indicate success */ + HGOTO_DONE(SUCCEED) + + /* If we are deleting the free space manager, leave now, to avoid + * [re-]starting it: dropping free space section on the floor. + */ + if(f->shared->fs_state_md == H5F_FS_STATE_DELETING) { +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: dropping addr = %a, size = %Hu, on the floor!\n", FUNC, addr, size); +#endif + HGOTO_DONE(SUCCEED) + } /* end if */ + + /* There's either already a free space manager, or the freed + * space isn't at the end of the file, so start up (or create) + * the file space manager + */ + if(H5MV__create(f) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space manager") + } /* end if */ + + /* Create the free-space section for the freed section */ + if(NULL == (node = H5MV__sect_new(addr, size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section") + + HDassert(f->shared->fs_man_md); + +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Before H5FS_sect_add()\n", FUNC); +#endif + + /* Add the section */ + if(H5FS_sect_add(f, f->shared->fs_man_md, (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, f) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space") + + node = NULL; + +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: After H5FS_sect_add()\n", FUNC); +#endif + +done: + /* Release section node, if allocated and not added to section list or merged */ + if(node) + if(H5MV__sect_free((H5FS_section_info_t *)node) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node") + +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value); +#endif + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5MV_free() */ + + +/*------------------------------------------------------------------------- + * Function: H5MV_try_extend + * + * Purpose: Extend a block at EOA in the file if possible. + * + * Return: Success: TRUE(1) - Block was extended + * FALSE(0) - Block could not be extended + * Failure: FAIL + * + *------------------------------------------------------------------------- + */ +htri_t +H5MV_try_extend(H5F_t *f, haddr_t addr, hsize_t size, hsize_t extra_requested) +{ + haddr_t end; /* End of block to extend */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Entering: addr = %a, size = %Hu, extra_requested = %Hu\n", FUNC, addr, size, extra_requested); +#endif + + /* Sanity check */ + HDassert(f); + HDassert(H5F_INTENT(f) & H5F_ACC_RDWR); + + /* Compute end of block to extend */ + end = addr + size; + + /* Try extending the block at EOA */ + if((ret_value = H5F__try_extend_md(f, end, extra_requested)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending file") +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: extended = %t\n", FUNC, ret_value); +#endif + + /* If no extension so far, try to extend into a free-space section */ + if(ret_value == FALSE) { + + /* Try to extend the block into a free-space section */ + if(f->shared->fs_man_md) { + if((ret_value = H5FS_sect_try_extend(f, f->shared->fs_man_md, addr, size, extra_requested, H5FS_ADD_RETURNED_SPACE, NULL)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending block in free space manager") +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Try to H5FS_sect_try_extend = %t\n", FUNC, ret_value); +#endif + } /* end if */ + + } /* end if */ + +done: +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Leaving: ret_value = %t\n", FUNC, ret_value); +#endif + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5MV_try_extend() */ + + +/*------------------------------------------------------------------------- + * Function: H5MV_try_shrink + * + * Purpose: Try to shrink the size of a file with a block + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +htri_t +H5MV_try_shrink(H5F_t *f, haddr_t addr, hsize_t size) +{ + H5MV_free_section_t *node = NULL; /* Free space section pointer */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Entering - addr = %a, size = %Hu\n", FUNC, addr, size); +#endif + + /* check arguments */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->lf); + HDassert(H5F_addr_defined(addr)); + HDassert(size > 0); + + /* Create free-space section for block */ + if(NULL == (node = H5MV__sect_new(addr, size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section") + + /* Check if the block can shrink the container */ + if((ret_value = H5MV__sect_can_shrink((const H5FS_section_info_t *)node, f)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check if section can shrink container") + else if(ret_value > 0) { + /* Shrink or absorb the section */ + if(H5MV__sect_shrink((H5FS_section_info_t **)&node, NULL) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink container") + } /* end if */ + +done: + /* Free section node allocated */ + if(node && H5MV__sect_free((H5FS_section_info_t *)node) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node") + +#ifdef H5MV_VFD_SWMR_DEBUG +HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value); +#endif + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5MV_try_shrink() */ + +/* + * If need to find out the amount of free-space in the file, port routines in H5MF.c + */ |