/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Programmer: Quincey Koziol * Tuesday, January 8, 2008 * * Purpose: Free space section callbacks for file. * */ /****************/ /* Module Setup */ /****************/ #define H5F_PACKAGE /*suppress error about including H5Fpkg */ #define H5MF_PACKAGE /*suppress error about including H5MFpkg */ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fpkg.h" /* File access */ #include "H5MFpkg.h" /* File memory management */ /****************/ /* Local Macros */ /****************/ /******************/ /* Local Typedefs */ /******************/ /********************/ /* Package Typedefs */ /********************/ /********************/ /* Local Prototypes */ /********************/ /* 'simple' section callbacks */ static H5FS_section_info_t *H5MF_sect_simple_deserialize(const H5FS_section_class_t *cls, hid_t dxpl_id, const uint8_t *buf, haddr_t sect_addr, hsize_t sect_size, unsigned *des_flags); static htri_t H5MF_sect_simple_can_merge(const H5FS_section_info_t *sect1, const H5FS_section_info_t *sect2, void *udata); static herr_t H5MF_sect_simple_merge(H5FS_section_info_t *sect1, H5FS_section_info_t *sect2, void *udata); static herr_t H5MF_sect_simple_valid(const H5FS_section_class_t *cls, const H5FS_section_info_t *sect); static H5FS_section_info_t *H5MF_sect_simple_split(H5FS_section_info_t *sect, hsize_t frag_size); /*********************/ /* Package Variables */ /*********************/ /* Class info for "simple" free space sections */ H5FS_section_class_t H5MF_FSPACE_SECT_CLS_SIMPLE[1] = {{ /* Class variables */ H5MF_FSPACE_SECT_SIMPLE, /* Section type */ 0, /* Extra serialized size */ H5FS_CLS_MERGE_SYM | H5FS_CLS_ADJUST_OK, /* Class flags */ NULL, /* Class private info */ /* Class methods */ NULL, /* Initialize section class */ NULL, /* Terminate section class */ /* Object methods */ NULL, /* Add section */ NULL, /* Serialize section */ H5MF_sect_simple_deserialize, /* Deserialize section */ H5MF_sect_simple_can_merge, /* Can sections merge? */ H5MF_sect_simple_merge, /* Merge sections */ H5MF_sect_simple_can_shrink, /* Can section shrink container?*/ H5MF_sect_simple_shrink, /* Shrink container w/section */ H5MF_sect_simple_free, /* Free section */ H5MF_sect_simple_valid, /* Check validity of section */ H5MF_sect_simple_split, /* Split section node for alignment */ NULL, /* Dump debugging for section */ }}; /*****************************/ /* Library Private Variables */ /*****************************/ /*******************/ /* Local Variables */ /*******************/ /* Declare a free list to manage the H5MF_free_section_t struct */ H5FL_DEFINE(H5MF_free_section_t); /*------------------------------------------------------------------------- * Function: H5MF_sect_simple_new * * Purpose: Create a new 'simple' section and return it to the caller * * Return: Pointer to new section on success/NULL on failure * * Programmer: Quincey Koziol * koziol@hdfgroup.org * January 8 2008 * *------------------------------------------------------------------------- */ H5MF_free_section_t * H5MF_sect_simple_new(haddr_t sect_off, hsize_t sect_size) { H5MF_free_section_t *sect = NULL; /* 'Simple' free space section to add */ H5MF_free_section_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT /* Check arguments. */ HDassert(sect_size); /* Create free space section node */ if (NULL == (sect = H5FL_MALLOC(H5MF_free_section_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for direct block free list section") /* Set the information passed in */ sect->sect_info.addr = sect_off; sect->sect_info.size = sect_size; /* Set the section's class & state */ sect->sect_info.type = H5MF_FSPACE_SECT_SIMPLE; sect->sect_info.state = H5FS_SECT_LIVE; /* Set return value */ ret_value = sect; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5MF_sect_simple_new() */ /*------------------------------------------------------------------------- * Function: H5MF_sect_simple_deserialize * * Purpose: Deserialize a buffer into a "live" single section * * Return: Success: non-negative * Failure: negative * * Programmer: Quincey Koziol * Tuesday, January 8, 2008 * *------------------------------------------------------------------------- */ static H5FS_section_info_t * H5MF_sect_simple_deserialize(const H5FS_section_class_t H5_ATTR_UNUSED *cls, hid_t H5_ATTR_UNUSED dxpl_id, const uint8_t H5_ATTR_UNUSED *buf, haddr_t sect_addr, hsize_t sect_size, unsigned H5_ATTR_UNUSED *des_flags) { H5MF_free_section_t *sect; /* New section */ H5FS_section_info_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT /* Check arguments. */ HDassert(H5F_addr_defined(sect_addr)); HDassert(sect_size); /* Create free space section for block */ if (NULL == (sect = H5MF_sect_simple_new(sect_addr, sect_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't initialize free space section") /* Set return value */ ret_value = (H5FS_section_info_t *)sect; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5MF_sect_simple_deserialize() */ /*------------------------------------------------------------------------- * Function: H5MF_sect_simple_can_merge * * Purpose: Can two sections of this type merge? * * Note: Second section must be "after" first section * * Return: Success: non-negative (TRUE/FALSE) * Failure: negative * * Programmer: Quincey Koziol * Tuesday, January 8, 2008 * *------------------------------------------------------------------------- */ static htri_t H5MF_sect_simple_can_merge(const H5FS_section_info_t *_sect1, const H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata) { const H5MF_free_section_t *sect1 = (const H5MF_free_section_t *)_sect1; /* File free section */ const H5MF_free_section_t *sect2 = (const H5MF_free_section_t *)_sect2; /* File free section */ htri_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT_NOERR /* Check arguments. */ HDassert(sect1); HDassert(sect2); HDassert(sect1->sect_info.type == sect2->sect_info.type); /* Checks "MERGE_SYM" flag */ HDassert(H5F_addr_lt(sect1->sect_info.addr, sect2->sect_info.addr)); /* Check if second section adjoins first section */ ret_value = H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr); FUNC_LEAVE_NOAPI(ret_value) } /* H5MF_sect_simple_can_merge() */ /*------------------------------------------------------------------------- * Function: H5MF_sect_simple_merge * * Purpose: Merge two sections of this type * * Note: Second section always merges into first node * * Return: Success: non-negative * Failure: negative * * Programmer: Quincey Koziol * Tuesday, January 8, 2008 * *------------------------------------------------------------------------- */ static herr_t H5MF_sect_simple_merge(H5FS_section_info_t *_sect1, H5FS_section_info_t *_sect2, void H5_ATTR_UNUSED *_udata) { H5MF_free_section_t *sect1 = (H5MF_free_section_t *)_sect1; /* File free section */ H5MF_free_section_t *sect2 = (H5MF_free_section_t *)_sect2; /* File free section */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT /* Check arguments. */ HDassert(sect1); HDassert(sect1->sect_info.type == H5MF_FSPACE_SECT_SIMPLE); HDassert(sect2); HDassert(sect2->sect_info.type == H5MF_FSPACE_SECT_SIMPLE); HDassert(H5F_addr_eq(sect1->sect_info.addr + sect1->sect_info.size, sect2->sect_info.addr)); /* Add second section's size to first section */ sect1->sect_info.size += sect2->sect_info.size; /* Get rid of second section */ if (H5MF_sect_simple_free((H5FS_section_info_t *)sect2) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free section node") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5MF_sect_simple_merge() */ /*------------------------------------------------------------------------- * Function: H5MF_sect_simple_can_shrink * * Purpose: Can this section shrink the container? * * Return: Success: non-negative (TRUE/FALSE) * Failure: negative * * Programmer: Quincey Koziol * Tuesday, January 8, 2008 * *------------------------------------------------------------------------- */ htri_t H5MF_sect_simple_can_shrink(const H5FS_section_info_t *_sect, void *_udata) { const H5MF_free_section_t *sect = (const H5MF_free_section_t *)_sect; /* File free section */ H5MF_sect_ud_t * udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */ haddr_t eoa; /* End of address space in the file */ haddr_t end; /* End of section to extend */ htri_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT /* Check arguments. */ HDassert(sect); HDassert(udata); HDassert(udata->f); /* Retrieve the end of the file's address space */ if (HADDR_UNDEF == (eoa = H5FD_get_eoa(udata->f->shared->lf, udata->alloc_type))) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed") /* Compute address of end of section to check */ end = sect->sect_info.addr + sect->sect_info.size; /* Check if the section is exactly at the end of the allocated space in the file */ if (H5F_addr_eq(end, eoa)) { /* Set the shrinking type */ udata->shrink = H5MF_SHRINK_EOA; #ifdef H5MF_ALLOC_DEBUG_MORE HDfprintf(stderr, "%s: section {%a, %Hu}, shrinks file, eoa = %a\n", FUNC, sect->sect_info.addr, sect->sect_info.size, eoa); #endif /* H5MF_ALLOC_DEBUG_MORE */ /* Indicate shrinking can occur */ HGOTO_DONE(TRUE) } /* end if */ else { /* Shrinking can't occur if the 'eoa_shrink_only' flag is set and we're not shrinking the EOA */ if (udata->allow_eoa_shrink_only) HGOTO_DONE(FALSE) /* Check if this section is allowed to merge with metadata aggregation block */ if (udata->f->shared->fs_aggr_merge[udata->alloc_type] & H5F_FS_MERGE_METADATA) { htri_t status; /* Status from aggregator adjoin */ /* See if section can absorb the aggregator & vice versa */ if ((status = H5MF_aggr_can_absorb(udata->f, &(udata->f->shared->meta_aggr), sect, &(udata->shrink))) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "error merging section with aggregation block") else if (status > 0) { /* Set the aggregator to operate on */ udata->aggr = &(udata->f->shared->meta_aggr); #ifdef H5MF_ALLOC_DEBUG_MORE HDfprintf(stderr, "%s: section {%a, %Hu}, adjoins metadata aggregator\n", FUNC, sect->sect_info.addr, sect->sect_info.size); #endif /* H5MF_ALLOC_DEBUG_MORE */ /* Indicate shrinking can occur */ HGOTO_DONE(TRUE) } /* end if */ } /* end if */ /* Check if this section is allowed to merge with small 'raw' aggregation block */ if (udata->f->shared->fs_aggr_merge[udata->alloc_type] & H5F_FS_MERGE_RAWDATA) { htri_t status; /* Status from aggregator adjoin */ /* See if section can absorb the aggregator & vice versa */ if ((status = H5MF_aggr_can_absorb(udata->f, &(udata->f->shared->sdata_aggr), sect, &(udata->shrink))) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "error merging section with aggregation block") else if (status > 0) { /* Set the aggregator to operate on */ udata->aggr = &(udata->f->shared->sdata_aggr); #ifdef H5MF_ALLOC_DEBUG_MORE HDfprintf(stderr, "%s: section {%a, %Hu}, adjoins small data aggregator\n", FUNC, sect->sect_info.addr, sect->sect_info.size); #endif /* H5MF_ALLOC_DEBUG_MORE */ /* Indicate shrinking can occur */ HGOTO_DONE(TRUE) } /* end if */ } /* end if */ } /* end else */ /* Set return value */ ret_value = FALSE; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5MF_sect_simple_can_shrink() */ /*------------------------------------------------------------------------- * Function: H5MF_sect_simple_shrink * * Purpose: Shrink container with section * * Return: Success: non-negative * Failure: negative * * Programmer: Quincey Koziol * Tuesday, January 8, 2008 * *------------------------------------------------------------------------- */ herr_t H5MF_sect_simple_shrink(H5FS_section_info_t **_sect, void *_udata) { H5MF_free_section_t **sect = (H5MF_free_section_t **)_sect; /* File free section */ H5MF_sect_ud_t * udata = (H5MF_sect_ud_t *)_udata; /* User data for callback */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT /* Check arguments. */ HDassert(sect); HDassert(udata); HDassert(udata->f); /* Check for shrinking file */ if (H5MF_SHRINK_EOA == udata->shrink) { /* Sanity check */ HDassert(H5F_INTENT(udata->f) & H5F_ACC_RDWR); /* Release section's space at EOA with file driver */ if (H5FD_free(udata->f->shared->lf, udata->dxpl_id, udata->alloc_type, udata->f, (*sect)->sect_info.addr, (*sect)->sect_info.size) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed") } /* end if */ else { /* Sanity check */ HDassert(udata->aggr); /* Absorb the section into the aggregator or vice versa */ if (H5MF_aggr_absorb(udata->f, udata->aggr, *sect, udata->allow_sect_absorb) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't absorb section into aggregator or vice versa") } /* end else */ /* Check for freeing section */ if (udata->shrink != H5MF_SHRINK_SECT_ABSORB_AGGR) { /* Free section */ if (H5MF_sect_simple_free((H5FS_section_info_t *)*sect) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node") /* Mark section as freed, for free space manager */ *sect = NULL; } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5MF_sect_simple_shrink() */ /*------------------------------------------------------------------------- * Function: H5MF_sect_simple_free * * Purpose: Free a 'single' section node * * Return: Success: non-negative * Failure: negative * * Programmer: Quincey Koziol * Tuesday, January 8, 2008 * *------------------------------------------------------------------------- */ herr_t H5MF_sect_simple_free(H5FS_section_info_t *_sect) { H5MF_free_section_t *sect = (H5MF_free_section_t *)_sect; /* File free section */ FUNC_ENTER_NOAPI_NOINIT_NOERR /* Check arguments. */ HDassert(sect); /* Release the section */ sect = H5FL_FREE(H5MF_free_section_t, sect); FUNC_LEAVE_NOAPI(SUCCEED) } /* H5MF_sect_simple_free() */ /*------------------------------------------------------------------------- * Function: H5MF_sect_simple_valid * * Purpose: Check the validity of a section * * Return: Success: non-negative * Failure: negative * * Programmer: Quincey Koziol * Tuesday, January 8, 2008 * *------------------------------------------------------------------------- */ static herr_t H5MF_sect_simple_valid(const H5FS_section_class_t H5_ATTR_UNUSED *cls, const H5FS_section_info_t #ifdef NDEBUG H5_ATTR_UNUSED #endif /* NDEBUG */ *_sect) { #ifndef NDEBUG const H5MF_free_section_t *sect = (const H5MF_free_section_t *)_sect; /* File free section */ #endif /* NDEBUG */ FUNC_ENTER_NOAPI_NOINIT_NOERR /* Check arguments. */ HDassert(sect); FUNC_LEAVE_NOAPI(SUCCEED) } /* H5MF_sect_simple_valid() */ /*------------------------------------------------------------------------- * Function: H5MF_sect_simple_split * * Purpose: Split SECT into 2 sections: fragment for alignment & the aligned section * SECT's addr and size are updated to point to the aligned section * * Return: Success: the fragment for aligning sect * Failure: null * * Programmer: Vailin Choi, July 29, 2008 * *------------------------------------------------------------------------- */ static H5FS_section_info_t * H5MF_sect_simple_split(H5FS_section_info_t *sect, hsize_t frag_size) { H5MF_free_section_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT /* Allocate space for new section */ if (NULL == (ret_value = H5MF_sect_simple_new(sect->addr, frag_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't initialize free space section") /* Set new section's info */ sect->addr += frag_size; sect->size -= frag_size; done: FUNC_LEAVE_NOAPI((H5FS_section_info_t *)ret_value) } /* end H5MF_sect_simple_split() */