diff options
Diffstat (limited to 'src/H5MF.c')
-rw-r--r-- | src/H5MF.c | 3482 |
1 files changed, 2517 insertions, 965 deletions
@@ -29,6 +29,7 @@ /****************/ #define H5F_FRIEND /*suppress error about including H5Fpkg */ +#define H5FS_FRIEND /*suppress error about including H5Fpkg */ #include "H5MFmodule.h" /* This source code file is part of the H5MF module */ @@ -38,6 +39,7 @@ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fpkg.h" /* File access */ +#include "H5FSpkg.h" /* File access */ #include "H5Iprivate.h" /* IDs */ #include "H5MFpkg.h" /* File memory management */ #include "H5VMprivate.h" /* Vectors and arrays */ @@ -50,11 +52,6 @@ #define H5MF_FSPACE_SHRINK 80 /* Percent of "normal" size to shrink serialized free space size */ #define H5MF_FSPACE_EXPAND 120 /* Percent of "normal" size to expand serialized free space size */ -/* Map an allocation request type to a free list */ -#define H5MF_ALLOC_TO_FS_TYPE(F, T) ((H5FD_MEM_DEFAULT == (F)->shared->fs_type_map[T]) \ - ? (T) : (F)->shared->fs_type_map[T]) - - /******************/ /* Local Typedefs */ /******************/ @@ -84,11 +81,24 @@ typedef struct { /********************/ /* Allocator routines */ -static herr_t H5MF_alloc_create(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type); -static herr_t H5MF__alloc_close(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type); -static herr_t H5MF__close_delete(H5F_t *f, hid_t dxpl_id, H5P_genplist_t **dxpl); +static haddr_t H5MF__alloc_pagefs(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size); + +/* "File closing" routines */ +static herr_t H5MF__close_aggrfs(H5F_t *f, hid_t dxpl_id); +static herr_t H5MF__close_pagefs(H5F_t *f, hid_t dxpl_id); static herr_t H5MF__close_shrink_eoa(H5F_t *f, hid_t dxpl_id); +/* General routines */ +static herr_t H5MF__get_free_sects(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5MF_sect_iter_ud_t *sect_udata, size_t *nums); +static hbool_t H5MF__fsm_type_is_self_referential(H5F_t *f, H5F_mem_page_t fsm_type); +static hbool_t H5MF__fsm_is_self_referential(H5F_t *f, H5FS_t *fspace); + +/* Free-space type manager routines */ +static herr_t H5MF__create_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type); +static herr_t H5MF__close_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type); +static herr_t H5MF__delete_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type); +static herr_t H5MF__close_delete_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type); + /*********************/ /* Package Variables */ @@ -223,10 +233,54 @@ done: /*------------------------------------------------------------------------- - * Function: H5MF__alloc_open + * Function: H5MF_alloc_to_fs_type + * + * Purpose: Map "alloc_type" to the free-space manager type + * + * Return: Success: non-negative + * Failure: negative + * + * Programmer: Vailin Choi; Nov 2016 + * + *------------------------------------------------------------------------- + */ +void +H5MF_alloc_to_fs_type(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size, H5F_mem_page_t *fs_type) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(f); + HDassert(fs_type); + + if(H5F_PAGED_AGGR(f)) { /* paged aggregation */ + if(size >= f->shared->fs_page_size) { + if(H5F_HAS_FEATURE(f, H5FD_FEAT_PAGED_AGGR)) { /* multi or split driver */ + /* For non-contiguous address space, map to large size free-space manager for each alloc_type */ + if(H5FD_MEM_DEFAULT == f->shared->fs_type_map[alloc_type]) + *fs_type = (H5F_mem_page_t) (alloc_type + (H5FD_MEM_NTYPES - 1)); + else + *fs_type = (H5F_mem_page_t) (f->shared->fs_type_map[alloc_type] + (H5FD_MEM_NTYPES - 1)); + } /* end if */ + else + /* For contiguous address space, map to generic large size free-space manager */ + *fs_type = H5F_MEM_PAGE_GENERIC; /* H5F_MEM_PAGE_SUPER */ + } /* end if */ + else + *fs_type = (H5F_mem_page_t)H5MF_ALLOC_TO_FS_AGGR_TYPE(f, alloc_type); + } /* end if */ + else /* non-paged aggregation */ + *fs_type = (H5F_mem_page_t)H5MF_ALLOC_TO_FS_AGGR_TYPE(f, alloc_type); + + FUNC_LEAVE_NOAPI_VOID +} /* end H5MF_alloc_to_fs_type() */ + + +/*------------------------------------------------------------------------- + * Function: H5MF_open_fstype * * Purpose: Open an existing free space manager of TYPE for file by - * creating a free-space structure + * creating a free-space structure. + * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. * * Return: Success: non-negative * Failure: negative @@ -238,31 +292,48 @@ done: *------------------------------------------------------------------------- */ herr_t -H5MF__alloc_open(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type) +H5MF_open_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type) { const H5FS_section_class_t *classes[] = { /* Free space section classes implemented for file */ - H5MF_FSPACE_SECT_CLS_SIMPLE}; - H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ - H5AC_ring_t fsm_ring; /* Free space manager ring */ - H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ - hbool_t reset_ring = FALSE; /* Whether the ring was set */ - herr_t ret_value = SUCCEED; /* Return value */ + H5MF_FSPACE_SECT_CLS_SIMPLE, + H5MF_FSPACE_SECT_CLS_SMALL, + H5MF_FSPACE_SECT_CLS_LARGE }; + hsize_t alignment; /* Alignment to use */ + hsize_t threshold; /* Threshold to use */ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) + FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) /* * Check arguments. */ HDassert(f); + if(H5F_PAGED_AGGR(f)) + HDassert(type < H5F_MEM_PAGE_NTYPES); + else { + HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES); + HDassert((H5FD_mem_t)type != H5FD_MEM_NOLIST); + } /* end else */ HDassert(f->shared); - HDassert(type != H5FD_MEM_NOLIST); HDassert(H5F_addr_defined(f->shared->fs_addr[type])); HDassert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED); - HDassert(type == H5MF_ALLOC_TO_FS_TYPE(f, type)); + + /* Set up the aligment and threshold to use depending on the manager type */ + if(H5F_PAGED_AGGR(f)) { + alignment = (type == H5F_MEM_PAGE_GENERIC) ? f->shared->fs_page_size : (hsize_t)H5F_ALIGN_DEF; + threshold = H5F_ALIGN_THRHD_DEF; + } /* end if */ + else { + alignment = f->shared->alignment; + threshold = f->shared->threshold; + } /* end else */ /* Set the ring type in the DXPL */ - if((type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) + if(H5MF__fsm_type_is_self_referential(f, type)) fsm_ring = H5AC_RING_MDFSM; else fsm_ring = H5AC_RING_RDFSM; @@ -272,7 +343,7 @@ H5MF__alloc_open(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type) /* Open an existing free space structure for the file */ if(NULL == (f->shared->fs_man[type] = H5FS_open(f, dxpl_id, f->shared->fs_addr[type], - NELMTS(classes), classes, f, f->shared->alignment, f->shared->threshold))) + NELMTS(classes), classes, f, alignment, threshold))) 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 */ @@ -286,14 +357,15 @@ done: HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) -} /* end H5MF__alloc_open() */ +} /* end H5MF_open_fstype() */ /*------------------------------------------------------------------------- - * Function: H5MF_alloc_create + * Function: H5MF__create_fstype * * Purpose: Create free space manager of TYPE for the file by creating - * a free-space structure + * a free-space structure + * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. * * Return: Success: non-negative * Failure: negative @@ -305,21 +377,34 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5MF_alloc_create(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type) +H5MF__create_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type) { const H5FS_section_class_t *classes[] = { /* Free space section classes implemented for file */ - H5MF_FSPACE_SECT_CLS_SIMPLE}; - herr_t ret_value = SUCCEED; /* Return value */ - H5FS_create_t fs_create; /* Free space creation parameters */ + H5MF_FSPACE_SECT_CLS_SIMPLE, + H5MF_FSPACE_SECT_CLS_SMALL, + H5MF_FSPACE_SECT_CLS_LARGE }; + H5FS_create_t fs_create; /* Free space creation parameters */ + hsize_t alignment; /* Alignment to use */ + hsize_t threshold; /* Threshold to use */ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) + FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) /* * Check arguments. */ HDassert(f); + if(H5F_PAGED_AGGR(f)) + HDassert(type < H5F_MEM_PAGE_NTYPES); + else { + HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES); + HDassert((H5FD_mem_t)type != H5FD_MEM_NOLIST); + } /* end else */ HDassert(f->shared); - HDassert(type != H5FD_MEM_NOLIST); HDassert(!H5F_addr_defined(f->shared->fs_addr[type])); HDassert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED); @@ -330,24 +415,48 @@ H5MF_alloc_create(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type) 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[type] = H5FS_create(f, dxpl_id, NULL, - &fs_create, NELMTS(classes), classes, f, f->shared->alignment, f->shared->threshold))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info") + /* Set up alignment and threshold to use depending on TYPE */ + if(H5F_PAGED_AGGR(f)) { + alignment = (type == H5F_MEM_PAGE_GENERIC) ? f->shared->fs_page_size : (hsize_t)H5F_ALIGN_DEF; + threshold = H5F_ALIGN_THRHD_DEF; + } /* end if */ + else { + alignment = f->shared->alignment; + threshold = f->shared->threshold; + } /* end else */ + /* Set the ring type in the DXPL */ + if(H5MF__fsm_type_is_self_referential(f, type)) + fsm_ring = H5AC_RING_MDFSM; + else + fsm_ring = H5AC_RING_RDFSM; + if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + reset_ring = TRUE; + + if(NULL == (f->shared->fs_man[type] = H5FS_create(f, dxpl_id, NULL, + &fs_create, NELMTS(classes), classes, f, alignment, threshold))) + 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[type]) f->shared->fs_state[type] = H5F_FS_STATE_OPEN; done: + /* Reset the ring in the DXPL */ + if(reset_ring) + if(H5AC_reset_ring(dxpl, orig_ring) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) -} /* end H5MF_alloc_create() */ +} /* end H5MF__create_fstype() */ /*------------------------------------------------------------------------- - * Function: H5MF__alloc_start + * Function: H5MF_start_fstype * - * Purpose: Open or create a free space manager of a given type + * Purpose: Open or create a free space manager of a given TYPE. + * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. * * Return: Success: non-negative * Failure: negative @@ -359,40 +468,123 @@ done: *------------------------------------------------------------------------- */ herr_t -H5MF__alloc_start(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type) +H5MF_start_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) /* * Check arguments. */ HDassert(f); HDassert(f->shared); - HDassert(type != H5FD_MEM_NOLIST); + if(H5F_PAGED_AGGR(f)) + HDassert(type < H5F_MEM_PAGE_NTYPES); + else { + HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES); + HDassert((H5FD_mem_t)type != H5FD_MEM_NOLIST); + } /* end else */ /* Check if the free space manager exists already */ if(H5F_addr_defined(f->shared->fs_addr[type])) { /* Open existing free space manager */ - if(H5MF__alloc_open(f, dxpl_id, type) < 0) + if(H5MF_open_fstype(f, dxpl_id, type) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, FAIL, "can't initialize file free space") } /* end if */ else { /* Create new free space manager */ - if(H5MF_alloc_create(f, dxpl_id, type) < 0) + if(H5MF__create_fstype(f, dxpl_id, type) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCREATE, FAIL, "can't initialize file free space") } /* end else */ done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5MF__alloc_start() */ + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5MF_start_fstype() */ + + +/*------------------------------------------------------------------------- + * Function: H5MF__delete_fstype + * + * Purpose: Delete the free-space manager as specified by TYPE. + * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. + * + * Return: Success: non-negative + * Failure: negative + * + * Programmer: Vailin Choi; April 2013 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5MF__delete_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type) +{ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + haddr_t tmp_fs_addr; /* Temporary holder for free space manager address */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) + + /* check args */ + HDassert(f); + if(H5F_PAGED_AGGR(f)) + HDassert(type < H5F_MEM_PAGE_NTYPES); + else + HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES); + HDassert(H5F_addr_defined(f->shared->fs_addr[type])); + + /* Put address into temporary variable and reset it */ + /* (Avoids loopback in file space freeing routine) */ + tmp_fs_addr = f->shared->fs_addr[type]; + f->shared->fs_addr[type] = HADDR_UNDEF; + + /* Shift to "deleting" state, to make certain we don't track any + * file space freed as a result of deleting the free space manager. + */ + f->shared->fs_state[type] = H5F_FS_STATE_DELETING; + + /* Set the ring type in the DXPL */ + if(H5MF__fsm_type_is_self_referential(f, type)) + fsm_ring = H5AC_RING_MDFSM; + else + fsm_ring = H5AC_RING_RDFSM; + if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + reset_ring = TRUE; + +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Before deleting free space manager\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* Delete free space manager for this type */ + if(H5FS_delete(f, dxpl_id, tmp_fs_addr) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't delete free space manager") + + /* Shift [back] to closed state */ + HDassert(f->shared->fs_state[type] == H5F_FS_STATE_DELETING); + f->shared->fs_state[type] = H5F_FS_STATE_CLOSED; + + /* Sanity check that the free space manager for this type wasn't started up again */ + HDassert(!H5F_addr_defined(f->shared->fs_addr[type])); + +done: + /* Reset the ring in the DXPL */ + if(reset_ring) + if(H5AC_reset_ring(dxpl, orig_ring) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") + + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5MF__delete_fstype() */ /*------------------------------------------------------------------------- - * Function: H5MF__alloc_close + * Function: H5MF__close_fstype * - * Purpose: Close an existing free space manager of TYPE for file + * Purpose: Close the free space manager of TYPE for file + * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. * * Return: Success: non-negative * Failure: negative @@ -402,7 +594,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5MF__alloc_close(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type) +H5MF__close_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type) { herr_t ret_value = SUCCEED; /* Return value */ @@ -412,11 +604,18 @@ H5MF__alloc_close(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type) * Check arguments. */ HDassert(f); + if(H5F_PAGED_AGGR(f)) + HDassert(type < H5F_MEM_PAGE_NTYPES); + else + HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES); HDassert(f->shared); - HDassert(type != H5FD_MEM_NOLIST); HDassert(f->shared->fs_man[type]); HDassert(f->shared->fs_state[type] != H5F_FS_STATE_CLOSED); +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Before closing free space manager\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + /* Close an existing free space structure for the file */ if(H5FS_close(f, dxpl_id, f->shared->fs_man[type]) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free space info") @@ -425,7 +624,158 @@ H5MF__alloc_close(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type) done: FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) -} /* end H5MF__alloc_close() */ +} /* end H5MF__close_fstype() */ + + + +/*------------------------------------------------------------------------- + * Function: H5MF_add_sect + * + * Purpose: To add a section to the specified free-space manager. + * + * Return: Success: non-negative + * Failure: negative + * + * Programmer: Vailin Choi; April 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5MF_add_sect(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, H5FS_t *fspace, H5MF_free_section_t *node) +{ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */ + H5MF_sect_ud_t udata; /* User data for callback */ + H5F_mem_page_t fs_type; /* Free space type (mapped from allocation type) */ + + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) + + HDassert(f); + HDassert(fspace); + HDassert(node); + + H5MF_alloc_to_fs_type(f, alloc_type, node->sect_info.size, &fs_type); + + /* Construct user data for callbacks */ + udata.f = f; + udata.dxpl_id = dxpl_id; + udata.alloc_type = alloc_type; + udata.allow_sect_absorb = TRUE; + udata.allow_eoa_shrink_only = FALSE; + + /* Set the ring type in the DXPL */ + if(H5MF__fsm_is_self_referential(f, fspace)) + fsm_ring = H5AC_RING_MDFSM; + else + fsm_ring = H5AC_RING_RDFSM; + if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + +#ifdef H5MF_ALLOC_DEBUG_MORE +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 /* H5MF_ALLOC_DEBUG_MORE */ + /* Add the section */ + if(H5FS_sect_add(f, dxpl_id, fspace, (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space") + +done: + /* Reset the ring in the DXPL */ + if(H5AC_reset_ring(dxpl, orig_ring) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5MF_add_sect() */ + + +/*------------------------------------------------------------------------- + * Function: H5MF_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 + * + * Programmer: Vailin Choi; April 2013 + * + *------------------------------------------------------------------------- + */ +htri_t +H5MF_find_sect(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size, H5FS_t *fspace, haddr_t *addr) +{ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */ + H5MF_free_section_t *node; /* Free space section pointer */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + htri_t ret_value = FAIL; /* Whether an existing free list node was found */ + + FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) + + HDassert(f); + HDassert(fspace); + + /* Set the ring type in the DXPL */ + if(H5MF__fsm_is_self_referential(f, fspace)) + fsm_ring = H5AC_RING_MDFSM; + else + fsm_ring = H5AC_RING_RDFSM; + if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + reset_ring = TRUE; + + /* Try to get a section from the free space manager */ + if((ret_value = H5FS_sect_find(f, dxpl_id, fspace, size, (H5FS_section_info_t **)&node)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "error locating free space in file") + +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: section found = %t\n", FUNC, ret_value); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* 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 H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: freeing node\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* Free section node */ + if(H5MF_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 H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: re-adding node, node->sect_info.size = %Hu\n", FUNC, node->sect_info.size); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* Re-add the section to the free-space manager */ + if(H5MF_add_sect(f, alloc_type, dxpl_id, fspace, node) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space") + } /* end else */ + } /* end if */ + +done: + /* Reset the ring in the DXPL */ + if(reset_ring) + if(H5AC_reset_ring(dxpl, orig_ring) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") + + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5MF_find_sect() */ /*------------------------------------------------------------------------- @@ -451,7 +801,7 @@ H5MF_alloc(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size) H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ H5AC_ring_t fsm_ring = H5AC_RING_INV; /* free space manager ring */ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ - H5FD_mem_t fs_type; /* Free space type (mapped from allocation type) */ + H5F_mem_page_t fs_type; /* Free space type (mapped from allocation type) */ hbool_t reset_ring = FALSE; /* Whether the ring was set */ haddr_t ret_value = HADDR_UNDEF; /* Return value */ @@ -466,12 +816,20 @@ HDfprintf(stderr, "%s: alloc_type = %u, size = %Hu\n", FUNC, (unsigned)alloc_typ HDassert(f->shared->lf); HDassert(size > 0); - /* Get free space type from allocation type */ - fs_type = H5MF_ALLOC_TO_FS_TYPE(f, alloc_type); + if(f->shared->first_alloc_dealloc) { + HDassert(! H5AC_cache_image_pending(f)); + if(H5MF_tidy_self_referential_fsm_hack(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, HADDR_UNDEF, "tidy of self referential fsm hack failed") + } /* end if */ + + H5MF_alloc_to_fs_type(f, alloc_type, size, &fs_type); + +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Check 1.0\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG_MORE */ /* Set the ring type in the DXPL */ - if((fs_type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (fs_type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) + if(H5MF__fsm_type_is_self_referential(f, fs_type)) fsm_ring = H5AC_RING_MDFSM; else fsm_ring = H5AC_RING_RDFSM; @@ -481,74 +839,46 @@ HDfprintf(stderr, "%s: alloc_type = %u, size = %Hu\n", FUNC, (unsigned)alloc_typ /* Check if we are using the free space manager for this file */ if(H5F_HAVE_FREE_SPACE_MANAGER(f)) { + /* We are about to change the contents of the free space manager -- + * notify metadata cache that the associated fsm ring is + * unsettled + */ + if(H5AC_unsettle_ring(f, fsm_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, HADDR_UNDEF, "attempt to notify cache that ring is unsettled failed") + /* Check if the free space manager for the file has been initialized */ - if(!f->shared->fs_man[fs_type] && H5F_addr_defined(f->shared->fs_addr[fs_type])) - if(H5MF__alloc_open(f, dxpl_id, fs_type) < 0) + if(!f->shared->fs_man[fs_type] && H5F_addr_defined(f->shared->fs_addr[fs_type])) { + /* Open the free-space manager */ + if(H5MF_open_fstype(f, dxpl_id, fs_type) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, HADDR_UNDEF, "can't initialize file free space") + HDassert(f->shared->fs_man[fs_type]); + } /* end if */ /* Search for large enough space in the free space manager */ - if(f->shared->fs_man[fs_type]) { - H5MF_free_section_t *node; /* Free space section pointer */ - htri_t node_found = FALSE; /* Whether an existing free list node was found */ - - /* Try to get a section from the free space manager */ - if((node_found = H5FS_sect_find(f, dxpl_id, f->shared->fs_man[fs_type], size, (H5FS_section_info_t **)&node)) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "error locating free space in file") -#ifdef H5MF_ALLOC_DEBUG_MORE -HDfprintf(stderr, "%s: Check 1.5, node_found = %t\n", FUNC, node_found); -#endif /* H5MF_ALLOC_DEBUG_MORE */ - - /* Check for actually finding section */ - if(node_found) { - /* Sanity check */ - HDassert(node); - - /* Retrieve return value */ - ret_value = node->sect_info.addr; - - /* Check for eliminating the section */ - if(node->sect_info.size == size) { -#ifdef H5MF_ALLOC_DEBUG_MORE -HDfprintf(stderr, "%s: Check 1.6, freeing node\n", FUNC); -#endif /* H5MF_ALLOC_DEBUG_MORE */ - /* Free section node */ - if(H5MF_sect_simple_free((H5FS_section_info_t *)node) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, HADDR_UNDEF, "can't free simple section node") - } /* end if */ - else { - H5MF_sect_ud_t udata; /* User data for callback */ - - /* Adjust information for section */ - node->sect_info.addr += size; - node->sect_info.size -= size; - - /* Construct user data for callbacks */ - udata.f = f; - udata.dxpl_id = dxpl_id; - udata.alloc_type = alloc_type; - udata.allow_sect_absorb = TRUE; - udata.allow_eoa_shrink_only = FALSE; + if(f->shared->fs_man[fs_type]) + if(H5MF_find_sect(f, alloc_type, dxpl_id, size, f->shared->fs_man[fs_type], &ret_value) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "error locating a node") + } /* end if */ + /* If no space is found from the free-space manager, continue further action */ + if(!H5F_addr_defined(ret_value)) { #ifdef H5MF_ALLOC_DEBUG_MORE -HDfprintf(stderr, "%s: Check 1.7, re-adding node, node->sect_info.size = %Hu\n", FUNC, node->sect_info.size); +HDfprintf(stderr, "%s: Check 2.0\n", FUNC); #endif /* H5MF_ALLOC_DEBUG_MORE */ - /* Re-insert section node into file's free space */ - if(H5FS_sect_add(f, dxpl_id, f->shared->fs_man[fs_type], (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, "can't re-add section to file free space") - } /* end else */ - - /* Leave now */ - HGOTO_DONE(ret_value) - } /* end if */ + if(f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE) { + HDassert(f->shared->fs_page_size >= H5F_FILE_SPACE_PAGE_SIZE_MIN); + if(HADDR_UNDEF == (ret_value = H5MF__alloc_pagefs(f, alloc_type, dxpl_id, size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed from paged aggregation") } /* end if */ + else { /* For non-paged aggregation, continue further action */ + if(HADDR_UNDEF == (ret_value = H5MF_aggr_vfd_alloc(f, alloc_type, dxpl_id, size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed from aggr/vfd") + } /* end else */ + } /* end if */ + HDassert(H5F_addr_defined(ret_value)); #ifdef H5MF_ALLOC_DEBUG_MORE -HDfprintf(stderr, "%s: Check 2.0\n", FUNC); +HDfprintf(stderr, "%s: Check 3.0\n", FUNC); #endif /* H5MF_ALLOC_DEBUG_MORE */ - } /* end if */ - - /* Allocate from the metadata aggregator (or the VFD) */ - if(HADDR_UNDEF == (ret_value = H5MF_aggr_vfd_alloc(f, alloc_type, dxpl_id, size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed from aggr/vfd") done: /* Reset the ring in the DXPL */ @@ -568,6 +898,146 @@ H5MF_sects_dump(f, dxpl_id, stderr); /*------------------------------------------------------------------------- + * Function: H5MF__alloc_pagefs + * + * Purpose: Allocate space from either the large or small free-space manager. + * For "large" request: + * Allocate request from VFD + * Determine mis-aligned fragment and return the fragment to the + * appropriate manager + * For "small" request: + * Allocate a page from the large manager + * Determine whether space is available from a mis-aligned fragment + * being returned to the manager + * Return left-over space to the manager after fulfilling request + * + * Return: Success: The file address of new chunk. + * Failure: HADDR_UNDEF + * + * Programmer: Vailin Choi; Dec 2012 + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5MF__alloc_pagefs(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, hsize_t size) +{ + H5F_mem_page_t ptype; /* Free-space mananger type */ + H5MF_free_section_t *node = NULL; /* Free space section pointer */ + haddr_t ret_value = HADDR_UNDEF; /* Return value */ + + FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, HADDR_UNDEF) + +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: alloc_type = %u, size = %Hu\n", FUNC, (unsigned)alloc_type, size); +#endif /* H5MF_ALLOC_DEBUG */ + + H5MF_alloc_to_fs_type(f, alloc_type, size, &ptype); + + switch(ptype) { + case H5F_MEM_PAGE_GENERIC: + case H5F_MEM_PAGE_LARGE_BTREE: + case H5F_MEM_PAGE_LARGE_DRAW: + case H5F_MEM_PAGE_LARGE_GHEAP: + case H5F_MEM_PAGE_LARGE_LHEAP: + case H5F_MEM_PAGE_LARGE_OHDR: + { + haddr_t eoa; /* EOA for the file */ + hsize_t frag_size = 0; /* Fragment size */ + + /* Get the EOA for the file */ + if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, alloc_type))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "Unable to get eoa") + HDassert(!(eoa % f->shared->fs_page_size)); + + H5MF_EOA_MISALIGN(f, (eoa+size), f->shared->fs_page_size, frag_size); + + /* Allocate from VFD */ + if(HADDR_UNDEF == (ret_value = H5F_alloc(f, dxpl_id, alloc_type, size + frag_size, NULL, NULL))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space") + + /* If there is a mis-aligned fragment at EOA */ + if(frag_size) { + + /* Start up the free-space manager */ + if(!(f->shared->fs_man[ptype])) + if(H5MF_start_fstype(f, dxpl_id, ptype) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize file free space") + + /* Create free space section for the fragment */ + if(NULL == (node = H5MF_sect_new(H5MF_FSPACE_SECT_LARGE, ret_value + size, frag_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize free space section") + + /* Add the fragment to the large free-space manager */ + if(H5MF_add_sect(f, alloc_type, dxpl_id, f->shared->fs_man[ptype], node) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, "can't re-add section to file free space") + + node = NULL; + } /* end if */ + } + break; + + case H5F_MEM_PAGE_META: + case H5F_MEM_PAGE_DRAW: + case H5F_MEM_PAGE_BTREE: + case H5F_MEM_PAGE_GHEAP: + case H5F_MEM_PAGE_LHEAP: + case H5F_MEM_PAGE_OHDR: + { + haddr_t new_page; /* The address for the new file size page */ + + /* Allocate one file space page */ + if(HADDR_UNDEF == (new_page = H5MF_alloc(f, alloc_type, dxpl_id, f->shared->fs_page_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space") + + /* Start up the free-space manager */ + if(!(f->shared->fs_man[ptype])) + if(H5MF_start_fstype(f, dxpl_id, ptype) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize file free space") + HDassert(f->shared->fs_man[ptype]); + + if(NULL == (node = H5MF_sect_new(H5MF_FSPACE_SECT_SMALL, (new_page + size), (f->shared->fs_page_size - size)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize free space section") + + /* Add the remaining space in the page to the manager */ + if(H5MF_add_sect(f, alloc_type, dxpl_id, f->shared->fs_man[ptype], node) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, "can't re-add section to file free space") + + node = NULL; + + /* Insert the new page into the Page Buffer list of new pages so + we don't read an empty page from disk */ + if(f->shared->page_buf != NULL && H5PB_add_new_page(f, alloc_type, new_page) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, "can't add new page to Page Buffer new page list") + + ret_value = new_page; + } + break; + + case H5F_MEM_PAGE_NTYPES: + case H5F_MEM_PAGE_DEFAULT: + default: + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space: unrecognized type") + break; + } /* end switch */ + +done: +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving: ret_value = %a, size = %Hu\n", FUNC, ret_value, size); +#endif /* H5MF_ALLOC_DEBUG */ +#ifdef H5MF_ALLOC_DEBUG_DUMP +H5MF_sects_dump(f, dxpl_id, stderr); +#endif /* H5MF_ALLOC_DEBUG_DUMP */ + + /* Release section node, if allocated and not added to section list or merged */ + if(node) + if(H5MF_sect_free((H5FS_section_info_t *)node) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, HADDR_UNDEF, "can't free section node") + + FUNC_LEAVE_NOAPI_TAG(ret_value, HADDR_UNDEF) +} /* end H5MF__alloc_pagefs() */ + + +/*------------------------------------------------------------------------- * Function: H5MF_alloc_tmp * * Purpose: Allocate temporary space in the file @@ -646,13 +1116,13 @@ H5MF_xfree(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, haddr_t addr, hsize_t size) { H5F_io_info2_t fio_info; /* I/O info for operation */ + H5F_mem_page_t fs_type; /* Free space type (mapped from allocation type) */ H5MF_free_section_t *node = NULL; /* Free space section pointer */ - H5MF_sect_ud_t udata; /* User data for callback */ + unsigned ctype; /* section class type */ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ - H5AC_ring_t fsm_ring; /* Free space manager ring */ - H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5AC_ring_t fsm_ring = H5AC_RING_INV; /* Ring of fsm */ hbool_t reset_ring = FALSE; /* Whether the ring was set */ - H5FD_mem_t fs_type; /* Free space type (mapped from allocation type) */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) @@ -666,19 +1136,16 @@ HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", FUN HGOTO_DONE(SUCCEED) HDassert(addr != 0); /* Can't deallocate the superblock :-) */ - /* Check for attempting to free space that's a 'temporary' file address */ - if(H5F_addr_le(f->shared->tmp_addr, addr)) - HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, FAIL, "attempting to free temporary file space") + if(f->shared->first_alloc_dealloc) { + HDassert(!H5AC_cache_image_pending(f)); + if(H5MF_tidy_self_referential_fsm_hack(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "tidy of self referential fsm hack failed") + } /* end if */ - /* Get free space type from allocation type */ - fs_type = H5MF_ALLOC_TO_FS_TYPE(f, alloc_type); -#ifdef H5MF_ALLOC_DEBUG_MORE -HDfprintf(stderr, "%s: fs_type = %u\n", FUNC, (unsigned)fs_type); -#endif /* H5MF_ALLOC_DEBUG_MORE */ + H5MF_alloc_to_fs_type(f, alloc_type, size, &fs_type); /* Set the ring type in the DXPL */ - if((fs_type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (fs_type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) + if(H5MF__fsm_type_is_self_referential(f, fs_type)) fsm_ring = H5AC_RING_MDFSM; else fsm_ring = H5AC_RING_RDFSM; @@ -686,6 +1153,19 @@ HDfprintf(stderr, "%s: fs_type = %u\n", FUNC, (unsigned)fs_type); HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") reset_ring = TRUE; + /* we are about to change the contents of the free space manager -- + * notify metadata cache that the associated fsm ring is + * unsettled + */ + /* Only do so for strategies that use free-space managers */ + if(H5F_HAVE_FREE_SPACE_MANAGER(f)) + if(H5AC_unsettle_ring(f, fsm_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, "attempt to notify cache that ring is unsettled failed") + + /* Check for attempting to free space that's a 'temporary' file address */ + if(H5F_addr_le(f->shared->tmp_addr, addr)) + HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, FAIL, "attempting to free temporary file space") + /* Set up I/O info for operation */ fio_info.f = f; if(H5FD_MEM_DRAW == alloc_type) { @@ -712,7 +1192,7 @@ HDfprintf(stderr, "%s: fs_type = %u\n", FUNC, (unsigned)fs_type); * space is at the end of the file */ #ifdef H5MF_ALLOC_DEBUG_MORE -HDfprintf(stderr, "%s: f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)fs_type, f->shared->fs_addr[fs_type]); +HDfprintf(stderr, "%s: fs_addr = %a\n", FUNC, f->shared->fs_addr[fs_type]); #endif /* H5MF_ALLOC_DEBUG_MORE */ if(!H5F_addr_defined(f->shared->fs_addr[fs_type])) { htri_t status; /* "can absorb" status for section into */ @@ -736,8 +1216,8 @@ HDfprintf(stderr, "%s: dropping addr = %a, size = %Hu, on the floor!\n", FUNC, a /* If we are deleting the free space manager, leave now, to avoid * [re-]starting it. - * or if file space strategy type is not using a free space manager - * (H5F_FILE_SPACE_AGGR_VFD or H5F_FILE_SPACE_VFD), drop free space + * or if file space strategy type is not using a free space manager + * (H5F_FSPACE_STRATEGY_AGGR or H5F_FSPACE_STRATEGY_NONE), drop free space * section on the floor. * * Note: this drops the space to free on the floor... @@ -755,38 +1235,42 @@ HDfprintf(stderr, "%s: dropping addr = %a, size = %Hu, on the floor!\n", FUNC, a * space isn't at the end of the file, so start up (or create) * the file space manager */ - if(H5MF__alloc_start(f, dxpl_id, fs_type) < 0) + if(H5MF_start_fstype(f, dxpl_id, fs_type) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space") } /* end if */ - /* Create free space section for block */ - if(NULL == (node = H5MF_sect_simple_new(addr, size))) + /* Create the free-space section for the freed section */ + ctype = H5MF_SECT_CLASS_TYPE(f, size); + if(NULL == (node = H5MF_sect_new(ctype, addr, size))) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section") - /* Construct user data for callbacks */ - udata.f = f; - udata.dxpl_id = dxpl_id; - udata.alloc_type = alloc_type; - udata.allow_sect_absorb = TRUE; - udata.allow_eoa_shrink_only = FALSE; - - /* If size of section freed is larger than threshold, add it to the free space manager */ + /* If size of the freed section is larger than threshold, add it to the free space manager */ if(size >= f->shared->fs_threshold) { HDassert(f->shared->fs_man[fs_type]); #ifdef H5MF_ALLOC_DEBUG_MORE HDfprintf(stderr, "%s: Before H5FS_sect_add()\n", FUNC); #endif /* H5MF_ALLOC_DEBUG_MORE */ + /* Add to the free space for the file */ - if(H5FS_sect_add(f, dxpl_id, f->shared->fs_man[fs_type], (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't add section to file free space") - node = NULL; + if(H5MF_add_sect(f, alloc_type, dxpl_id, f->shared->fs_man[fs_type], node) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't add section to file free space") + node = NULL; + #ifdef H5MF_ALLOC_DEBUG_MORE HDfprintf(stderr, "%s: After H5FS_sect_add()\n", FUNC); #endif /* H5MF_ALLOC_DEBUG_MORE */ } /* end if */ else { htri_t merged; /* Whether node was merged */ + H5MF_sect_ud_t udata; /* User data for callback */ + + /* Construct user data for callbacks */ + udata.f = f; + udata.dxpl_id = dxpl_id; + udata.alloc_type = alloc_type; + udata.allow_sect_absorb = TRUE; + udata.allow_eoa_shrink_only = FALSE; /* Try to merge the section that is smaller than threshold */ if((merged = H5FS_sect_try_merge(f, dxpl_id, f->shared->fs_man[fs_type], (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata)) < 0) @@ -804,7 +1288,7 @@ done: /* Release section node, if allocated and not added to section list or merged */ if(node) - if(H5MF_sect_simple_free((H5FS_section_info_t *)node) < 0) + if(H5MF_sect_free((H5FS_section_info_t *)node) < 0) HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node") #ifdef H5MF_ALLOC_DEBUG @@ -821,6 +1305,14 @@ H5MF_sects_dump(f, dxpl_id, stderr); * Function: H5MF_try_extend * * Purpose: Extend a block in the file if possible. + * For non-paged aggregation: + * --try to extend at EOA + * --try to extend into the aggregators + * --try to extend into a free-space section if adjoined + * For paged aggregation: + * --try to extend at EOA + * --try to extend into a free-space section if adjoined + * --try to extend into the page end threshold if a metadata block * * Return: Success: TRUE(1) - Block was extended * FALSE(0) - Block could not be extended @@ -835,14 +1327,16 @@ htri_t H5MF_try_extend(H5F_t *f, hid_t dxpl_id, H5FD_mem_t alloc_type, haddr_t addr, hsize_t size, hsize_t extra_requested) { - H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ - H5AC_ring_t fsm_ring; /* Free space manager ring */ - H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ - haddr_t end; /* End of block to extend */ - H5FD_mem_t fs_type; /* Memory type of the free space manager */ - H5FD_mem_t map_type; /* Mapped type */ - hbool_t reset_ring = FALSE; /* Whether the ring was set */ - htri_t ret_value = FAIL; /* Return value */ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5AC_ring_t fsm_ring = H5AC_RING_INV; /* ring of fsm */ + haddr_t end; /* End of block to extend */ + H5FD_mem_t map_type; /* Mapped type */ + H5F_mem_page_t fs_type; /* free space type */ + htri_t allow_extend = TRUE; /* Possible to extend the block */ + hsize_t frag_size = 0; /* Size of mis-aligned fragment */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + htri_t ret_value = FALSE; /* Return value */ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) #ifdef H5MF_ALLOC_DEBUG @@ -859,12 +1353,33 @@ HDfprintf(stderr, "%s: Entering: alloc_type = %u, addr = %a, size = %Hu, extra_r /* Compute end of block to extend */ end = addr + size; + /* For paged aggregation: + * To extend a small block: can only extend if not crossing page boundary + * To extend a large block at EOA: calculate in advance mis-aligned fragment so EOA will still end at page boundary + */ + if(H5F_PAGED_AGGR(f)) { + if(size < f->shared->fs_page_size) { + /* To extend a small block: cannot cross page boundary */ + if((addr / f->shared->fs_page_size) != (((end + extra_requested) - 1) / f->shared->fs_page_size)) + allow_extend = FALSE; + } /* end if */ + else { + haddr_t eoa; /* EOA for the file */ + + /* To extend a large block: calculate in advance the mis-aligned fragment so EOA will end at page boundary if extended */ + if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, alloc_type))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa") + HDassert(!(eoa % f->shared->fs_page_size)); + + H5MF_EOA_MISALIGN(f, (eoa+extra_requested), f->shared->fs_page_size, frag_size); + } /* end else */ + } /* end if */ + /* Get free space type from allocation type */ - fs_type = H5MF_ALLOC_TO_FS_TYPE(f, alloc_type); + H5MF_alloc_to_fs_type(f, alloc_type, size, &fs_type); /* Set the ring type in the DXPL */ - if((fs_type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (fs_type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) + if(H5MF__fsm_type_is_self_referential(f, fs_type)) fsm_ring = H5AC_RING_MDFSM; else fsm_ring = H5AC_RING_RDFSM; @@ -872,29 +1387,90 @@ HDfprintf(stderr, "%s: Entering: alloc_type = %u, addr = %a, size = %Hu, extra_r HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") reset_ring = TRUE; - /* Check if the block is exactly at the end of the file */ - if((ret_value = H5FD_try_extend(f->shared->lf, map_type, f, dxpl_id, end, extra_requested)) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending file") - else if(ret_value == FALSE) { - H5F_blk_aggr_t *aggr; /* Aggregator to use */ + if(allow_extend) { + /* Try extending the block at EOA */ + if((ret_value = H5F_try_extend(f, dxpl_id, map_type, end, extra_requested + frag_size)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending file") +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: extended = %t\n", FUNC, ret_value); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* If extending at EOA succeeds: */ + /* for paged aggregation, put the fragment into the large-sized free-space manager */ + if(ret_value == TRUE && H5F_PAGED_AGGR(f) && frag_size) { + H5MF_free_section_t *node = NULL; /* Free space section pointer */ + + /* Should be large-sized block */ + HDassert(size >= f->shared->fs_page_size); + + /* Start up the free-space manager */ + if(!(f->shared->fs_man[fs_type])) + if(H5MF_start_fstype(f, dxpl_id, fs_type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space") + + /* Create free space section for the fragment */ + if(NULL == (node = H5MF_sect_new(H5MF_FSPACE_SECT_LARGE, end + extra_requested, frag_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section") + + /* Add the fragment to the large-sized free-space manager */ + if(H5MF_add_sect(f, alloc_type, dxpl_id, f->shared->fs_man[fs_type], node) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space") + + node = NULL; + } /* end if */ - /* Check for test block able to extend aggregation block */ - aggr = (map_type == H5FD_MEM_DRAW) ? &(f->shared->sdata_aggr) : &(f->shared->meta_aggr); - if((ret_value = H5MF_aggr_try_extend(f, dxpl_id, aggr, map_type, end, extra_requested)) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending aggregation block") - else if(ret_value == FALSE) { + /* For non-paged aggregation: try to extend into the aggregators */ + if(ret_value == FALSE && (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR || + f->shared->fs_strategy == H5F_FSPACE_STRATEGY_AGGR) ) { + H5F_blk_aggr_t *aggr; /* Aggregator to use */ + + /* Check if the block is able to extend into aggregation block */ + aggr = (map_type == H5FD_MEM_DRAW) ? &(f->shared->sdata_aggr) : &(f->shared->meta_aggr); + if((ret_value = H5MF_aggr_try_extend(f, dxpl_id, aggr, map_type, end, extra_requested)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending aggregation block") + +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: H5MF_aggr_try_extend = %t\n", FUNC, ret_value); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + } /* end if */ + + /* If no extension so far, try to extend into a free-space section */ + if(ret_value == FALSE && ((f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR) || + (H5F_PAGED_AGGR(f))) ) { + H5MF_sect_ud_t udata; /* User data */ + + /* Construct user data for callbacks */ + udata.f = f; + udata.dxpl_id = dxpl_id; + udata.alloc_type = alloc_type; /* Check if the free space for the file has been initialized */ if(!f->shared->fs_man[fs_type] && H5F_addr_defined(f->shared->fs_addr[fs_type])) - if(H5MF__alloc_open(f, dxpl_id, fs_type) < 0) + /* Open the free-space manager */ + if(H5MF_open_fstype(f, dxpl_id, fs_type) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space") - /* Check for test block able to block in free space manager */ - if(f->shared->fs_man[fs_type]) - if((ret_value = H5FS_sect_try_extend(f, dxpl_id, f->shared->fs_man[fs_type], addr, size, extra_requested)) < 0) + /* Try to extend the block into a free-space section */ + if(f->shared->fs_man[fs_type]) { + if((ret_value = H5FS_sect_try_extend(f, dxpl_id, f->shared->fs_man[fs_type], addr, size, extra_requested, H5FS_ADD_RETURNED_SPACE, &udata)) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending block in free space manager") +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Try to H5FS_sect_try_extend = %t\n", FUNC, ret_value); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + } /* end if */ + + /* For paged aggregation and a metadata block: try to extend into page end threshold */ + if(ret_value == FALSE && H5F_PAGED_AGGR(f) && map_type != H5FD_MEM_DRAW) { + H5MF_EOA_MISALIGN(f, end, f->shared->fs_page_size, frag_size); + + if(frag_size <= H5F_PGEND_META_THRES(f) && extra_requested <= frag_size) + ret_value = TRUE; +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Try to extend into the page end threshold = %t\n", FUNC, ret_value); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + } /* end if */ } /* end if */ - } /* end else-if */ + } /* allow_extend */ done: /* Reset the ring in the DXPL */ @@ -914,174 +1490,316 @@ H5MF_sects_dump(f, dxpl_id, stderr); /*------------------------------------------------------------------------- - * Function: H5MF_get_freespace + * Function: H5MF_try_shrink * - * Purpose: Retrieve the amount of free space in a file. + * Purpose: Try to shrink the size of a file with a block or absorb it + * into a block aggregator. * - * Return: Success: Amount of free space in file - * Failure: Negative + * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * Monday, October 6, 2003 + * koziol@hdfgroup.org + * Feb 14 2008 * - * Modifications: - * Vailin Choi; July 2012 - * As the default free-list mapping is changed to H5FD_FLMAP_DICHOTOMY, - * checks are added to account for the last section of each free-space manager - * and the remaining space in the two aggregators are at EOF. *------------------------------------------------------------------------- */ -herr_t -H5MF_get_freespace(H5F_t *f, hid_t dxpl_id, hsize_t *tot_space, hsize_t *meta_size) +htri_t +H5MF_try_shrink(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, haddr_t addr, + hsize_t size) { - H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ - H5AC_ring_t curr_ring; /* Current ring value */ - H5AC_ring_t needed_ring; /* Ring value needed for loop iteration */ - H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ - haddr_t eoa; /* End of allocated space in the file */ - 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" */ - hsize_t tot_fs_size = 0; /* Amount of all free space managed */ - hsize_t tot_meta_size = 0; /* Amount of metadata for free space managers */ - H5FD_mem_t type; /* Memory type for iteration */ - hbool_t fs_started[H5FD_MEM_NTYPES]; /* Indicate whether the free-space manager has been started */ - hbool_t eoa_shrank; /* Whether an EOA shrink occurs */ - hbool_t reset_ring = FALSE; /* Whether the ring was set */ - herr_t ret_value = SUCCEED; /* Return value */ + H5MF_free_section_t *node = NULL; /* Free space section pointer */ + H5MF_sect_ud_t udata; /* User data for callback */ + H5FS_section_class_t *sect_cls; /* Section class */ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5AC_ring_t fsm_ring = H5AC_RING_INV; /* Ring of fsm */ + H5F_mem_page_t fs_type; /* Free space type */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + htri_t ret_value = FAIL; /* Return value */ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)alloc_type, addr, size); +#endif /* H5MF_ALLOC_DEBUG */ - /* check args */ + /* check arguments */ HDassert(f); HDassert(f->shared); HDassert(f->shared->lf); + HDassert(H5F_addr_defined(addr)); + HDassert(size > 0); - /* Retrieve the 'eoa' for the file */ - if(HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_DEFAULT))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed") + /* Set up free-space section class information */ + sect_cls = H5MF_SECT_CLS_TYPE(f, size); + HDassert(sect_cls); + + /* Get free space type from allocation type */ + H5MF_alloc_to_fs_type(f, alloc_type, size, &fs_type); /* Set the ring type in the DXPL */ - if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0) + if(H5MF__fsm_type_is_self_referential(f, fs_type)) + fsm_ring = H5AC_RING_MDFSM; + else + fsm_ring = H5AC_RING_RDFSM; + if(H5AC_set_ring(dxpl_id, fsm_ring, &dxpl, &orig_ring) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") reset_ring = TRUE; - curr_ring = H5AC_RING_RDFSM; - /* Retrieve metadata aggregator info, if available */ - if(H5MF_aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query metadata aggregator stats") + /* Create free-space section for block */ + if(NULL == (node = H5MF_sect_new(sect_cls->type, addr, size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section") - /* Retrieve 'small data' aggregator info, if available */ - if(H5MF_aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query small data aggregator stats") + /* Construct user data for callbacks */ + udata.f = f; + udata.dxpl_id = dxpl_id; + udata.alloc_type = alloc_type; + udata.allow_sect_absorb = FALSE; /* Force section to be absorbed into aggregator */ + udata.allow_eoa_shrink_only = FALSE; - /* Iterate over all the free space types that have managers and get each free list's space */ - for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { + /* Check if the block can shrink the container */ + if(sect_cls->can_shrink) { + if((ret_value = (*sect_cls->can_shrink)((const H5FS_section_info_t *)node, &udata)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check if section can shrink container") + if(ret_value > 0) { + HDassert(sect_cls->shrink); - fs_started[type] = FALSE; + if((*sect_cls->shrink)((H5FS_section_info_t **)&node, &udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink container") + } /* end if */ + } /* end if */ - /* test to see if we need to switch rings -- do so if required */ - if((type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) - needed_ring = H5AC_RING_MDFSM; - else - needed_ring = H5AC_RING_RDFSM; +done: + /* Reset the ring in the DXPL */ + if(reset_ring) + if(H5AC_reset_ring(dxpl, orig_ring) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") - if(needed_ring != curr_ring) { - if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (2)") - curr_ring = needed_ring; - } /* end if */ + /* Free section node allocated */ + if(node && H5MF_sect_free((H5FS_section_info_t *)node) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node") - /* Check if the free space for the file has been initialized */ - if(!f->shared->fs_man[type] && H5F_addr_defined(f->shared->fs_addr[type])) { - if(H5MF__alloc_open(f, dxpl_id, type) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space") - HDassert(f->shared->fs_man[type]); - fs_started[type] = TRUE; - } /* end if */ +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value); +#endif /* H5MF_ALLOC_DEBUG */ + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5MF_try_shrink() */ - /* Check if there's free space of this type */ - if(f->shared->fs_man[type]) { - hsize_t type_fs_size = 0; /* Amount of free space managed for each type */ - hsize_t type_meta_size = 0; /* Amount of free space metadata for each type */ + +/*------------------------------------------------------------------------- + * Function: H5MF_close + * + * Purpose: Close the free space tracker(s) for a file: + * paged or non-paged aggregation + * + * Return: SUCCEED/FAIL + * + * Programmer: Vailin Choi; Dec 2012 + * + *------------------------------------------------------------------------- + */ +herr_t +H5MF_close(H5F_t *f, hid_t dxpl_id) +{ + herr_t ret_value = SUCCEED; /* Return value */ - /* Retrieve free space size from free space manager */ - if(H5FS_sect_stats(f->shared->fs_man[type], &type_fs_size, NULL) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats") - if(H5FS_size(f, f->shared->fs_man[type], &type_meta_size) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space metadata stats") + FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Entering\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG */ - /* Increment total free space for types */ - tot_fs_size += type_fs_size; - tot_meta_size += type_meta_size; - } /* end if */ - } /* end for */ + /* check args */ + HDassert(f); + HDassert(f->shared); - /* Iterate until no more EOA shrink occurs */ - do { - eoa_shrank = FALSE; + if(H5F_PAGED_AGGR(f)) { + if((ret_value = H5MF__close_pagefs(f, dxpl_id)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't close free-space managers for 'page' file space") + } /* end if */ + else { + if((ret_value = H5MF__close_aggrfs(f, dxpl_id)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't close free-space managers for 'aggr' file space") + } /* end else */ - /* Check the last section of each free-space manager */ - for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { - haddr_t sect_addr = HADDR_UNDEF; - hsize_t sect_size = 0; - - if(f->shared->fs_man[type]) { - if(H5FS_sect_query_last_sect(f->shared->fs_man[type], §_addr, §_size) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query last section on merge list") - - /* Deduct space from previous accumulation if the section is at EOA */ - if(H5F_addr_eq(sect_addr + sect_size, eoa)) { - eoa = sect_addr; - eoa_shrank = TRUE; - tot_fs_size -= sect_size; - } /* end if */ - } /* end if */ - } /* end for */ - - /* Check the metadata and raw data aggregators */ - if(ma_size > 0 && H5F_addr_eq(ma_addr + ma_size, eoa)) { - eoa = ma_addr; - eoa_shrank = TRUE; - ma_size = 0; - } /* end if */ - if(sda_size > 0 && H5F_addr_eq(sda_addr + sda_size, eoa)) { - eoa = sda_addr; - eoa_shrank = TRUE; - sda_size = 0; - } /* end if */ - } while(eoa_shrank); +done: - /* Close the free-space managers if they were opened earlier in this routine */ - for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { - if(fs_started[type]) { +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG */ + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5MF_close() */ + + +/*------------------------------------------------------------------------- + * Function: H5MF__close_delete_fstype + * + * Purpose: Common code for closing and deleting the freespace manager + * of TYPE for file. + * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. + * + * Return: SUCCEED/FAIL + * + * Programmer: Vailin Choi + * Jan 2016 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5MF__close_delete_fstype(H5F_t *f, hid_t dxpl_id, H5F_mem_page_t type) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Entering\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG */ + + /* check args */ + HDassert(f); + HDassert(f->shared); + if(H5F_PAGED_AGGR(f)) + HDassert(type < H5F_MEM_PAGE_NTYPES); + else + HDassert((H5FD_mem_t)type < H5FD_MEM_NTYPES); + +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Check 1.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* If the free space manager for this type is open, close it */ + if(f->shared->fs_man[type]) + if(H5MF__close_fstype(f, dxpl_id, type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager") + +#ifdef H5MF_ALLOC_DEBUG_MORE +HDfprintf(stderr, "%s: Check 2.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]); +#endif /* H5MF_ALLOC_DEBUG_MORE */ + + /* If there is free space manager info for this type, delete it */ + if(H5F_addr_defined(f->shared->fs_addr[type])) + if(H5MF__delete_fstype(f, dxpl_id, type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't delete the free space manager") + +done: +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG */ + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* H5MF__close_delete() */ + + +/*------------------------------------------------------------------------- + * Function: H5MF_try_close + * + * Purpose: This is called by H5Fformat_convert() to close and delete + * free-space managers when downgrading persistent free-space + * to non-persistent. + * + * Return: SUCCEED/FAIL + * + * Programmer: Vailin Choi + * Jan 2016 + * + *------------------------------------------------------------------------- + */ +herr_t +H5MF_try_close(H5F_t *f, hid_t dxpl_id) +{ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ + H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Entering\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG */ + + /* check args */ + HDassert(f); + /* If there have been no file space allocations / deallocation so + * far, must call H5MF_tidy_self_referential_fsm_hack() to float + * all self referential FSMs and release file space allocated to + * them. Otherwise, the function will be called after the format + * conversion, and will become very confused. + * + * The situation is further complicated if a cache image exists + * and had not yet been loaded into the metadata cache. In this + * case, call H5AC_force_cache_image_load() instead of + * H5MF_tidy_self_referential_fsm_hack(). H5AC_force_cache_image_load() + * will load the cache image, and then call + * H5MF_tidy_self_referential_fsm_hack() to discard the cache image + * block. + */ + if(f->shared->first_alloc_dealloc) { + if(H5AC_cache_image_pending(f)) { + if(H5AC_force_cache_image_load(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "forced cache image load failed") + } /* end if */ + else { + if(H5MF_tidy_self_referential_fsm_hack(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "tidy of self referential fsm hack failed") + } /* end else */ + } /* end if */ + + /* Set the ring type in the DXPL. In most cases, we will + * need H5AC_RING_RDFSM, so initialy set the ring in + * the DXPL to that value. We will alter this later if + * needed. + */ + if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + reset_ring = TRUE; + curr_ring = H5AC_RING_RDFSM; + + if(H5F_PAGED_AGGR(f)) { + H5F_mem_page_t ptype; /* Memory type for iteration */ + + /* Iterate over all the free space types that have managers and + * get each free list's space + */ + for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) { + /* Test to see if we need to switch rings -- do so if required */ + if(H5MF__fsm_type_is_self_referential(f, ptype)) + needed_ring = H5AC_RING_MDFSM; + else + needed_ring = H5AC_RING_RDFSM; + + if(needed_ring != curr_ring ) { + if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)") + curr_ring = needed_ring; + } /* end if */ + + if(H5MF__close_delete_fstype(f, dxpl_id, ptype) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager") + } /* end for */ + } /* end if */ + else { + H5FD_mem_t type; /* Memory type for iteration */ + + /* Iterate over all the free space types that have managers and + * get each free list's space + */ + for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { /* test to see if we need to switch rings -- do so if required */ - if((type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) + if(H5MF__fsm_type_is_self_referential(f, (H5F_mem_page_t)type)) needed_ring = H5AC_RING_MDFSM; else needed_ring = H5AC_RING_RDFSM; if(needed_ring != curr_ring) { if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (3)") + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") curr_ring = needed_ring; } /* end if */ - if(H5MF__alloc_close(f, dxpl_id, type) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't close file free space") - } /* end if */ - } /* end for */ - - /* Set the value(s) to return */ - /* (The metadata & small data aggregators count as free space now, since they aren't at EOA) */ - if(tot_space) - *tot_space = tot_fs_size + ma_size + sda_size; - if(meta_size) - *meta_size = tot_meta_size; + if(H5MF__close_delete_fstype(f, dxpl_id, (H5F_mem_page_t)type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager") + } /* end for */ + } /* end else */ done: /* Reset the ring in the DXPL */ @@ -1089,75 +1807,370 @@ done: if(H5AC_reset_ring(dxpl, orig_ring) < 0) HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG */ FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) -} /* end H5MF_get_freespace() */ +} /* H5MF_try_close() */ /*------------------------------------------------------------------------- - * Function: H5MF_try_shrink + * Function: H5MF__close_aggrfs * - * Purpose: Try to shrink the size of a file with a block or absorb it - * into a block aggregator. + * Purpose: Close the free space tracker(s) for a file: non-paged aggregation * - * Return: Non-negative on success/Negative on failure + * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol - * koziol@hdfgroup.org - * Feb 14 2008 + * Tuesday, January 22, 2008 * *------------------------------------------------------------------------- */ -htri_t -H5MF_try_shrink(H5F_t *f, H5FD_mem_t alloc_type, hid_t dxpl_id, haddr_t addr, - hsize_t size) +static herr_t +H5MF__close_aggrfs(H5F_t *f, hid_t dxpl_id) { - H5MF_free_section_t *node = NULL; /* Free space section pointer */ - H5MF_sect_ud_t udata; /* User data for callback */ - htri_t ret_value = FAIL; /* Return value */ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ + H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5FD_mem_t type; /* Memory type for iteration */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) #ifdef H5MF_ALLOC_DEBUG -HDfprintf(stderr, "%s: Entering - alloc_type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)alloc_type, addr, size); +HDfprintf(stderr, "%s: Entering\n", FUNC); #endif /* H5MF_ALLOC_DEBUG */ - /* check arguments */ + /* check args */ HDassert(f); HDassert(f->shared); HDassert(f->shared->lf); - HDassert(H5F_addr_defined(addr)); - HDassert(size > 0); + HDassert(f->shared->sblock); - /* Create free space section for block */ - if(NULL == (node = H5MF_sect_simple_new(addr, size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section") + /* Set the ring type in the DXPL. In most cases, we will + * need H5AC_RING_RDFSM, so initialy set the ring in + * the DXPL to that value. We will alter this later if + * needed. + */ + if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + reset_ring = TRUE; + curr_ring = H5AC_RING_RDFSM; - /* Construct user data for callbacks */ - udata.f = f; - udata.dxpl_id = dxpl_id; - udata.alloc_type = alloc_type; - udata.allow_sect_absorb = FALSE; /* Force section to be absorbed into aggregator */ - udata.allow_eoa_shrink_only = FALSE; - - /* Call the "can shrink" callback for the section */ - if((ret_value = H5MF_sect_simple_can_shrink((const H5FS_section_info_t *)node, &udata)) < 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(H5MF_sect_simple_shrink((H5FS_section_info_t **)&node, &udata) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink container") + /* Free the space in aggregators */ + /* (for space not at EOA, it may be put into free space managers) */ + if(H5MF_free_aggrs(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators") + + /* Trying shrinking the EOA for the file */ + if(H5MF__close_shrink_eoa(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa") + + /* Making free-space managers persistent for superblock version >= 2 */ + if(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2 + && f->shared->fs_persist) { + H5O_fsinfo_t fsinfo; /* File space info message */ + haddr_t final_eoa; /* Final eoa -- for sanity check */ + H5F_mem_page_t ptype; /* Memory type for iteration */ + + /* superblock extension and free space manager message should + * exist at this point -- verify at least the former. + */ + HDassert(H5F_addr_defined(f->shared->sblock->ext_addr)); + + /* file space for all non-empty free space managers should be + * allocated at this point, and these free space managers should + * be written to file and thus their headers and section info + * entries in the metadata cache should be clean. + */ + + /* gather data for the free space manager superblock extension message. + * + * In passing, verify that all the free space managers are closed. + */ + for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) + fsinfo.fs_addr[ptype - 1] = HADDR_UNDEF; + for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) + fsinfo.fs_addr[type-1] = f->shared->fs_addr[type]; + fsinfo.strategy = f->shared->fs_strategy; + fsinfo.persist = f->shared->fs_persist; + fsinfo.threshold = f->shared->fs_threshold; + fsinfo.page_size = f->shared->fs_page_size; + fsinfo.pgend_meta_thres = f->shared->pgend_meta_thres; + fsinfo.eoa_pre_fsm_fsalloc = f->shared->eoa_pre_fsm_fsalloc; + + /* Write the free space manager message -- message must already exist */ + if(H5F_super_ext_write_msg(f, dxpl_id, H5O_FSINFO_ID, &fsinfo, FALSE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, "error in writing message to superblock extension") + + /* Close the free space managers */ + for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { + if(f->shared->fs_man[type]) { + /* test to see if we need to switch rings -- do + * so if required + */ + if(H5MF__fsm_type_is_self_referential(f, (H5F_mem_page_t)type)) + needed_ring = H5AC_RING_MDFSM; + else + needed_ring = H5AC_RING_RDFSM; + + if(needed_ring != curr_ring) { + if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)") + curr_ring = needed_ring; + } /* end if */ + + HDassert(f->shared->fs_state[type] == H5F_FS_STATE_OPEN); + + if(H5FS_close(f, dxpl_id, f->shared->fs_man[type]) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close free space manager") + f->shared->fs_man[type] = NULL; + f->shared->fs_state[type] = H5F_FS_STATE_CLOSED; + } /* end if */ + f->shared->fs_addr[type] = HADDR_UNDEF; + } /* end for */ + + /* verify that we haven't dirtied any metadata cache entries + * from the metadata free space manager ring out. + */ + HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM)); + + /* verify that the aggregators are still shutdown. */ + HDassert(f->shared->sdata_aggr.tot_size == 0); + HDassert(f->shared->sdata_aggr.addr == 0); + HDassert(f->shared->sdata_aggr.size == 0); + + HDassert(f->shared->meta_aggr.tot_size == 0); + HDassert(f->shared->meta_aggr.addr == 0); + HDassert(f->shared->meta_aggr.size == 0); + + /* Trying shrinking the EOA for the file */ + /* (in case any free space is now at the EOA) */ + if(H5MF__close_shrink_eoa(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa") + + /* get the eoa, and verify that it has the expected value */ + if(HADDR_UNDEF == (final_eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)) ) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size") + + /* f->shared->eoa_post_fsm_fsalloc is undefined if there has + * been no file space allocation or deallocation since file + * open. + */ + HDassert((f->shared->first_alloc_dealloc) || (final_eoa == f->shared->eoa_post_fsm_fsalloc)); } /* end if */ + else { /* super_vers can be 0, 1, 2 */ + for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) + if(H5MF__close_delete_fstype(f, dxpl_id, (H5F_mem_page_t)type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space") + } /* end else */ + + /* Free the space in aggregators (again) */ + /* (in case any free space information re-started them) */ + if(H5MF_free_aggrs(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators") + + /* Trying shrinking the EOA for the file */ + /* (in case any free space is now at the EOA) */ + if(H5MF__close_shrink_eoa(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa") done: + /* Reset the ring in the DXPL */ + if(reset_ring) + if(H5AC_reset_ring(dxpl, orig_ring) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") - /* Free section node allocated */ - if(node && H5MF_sect_simple_free((H5FS_section_info_t *)node) < 0) - HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node") +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG */ + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5MF__close_aggrfs() */ + +/*------------------------------------------------------------------------- + * Function: H5MF__close_pagefs + * + * Purpose: Close the free space tracker(s) for a file: paged aggregation + * + * Return: SUCCEED/FAIL + * + * Programmer: Vailin Choi; Dec 2012 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5MF__close_pagefs(H5F_t *f, hid_t dxpl_id) +{ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t curr_ring = H5AC_RING_INV; /* current ring value */ + H5AC_ring_t needed_ring = H5AC_RING_INV; /* ring value needed for this + * iteration. + */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5F_mem_page_t ptype; /* Memory type for iteration */ + H5O_fsinfo_t fsinfo; /* File space info message */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) #ifdef H5MF_ALLOC_DEBUG -HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value); +HDfprintf(stderr, "%s: Entering\n", FUNC); #endif /* H5MF_ALLOC_DEBUG */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5MF_try_shrink() */ + + /* check args */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->lf); + HDassert(f->shared->sblock); + HDassert(f->shared->fs_page_size); + HDassert(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2); + + /* Set the ring type in the DXPL. In most cases, we will + * need H5AC_RING_RDFSM, so initialy set the ring in + * the DXPL to that value. We will alter this later if + * needed. + */ + if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + reset_ring = TRUE; + curr_ring = H5AC_RING_RDFSM; + + /* Trying shrinking the EOA for the file */ + if(H5MF__close_shrink_eoa(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa") + + /* Set up file space info message */ + fsinfo.strategy = f->shared->fs_strategy; + fsinfo.persist = f->shared->fs_persist; + fsinfo.threshold = f->shared->fs_threshold; + fsinfo.page_size = f->shared->fs_page_size; + fsinfo.pgend_meta_thres = f->shared->pgend_meta_thres; + fsinfo.eoa_pre_fsm_fsalloc = HADDR_UNDEF; + for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) + fsinfo.fs_addr[ptype - 1] = HADDR_UNDEF; + + if(f->shared->fs_persist) { + haddr_t final_eoa; /* final eoa -- for sanity check */ + + /* superblock extension and free space manager message should + * exist at this point -- verify at least the former. + */ + HDassert(H5F_addr_defined(f->shared->sblock->ext_addr)); + + /* file space for all non-empty free space managers should be + * allocated at this point, and these free space managers should + * be written to file and thus their headers and section info + * entries in the metadata cache should be clean. + */ + + /* gather data for the free space manager superblock extension message. + * Only need addresses of FSMs and eoa prior to allocation of + * file space for the self referential free space managers. Other + * data was gathered above. + */ + for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) + fsinfo.fs_addr[ptype-1] = f->shared->fs_addr[ptype]; + fsinfo.eoa_pre_fsm_fsalloc = f->shared->eoa_pre_fsm_fsalloc; + + /* Write the free space manager message -- message must already exist */ + if(H5F_super_ext_write_msg(f, dxpl_id, H5O_FSINFO_ID, &fsinfo, FALSE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, "error in writing message to superblock extension") + + /* Close the free space managers */ + /* use H5MF__close_fstype() for this? */ + for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) { + if(f->shared->fs_man[ptype]) { + /* test to see if we need to switch rings -- do + * so if required + */ + if(H5MF__fsm_type_is_self_referential(f, ptype)) + needed_ring = H5AC_RING_MDFSM; + else + needed_ring = H5AC_RING_RDFSM; + + if(needed_ring != curr_ring) { + if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)") + curr_ring = needed_ring; + } /* end if */ + + HDassert(f->shared->fs_state[ptype] == H5F_FS_STATE_OPEN); + + if(H5FS_close(f, dxpl_id, f->shared->fs_man[ptype]) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close free space manager") + f->shared->fs_man[ptype] = NULL; + f->shared->fs_state[ptype] = H5F_FS_STATE_CLOSED; + } /* end if */ + f->shared->fs_addr[ptype] = HADDR_UNDEF; + } /* end for */ + + /* verify that we haven't dirtied any metadata cache entries + * from the metadata free space manager ring out. + */ + HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM)); + + /* Trying shrinking the EOA for the file */ + /* (in case any free space is now at the EOA) */ + if(H5MF__close_shrink_eoa(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa") + + /* get the eoa, and verify that it has the expected value */ + if(HADDR_UNDEF == (final_eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT)) ) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size") + + /* f->shared->eoa_post_fsm_fsalloc is undefined if there has + * been no file space allocation or deallocation since file + * open. + * + * If there is a cache image in the file at file open, + * f->shared->first_alloc_dealloc will always be FALSE unless + * the file is opened R/O, as otherwise, the image will have been + * read and discarded by this point. + * + * If a cache image was created on file close, the actual EOA + * should be in f->shared->eoa_post_mdci_fsalloc. Note that in + * this case, it is conceivable that f->shared->first_alloc_dealloc + * will still be TRUE, as the cache image is allocated directly from + * the file driver layer. However, as this possibility seems remote, + * it is ignored in the following assert. + */ + HDassert((f->shared->first_alloc_dealloc) || + (final_eoa == f->shared->eoa_post_fsm_fsalloc) || + ((H5F_addr_defined(f->shared->eoa_post_mdci_fsalloc)) && + (final_eoa == f->shared->eoa_post_mdci_fsalloc))); + } /* end if */ + else { + /* Iterate over all the free space types that have managers + * and get each free list's space + */ + for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) + if(H5MF__close_delete_fstype(f, dxpl_id, ptype) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager") + + /* Write file space info message to superblock extension object header */ + /* Create the superblock extension object header in advance if needed */ + if(H5F_super_ext_write_msg(f, dxpl_id, H5O_FSINFO_ID, &fsinfo, FALSE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, "error in writing message to superblock extension") + } /* end else */ + + /* Trying shrinking the EOA for the file */ + /* (in case any free space is now at the EOA) */ + if(H5MF__close_shrink_eoa(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa") + +done: + /* Reset the ring in the DXPL */ + if(reset_ring) + if(H5AC_reset_ring(dxpl, orig_ring) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") + +#ifdef H5MF_ALLOC_DEBUG +HDfprintf(stderr, "%s: Leaving\n", FUNC); +#endif /* H5MF_ALLOC_DEBUG */ + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5MF__close_pagefs() */ /*------------------------------------------------------------------------- @@ -1175,17 +2188,16 @@ HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value); static herr_t H5MF__close_shrink_eoa(H5F_t *f, hid_t dxpl_id) { - H5FD_mem_t type; /* Memory type for iteration */ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ + H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ - H5AC_ring_t curr_ring = H5AC_RING_INV; /* current ring value */ - H5AC_ring_t needed_ring = H5AC_RING_INV; /* ring value needed for this - * iteration. - */ + H5F_mem_t type; + H5F_mem_page_t ptype; /* Memory type for iteration */ hbool_t eoa_shrank; /* Whether an EOA shrink occurs */ - hbool_t reset_ring = FALSE; /* Whether the ring was set */ htri_t status; /* Status value */ H5MF_sect_ud_t udata; /* User data for callback */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) @@ -1197,13 +2209,10 @@ H5MF__close_shrink_eoa(H5F_t *f, hid_t dxpl_id) /* Construct user data for callbacks */ udata.f = f; udata.dxpl_id = dxpl_id; - udata.allow_sect_absorb = FALSE; - udata.allow_eoa_shrink_only = TRUE; + udata.allow_sect_absorb = FALSE; + udata.allow_eoa_shrink_only = TRUE; - /* Set the ring type in the DXPL. In most cases, we will - * need H5AC_RING_RDFSM, so initialy set the ring type in - * the DXPL to that value. We will alter this later if needed. - */ + /* Set the ring type in the DXPL */ if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value(1)") reset_ring = TRUE; @@ -1213,36 +2222,62 @@ H5MF__close_shrink_eoa(H5F_t *f, hid_t dxpl_id) do { eoa_shrank = FALSE; - /* Check the last section of each free-space manager */ - for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { + if(H5F_PAGED_AGGR(f)) { + /* Check the last section of each free-space manager */ + for(ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, ptype)) { + if(f->shared->fs_man[ptype]) { + /* Test to see if we need to switch rings -- do so if required */ + if(H5MF__fsm_type_is_self_referential(f, ptype)) + needed_ring = H5AC_RING_MDFSM; + else + needed_ring = H5AC_RING_RDFSM; - /* test to see if we need to switch rings -- do so if required */ - if((H5MF_ALLOC_TO_FS_TYPE(f, type) == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (H5MF_ALLOC_TO_FS_TYPE(f, type) == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) - needed_ring = H5AC_RING_MDFSM; - else - needed_ring = H5AC_RING_RDFSM; + if(needed_ring != curr_ring) { + if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)") + curr_ring = needed_ring; + } /* end if */ - if(needed_ring != curr_ring) { - if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (2)") - curr_ring = needed_ring; - } /* end if */ + udata.alloc_type = (H5FD_mem_t)((H5FD_mem_t)ptype < H5FD_MEM_NTYPES ? ptype : ((ptype % H5FD_MEM_NTYPES) + 1)); - if(f->shared->fs_man[type]) { - udata.alloc_type = type; - if((status = H5FS_sect_try_shrink_eoa(f, dxpl_id, f->shared->fs_man[type], &udata)) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa") - else if(status > 0) - eoa_shrank = TRUE; - } /* end if */ - } /* end for */ + if((status = H5FS_sect_try_shrink_eoa(f, dxpl_id, f->shared->fs_man[ptype], &udata)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa") + else if(status > 0) + eoa_shrank = TRUE; + } /* end if */ + } /* end for */ + } /* end if */ + else { + /* Check the last section of each free-space manager */ + for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { + if(f->shared->fs_man[type]) { + /* Test to see if we need to switch rings -- do so if required */ + if(H5MF__fsm_type_is_self_referential(f, (H5F_mem_page_t)type)) + needed_ring = H5AC_RING_MDFSM; + else + needed_ring = H5AC_RING_RDFSM; + + if(needed_ring != curr_ring) { + if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)") + curr_ring = needed_ring; + } /* end if */ + + udata.alloc_type = type; - /* check the two aggregators */ - if((status = H5MF_aggrs_try_shrink_eoa(f, dxpl_id)) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa") - else if(status > 0) - eoa_shrank = TRUE; + if((status = H5FS_sect_try_shrink_eoa(f, dxpl_id, f->shared->fs_man[type], &udata)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa") + else if(status > 0) + eoa_shrank = TRUE; + } /* end if */ + } /* end for */ + + /* check the two aggregators */ + if((status = H5MF_aggrs_try_shrink_eoa(f, dxpl_id)) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa") + else if(status > 0) + eoa_shrank = TRUE; + } /* end else */ } while(eoa_shrank); done: @@ -1256,6 +2291,370 @@ done: /*------------------------------------------------------------------------- + * Function: H5MF_get_freespace + * + * Purpose: Retrieve the amount of free space in the file + * + * Return: Success: Amount of free space in file + * Failure: Negative + * + * Programmer: Quincey Koziol + * Monday, October 6, 2003 + * + *------------------------------------------------------------------------- + */ +herr_t +H5MF_get_freespace(H5F_t *f, hid_t dxpl_id, hsize_t *tot_space, hsize_t *meta_size) +{ + 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" */ + hsize_t tot_fs_size = 0; /* Amount of all free space managed */ + hsize_t tot_meta_size = 0; /* Amount of metadata for free space managers */ + H5FD_mem_t tt; /* Memory type for iteration */ + H5F_mem_page_t type; /* Memory type for iteration */ + H5F_mem_page_t start_type; /* Memory type for iteration */ + H5F_mem_page_t end_type; /* Memory type for iteration */ + htri_t fs_started[H5F_MEM_PAGE_NTYPES]; /* Indicate whether the free-space manager has been started */ + haddr_t fs_eoa[H5FD_MEM_NTYPES]; /* EAO for each free-space manager */ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ + H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) + + /* check args */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->lf); + + /* Set the ring type in the DXPL. In most cases, we will + * need H5AC_RING_RDFSM, so initialy set the ring in + * the DXPL to that value. We will alter this later if + * needed. + */ + if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + reset_ring = TRUE; + curr_ring = H5AC_RING_RDFSM; + + /* Determine start/end points for loop */ + if(H5F_PAGED_AGGR(f)) { + start_type = H5F_MEM_PAGE_META; + end_type = H5F_MEM_PAGE_NTYPES; + } /* end if */ + else { + start_type = (H5F_mem_page_t)H5FD_MEM_SUPER; + end_type = (H5F_mem_page_t)H5FD_MEM_NTYPES; + } /* end else */ + + for(tt = H5FD_MEM_SUPER; tt < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, tt)) + if(HADDR_UNDEF == (fs_eoa[tt] = H5F_get_eoa(f, tt))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed") + + if(!H5F_PAGED_AGGR(f)) { + /* Retrieve metadata aggregator info, if available */ + if(H5MF_aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query metadata aggregator stats") + + /* Retrieve 'small data' aggregator info, if available */ + if(H5MF_aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query small data aggregator stats") + } /* end if */ + + /* Iterate over all the free space types that have managers and get each free list's space */ + for(type = start_type; type < end_type; H5_INC_ENUM(H5F_mem_page_t, type)) { + fs_started[type] = FALSE; + + /* Check if the free space for the file has been initialized */ + if(!f->shared->fs_man[type] && H5F_addr_defined(f->shared->fs_addr[type])) { + if(H5MF_open_fstype(f, dxpl_id, type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space") + HDassert(f->shared->fs_man[type]); + fs_started[type] = TRUE; + } /* end if */ + + /* test to see if we need to switch rings -- do + * so if required + */ + if(H5MF__fsm_type_is_self_referential(f, (H5F_mem_page_t)type)) + needed_ring = H5AC_RING_MDFSM; + else + needed_ring = H5AC_RING_RDFSM; + + if(needed_ring != curr_ring) { + if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + curr_ring = needed_ring; + } /* end if */ + + /* Check if there's free space of this type */ + if(f->shared->fs_man[type]) { + hsize_t type_fs_size = 0; /* Amount of free space managed for each type */ + hsize_t type_meta_size = 0; /* Amount of free space metadata for each type */ + + /* Retrieve free space size from free space manager */ + if(H5FS_sect_stats(f->shared->fs_man[type], &type_fs_size, NULL) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats") + if(H5FS_size(f, f->shared->fs_man[type], &type_meta_size) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space metadata stats") + + /* Increment total free space for types */ + tot_fs_size += type_fs_size; + tot_meta_size += type_meta_size; + } /* end if */ + } /* end for */ + + /* Close the free-space managers if they were opened earlier in this routine */ + for(type = start_type; type < end_type; H5_INC_ENUM(H5F_mem_page_t, type)) { + /* Test to see if we need to switch rings -- do so if required */ + if(H5MF__fsm_type_is_self_referential(f, (H5F_mem_page_t)type)) + needed_ring = H5AC_RING_MDFSM; + else + needed_ring = H5AC_RING_RDFSM; + + if(needed_ring != curr_ring) { + if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + curr_ring = needed_ring; + } /* end if */ + + if(fs_started[type]) + if(H5MF__close_fstype(f, dxpl_id, type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't close file free space") + } /* end for */ + + /* Set the value(s) to return */ + /* (The metadata & small data aggregators count as free space now, since they aren't at EOA) */ + if(tot_space) + *tot_space = tot_fs_size + ma_size + sda_size; + if(meta_size) + *meta_size = tot_meta_size; + +done: + /* Reset the ring in the DXPL */ + if(reset_ring) + if(H5AC_reset_ring(dxpl, orig_ring) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") + + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5MF_get_freespace() */ + + +/*------------------------------------------------------------------------- + * Function: H5MF_get_free_sections() + * + * Purpose: To retrieve free-space section information for + * paged or non-paged aggregation + * + * Return: SUCCEED/FAIL + * + * Programmer: Vailin Choi; Dec 2012 + * + *------------------------------------------------------------------------- + */ +ssize_t +H5MF_get_free_sections(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, size_t nsects, H5F_sect_info_t *sect_info) +{ + H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ + H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ + H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + size_t total_sects = 0; /* Total number of sections */ + H5MF_sect_iter_ud_t sect_udata; /* User data for callback */ + H5F_mem_page_t start_type, end_type; /* Memory types to iterate over */ + H5F_mem_page_t ty; /* Memory type for iteration */ + hbool_t reset_ring = FALSE; /* Whether the ring was set */ + ssize_t ret_value = -1; /* Return value */ + + FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, -1) + + /* check args */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->lf); + + /* H5MF_tidy_self_referential_fsm_hack() will fail if any self + * referential FSM is opened prior to the call to it. Thus call + * it here if necessary and if it hasn't been called already. + * + * The situation is further complicated if a cache image exists + * and had not yet been loaded into the metadata cache. In this + * case, call H5AC_force_cache_image_load() instead of + * H5MF_tidy_self_referential_fsm_hack(). H5AC_force_cache_image_load() + * will load the cache image, and then call + * H5MF_tidy_self_referential_fsm_hack() to discard the cache image + * block. + */ + if(f->shared->first_alloc_dealloc) { + if(H5AC_cache_image_pending(f)) { + if(H5AC_force_cache_image_load(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "forced cache image load failed") + } /* end if */ + else { + if(H5MF_tidy_self_referential_fsm_hack(f, dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "tidy of self referential fsm hack failed") + } /* end else */ + } /* end if */ + + if(type == H5FD_MEM_DEFAULT) { + start_type = H5F_MEM_PAGE_SUPER; + end_type = H5F_MEM_PAGE_NTYPES; + } /* end if */ + else { + start_type = end_type = (H5F_mem_page_t)type; + if(H5F_PAGED_AGGR(f)) /* set to the corresponding LARGE free-space manager */ + end_type = (H5F_mem_page_t)(end_type + H5FD_MEM_NTYPES); + else + H5_INC_ENUM(H5F_mem_page_t, end_type); + } /* end else */ + + /* Set up user data for section iteration */ + sect_udata.sects = sect_info; + sect_udata.sect_count = nsects; + sect_udata.sect_idx = 0; + + /* Set the ring type in the DXPL. In most cases, we will + * need H5AC_RING_RDFSM, so initialy set the ring in + * the DXPL to that value. We will alter this later if + * needed. + */ + if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value(0)") + reset_ring = TRUE; + curr_ring = H5AC_RING_RDFSM; + + /* Iterate over memory types, retrieving the number of sections of each type */ + for(ty = start_type; ty < end_type; H5_INC_ENUM(H5F_mem_page_t, ty)) { + hbool_t fs_started = FALSE; /* The free-space manager is opened or not */ + size_t nums = 0; /* The number of free-space sections */ + + /* Test to see if we need to switch rings -- do so if required */ + if(H5MF__fsm_type_is_self_referential(f, ty)) + needed_ring = H5AC_RING_MDFSM; + else + needed_ring = H5AC_RING_RDFSM; + + if(needed_ring != curr_ring) { + if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (1)") + curr_ring = needed_ring; + } /* end if */ + + if(!f->shared->fs_man[ty] && H5F_addr_defined(f->shared->fs_addr[ty])) { + if(H5MF_open_fstype(f, dxpl_id, ty) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't open the free space manager") + HDassert(f->shared->fs_man[ty]); + fs_started = TRUE; + } /* end if */ + + /* Check if there's free space sections of this type */ + if(f->shared->fs_man[ty]) + if(H5MF__get_free_sects(f, dxpl_id, f->shared->fs_man[ty], §_udata, &nums) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get section info for the free space manager") + + /* Increment total # of sections */ + total_sects += nums; + + /* Close the free space manager of this type, if we started it here */ + if(fs_started) + if(H5MF__close_fstype(f, dxpl_id, ty) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCLOSEOBJ, FAIL, "can't close file free space") + if((H5F_PAGED_AGGR(f)) && (type != H5FD_MEM_DEFAULT)) + ty = (H5F_mem_page_t)(ty + H5FD_MEM_NTYPES - 2); + } /* end for */ + + /* Set return value */ + ret_value = (ssize_t)total_sects; + +done: + /* Reset the ring in the DXPL */ + if(reset_ring) + if(H5AC_reset_ring(dxpl, orig_ring) < 0) + HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") + + FUNC_LEAVE_NOAPI_TAG(ret_value, -1) +} /* H5MF_get_free_sections() */ + + +/*------------------------------------------------------------------------- + * Function: H5MF_sects_cb() + * + * Purpose: Iterator callback for each free-space section + * Retrieve address and size into user data + * + * Return: Always succeed + * + * Programmer: Vailin Choi + * July 1st, 2009 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5MF_sects_cb(H5FS_section_info_t *_sect, void *_udata) +{ + H5MF_free_section_t *sect = (H5MF_free_section_t *)_sect; + H5MF_sect_iter_ud_t *udata = (H5MF_sect_iter_ud_t *)_udata; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + if(udata->sect_idx < udata->sect_count) { + udata->sects[udata->sect_idx].addr = sect->sect_info.addr; + udata->sects[udata->sect_idx].size = sect->sect_info.size; + udata->sect_idx++; + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5MF_sects_cb() */ + + +/*------------------------------------------------------------------------- + * Function: H5MF__get_free_sects + * + * Purpose: Retrieve section information for the specified free-space manager. + * + * Return: Success: non-negative + * Failure: negative + * + * Programmer: Vailin Choi; Dec 2012 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5MF__get_free_sects(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, H5MF_sect_iter_ud_t *sect_udata, size_t *nums) +{ + hsize_t hnums = 0; /* # of sections */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* check args */ + HDassert(f); + HDassert(sect_udata); + HDassert(nums); + HDassert(fspace); + + /* Query how many sections of this type */ + if(H5FS_sect_stats(fspace, NULL, &hnums) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats") + H5_CHECKED_ASSIGN(*nums, size_t, hnums, hsize_t); + + /* Check if we should retrieve the section info */ + if(sect_udata->sects && *nums > 0) + /* Iterate over all the free space sections of this type, adding them to the user's section info */ + if(H5FS_sect_iterate(f, dxpl_id, fspace, H5MF_sects_cb, sect_udata) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_BADITER, FAIL, "can't iterate over sections") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5MF__get_free_sects() */ + + +/*------------------------------------------------------------------------- * Function: H5MF_settle_raw_data_fsm() * * Purpose: Handle any tasks required before the metadata cache @@ -1263,19 +2662,48 @@ done: * and any metadata free space managers that reside in the * raw data free space manager ring. * - * Specifically, any metadata managers that DON'T handle - * space allocation for free space manager header or section - * info will reside in the raw data free space manager ring. - * As of this writing, the plan is to move to only two free space - * managers, one for raw data and one for metadata -- which - * means that only the raw data free space manager will reside - * in the free space manager ring. However, this has not been - * fully implemented yet, so this code must support the - * possibilty of multiple metadata free space managers, at most - * two of which handle free space manager header or section info, - * and thus reside in the metadata free space manager ring. - * - * At present, the task list is: + * Specifically, this means any metadata managers that DON'T + * handle space allocation for free space manager header or + * section info will reside in the raw data free space manager + * ring. + * + * In the absence of page allocation, there is at most one + * free space manager per memory type defined in H5F_mem_t. + * Of these, the one that allocates H5FD_MEM_DRAW will + * always reside in the raw data free space manager ring. + * If there is more than one metadata free space manager, + * all that don't handle H5FD_MEM_FSPACE_HDR or + * H5FD_MEM_FSPACE_SINFO (which map to H5FD_MEM_OHDR and + * H5FD_MEM_LHEAP respectively) will reside in the raw + * data free space manager ring as well + * + * With page allocation, the situation is conceptually + * identical, but more complex in practice. + * + * In the worst case (multi file driver) page allocation + * can result in two free space managers for each memory + * type -- one for small (less than on equal to one page) + * allocations, and one for large (greater than one page) + * allocations. + * + * In the more common one file case, page allocation will + * result in a total of three free space managers -- one for + * small (<= one page) raw data allocations, one for small + * metadata allocations (i.e, all memory types other than + * H5FD_MEM_DRAW), and one for all large (> one page) + * allocations. + * + * Despite these complications, the solution is the same in + * the page allocation case -- free space managers (be they + * small data or large) are assigned to the raw data free + * space manager ring if they don't allocate file space for + * free space managers. Note that in the one file case, the + * large free space manager must be assigned to the metadata + * free space manager ring, as it both allocates pages for + * the metadata free space manager, and allocates space for + * large (> 1 page) metadata cache entries. + * + * At present, the task list for this routine is: * * 1) Reduce the EOA to the extent possible. To do this: * @@ -1330,26 +2758,43 @@ done: herr_t H5MF_settle_raw_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled) { + int pass_count; + hsize_t alloc_size; + H5F_mem_t mem_type; /* Memory type for iteration */ + H5F_mem_page_t fsm_type; /* FSM type for iteration */ + H5O_fsinfo_t fsinfo; /* Free space manager info message */ + H5FS_stat_t fs_stat; /* Information for free-space manager */ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ + H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration */ hbool_t reset_ring = FALSE; /* Whether the ring was set */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) - /* check args */ + /* Check args */ HDassert(f); HDassert(f->shared); HDassert(fsm_settled); - /* Only need to settle things if we are persisting the free space info */ - if(f->shared->fs_strategy == H5F_FILE_SPACE_ALL_PERSIST) { - H5O_fsinfo_t fsinfo; /* Free space manager info message */ - H5FD_mem_t type; /* Memory type for iteration */ - H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ - H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration */ - hbool_t fsm_opened[H5FD_MEM_NTYPES]; /* State of FSM */ - hbool_t fsm_visited[H5FD_MEM_NTYPES]; /* State of FSM */ + /* Only need to settle things if we are persisting the free space info + * and allocation/deallocation has occurred. + */ + if(f->shared->fs_persist && !f->shared->first_alloc_dealloc) { + hbool_t fsm_opened[H5F_MEM_PAGE_NTYPES]; /* State of FSM */ + hbool_t fsm_visited[H5F_MEM_PAGE_NTYPES]; /* State of FSM */ + + /* Sanity check */ + HDassert(f->shared->sblock); + + /* should only be called if file is opened R/W */ + HDassert(H5F_INTENT(f) & H5F_ACC_RDWR); + + /* shouldn't be called unless we have a superblock supporting the + * superblock extension. + */ + HDassert(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2); /* Initialize fsm_opened and fsm_visited */ HDmemset(fsm_opened, 0, sizeof(fsm_opened)); @@ -1366,8 +2811,12 @@ H5MF_settle_raw_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled) * * Note that while the raw data aggregator should not be restarted during * the close process, this need not be the case for the metadata aggregator. + * + * Note also that the aggregators will not exist if page aggregation + * is enabled -- skip this if so. */ - if(H5MF_free_aggrs(f, dxpl_id) < 0) + /* Vailin -- is this correct? */ + if(!H5F_PAGED_AGGR(f) && (H5MF_free_aggrs(f, dxpl_id) < 0)) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free aggregators") /* Set the ring type in the DXPL. In most cases, we will @@ -1389,7 +2838,7 @@ H5MF_settle_raw_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled) * In the case of the raw data free space manager, and any other free * space manager that does not allocate space for free space managers, * allocations should be complete at this point, as all raw data should - * have space allocated and be flushed to file at this point. Thus we + * have space allocated and be flushed to file by now. Thus we * can examine such free space managers and only re-allocate space for * them if they contain free space. Do this later in this function after * the EOA has been reduced to the extent possible. @@ -1400,79 +2849,100 @@ H5MF_settle_raw_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled) * are possible), the matter is more ticklish due to the self- * referential nature of the problem. These FSMs are dealt with in * H5MF_settle_meta_data_fsm(). + * + * Since paged allocation may be enabled, there may be up to two + * free space managers per memory type -- one for small and one for + * large allocation. Hence we must loop over the memory types twice + * setting the allocation size accordingly if paged allocation is + * enabled. */ - for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { - H5FS_stat_t fs_stat; /* Information for free-space manager */ - H5FD_mem_t fsm_type; /* File memory type for FSM */ - - /* There is potentially a many-to-one mapping from memory types to - * free space managers. Use the fsm_visited[] array to avoid visiting - * a given FSM more than once. Use fsm_opened[] to track which FSMs - * must be closed at the end of this function. - */ - fsm_type = H5MF_ALLOC_TO_FS_TYPE(f, type); - if(!fsm_visited[fsm_type]) { - fsm_visited[fsm_type] = TRUE; - - /* If there is no active FSM for this type, but such a FSM has - * space allocated in file, open it so that we can free its file - * space. - */ - if(NULL == f->shared->fs_man[fsm_type]) { - if(H5F_addr_defined(f->shared->fs_addr[fsm_type])) { - /* Sanity check */ - HDassert(fsm_opened[fsm_type] == FALSE); - - /* Start up FSM for the file memory type */ - if(H5MF__alloc_open(f, dxpl_id, fsm_type) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager") - fsm_opened[fsm_type] = TRUE; - } /* end if */ + for(pass_count = 0; pass_count <= 1; pass_count++) { + if(pass_count == 0) + alloc_size = 1; + else if ( H5F_PAGED_AGGR(f) ) + alloc_size = f->shared->fs_page_size + 1; + else /* no need for a second pass */ + break; + + for(mem_type = H5FD_MEM_SUPER; mem_type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5F_mem_t, mem_type)) { + H5MF_alloc_to_fs_type(f, mem_type, alloc_size, &fsm_type); + + if(pass_count == 0) { /* this is the first pass */ + HDassert(fsm_type > H5F_MEM_PAGE_DEFAULT); + HDassert(fsm_type < H5F_MEM_PAGE_LARGE_SUPER); } /* end if */ + else if(H5F_PAGED_AGGR(f)) { /* page alloc active */ + HDassert(fsm_type >= H5F_MEM_PAGE_LARGE_SUPER); + HDassert(fsm_type < H5F_MEM_PAGE_NTYPES); + } /* end else-if */ + else /* paged allocation disabled -- should be unreachable */ + HDassert(FALSE); + + if(!fsm_visited[fsm_type]) { + fsm_visited[fsm_type] = TRUE; + + /* If there is no active FSM for this type, but such a FSM has + * space allocated in file, open it so that we can free its file + * space. + */ + if(NULL == f->shared->fs_man[fsm_type]) { + if(H5F_addr_defined(f->shared->fs_addr[fsm_type])) { + /* Sanity check */ + HDassert(fsm_opened[fsm_type] == FALSE); - /* Check for an actual FSM for this type now */ - /* (Possibly opened in previous step) */ - if(f->shared->fs_man[fsm_type]) { - /* Test to see if we need to switch rings -- do so if required */ - if((fsm_type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (fsm_type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) - needed_ring = H5AC_RING_MDFSM; - else - needed_ring = H5AC_RING_RDFSM; - if(needed_ring != curr_ring) { - if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") - curr_ring = needed_ring; + if(H5MF_open_fstype(f, dxpl_id, fsm_type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager") + fsm_opened[fsm_type] = TRUE; + } /* end if */ } /* end if */ - /* Query free space manager info for this type */ - if(H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info") + if(f->shared->fs_man[fsm_type]) { + /* Test to see if we need to switch rings -- do so if required */ + if(H5MF__fsm_type_is_self_referential(f, fsm_type)) + needed_ring = H5AC_RING_MDFSM; + else + needed_ring = H5AC_RING_RDFSM; + + if(needed_ring != curr_ring) { + if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + curr_ring = needed_ring; + } /* end if */ - /* Check if the free space manager has space in the file */ - if(H5F_addr_defined(fs_stat.addr) || H5F_addr_defined(fs_stat.sect_addr)) { - /* Delete the free space manager in the file. Will - * reallocate later if the free space manager contains - * any free space. - */ - if(H5FS_free(f, f->shared->fs_man[fsm_type], dxpl_id) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free-space headers") - f->shared->fs_addr[fsm_type] = HADDR_UNDEF; + /* Query free space manager info for this type */ + if(H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info") + + /* Check if the free space manager has space in the file */ + if(H5F_addr_defined(fs_stat.addr) || H5F_addr_defined(fs_stat.sect_addr)) { + /* Delete the free space manager in the file. Will + * reallocate later if the free space manager contains + * any free space. + */ + if(H5FS_free(f, f->shared->fs_man[fsm_type], dxpl_id, TRUE) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free-space headers") + f->shared->fs_addr[fsm_type] = HADDR_UNDEF; + } /* end if */ } /* end if */ - } /* end if */ - /* note that we are tracking opened FSM -- we will close them - * at the end of the function. - */ - } /* end if */ + /* note that we are tracking opened FSM -- we will close them + * at the end of the function. + */ + } /* end if */ + } /* end for */ } /* end for */ + /* c) Delete the free space manager superblock extension message * if allocated. * * Must do this since the routine that writes / creates superblock * extension messages will choke if the target message is * unexpectedly either absent or present. + * + * Update: This is probably unecessary, as I gather that the + * file space manager info message is guaranteed to exist. + * Leave it in for now, but consider removing it. */ if(H5F_addr_defined(f->shared->sblock->ext_addr)) if(H5F_super_ext_remove_msg(f, dxpl_id, H5O_FSINFO_ID) < 0) @@ -1496,11 +2966,16 @@ H5MF_settle_raw_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled) * those addresses are unknown. This is OK -- we will write the correct * values to the message at free space manager shutdown. */ - for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) - fsinfo.fs_addr[type - 1] = HADDR_UNDEF; + for(fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, fsm_type)) + fsinfo.fs_addr[fsm_type - 1] = HADDR_UNDEF; fsinfo.strategy = f->shared->fs_strategy; + fsinfo.persist = f->shared->fs_persist; fsinfo.threshold = f->shared->fs_threshold; - if(H5F_super_ext_write_msg(f, dxpl_id, H5O_FSINFO_ID, &fsinfo, TRUE, H5O_MSG_NO_FLAGS_SET) < 0) + fsinfo.page_size = f->shared->fs_page_size; + fsinfo.pgend_meta_thres = f->shared->pgend_meta_thres; + fsinfo.eoa_pre_fsm_fsalloc = HADDR_UNDEF; + + if(H5F_super_ext_write_msg(f, dxpl_id, H5O_FSINFO_ID, &fsinfo, TRUE, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, "error in writing fsinfo message to superblock extension") @@ -1524,102 +2999,117 @@ H5MF_settle_raw_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled) */ /* Reinitialize fsm_visited */ - HDmemset(fsm_visited, 0, sizeof(fsm_visited)); - - for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { - H5FD_mem_t fsm_type; /* File memory type for FSM */ - - fsm_type = H5MF_ALLOC_TO_FS_TYPE(f, type); - - /* test to see if we need to switch rings -- do so if required */ - if((fsm_type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (fsm_type == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) - needed_ring = H5AC_RING_MDFSM; - else - needed_ring = H5AC_RING_RDFSM; - - if(needed_ring != curr_ring) { - if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring)< 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") - curr_ring = needed_ring; - } /* end if */ - - /* Since there can be a many-to-one mapping from memory types - * to free space managers, ensure that we don't visit any FSM - * more than once. - */ - if(!fsm_visited[fsm_type]) { - fsm_visited[fsm_type] = TRUE; - - if(f->shared->fs_man[fsm_type]) { - /* Only allocate file space if the target free space manager - * doesn't allocate file space for free space managers. Note - * that this is also the deciding factor as to whether a FSM - * in in the raw data FSM ring. - */ - if((fsm_type != H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - && (fsm_type != H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) { - H5FS_stat_t fs_stat; /* Information for free-space manager */ + for(fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, fsm_type)) + fsm_visited[fsm_type] = FALSE; + + for(pass_count = 0; pass_count <= 1; pass_count++) { + if(pass_count == 0) + alloc_size = 1; + else if(H5F_PAGED_AGGR(f)) + alloc_size = f->shared->fs_page_size + 1; + else /* no need for a second pass */ + break; + + for(mem_type = H5FD_MEM_SUPER; mem_type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5F_mem_t, mem_type)) { + H5MF_alloc_to_fs_type(f, mem_type, alloc_size, &fsm_type); + + if(pass_count == 0) { /* this is the first pass */ + HDassert(fsm_type > H5F_MEM_PAGE_DEFAULT); + HDassert(fsm_type < H5F_MEM_PAGE_LARGE_SUPER); + } /* end if */ + else if(H5F_PAGED_AGGR(f)) { /* page alloc active */ + HDassert(fsm_type >= H5F_MEM_PAGE_LARGE_SUPER); + HDassert(fsm_type < H5F_MEM_PAGE_NTYPES); + } /* end else-if */ + else /* paged allocation disabled -- should be unreachable */ + HDassert(FALSE); - /* The current ring should be H5AC_RING_RDFSM */ - HDassert(curr_ring == H5AC_RING_RDFSM); + /* test to see if we need to switch rings -- do so if required */ + if(H5MF__fsm_type_is_self_referential(f, fsm_type)) + needed_ring = H5AC_RING_MDFSM; + else + needed_ring = H5AC_RING_RDFSM; - /* Query free space manager info for this type */ - if(H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0 ) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info") + if(needed_ring != curr_ring) { + if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring)< 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") + curr_ring = needed_ring; + } /* end if */ - /* If the free space manager contains section info, - * allocate space for the header and sinfo (note that - * space must not be allocated at present -- verify - * verify this with assertions). + /* Since there can be a many-to-one mapping from memory types + * to free space managers, ensure that we don't visit any FSM + * more than once. + */ + if(!fsm_visited[fsm_type]) { + fsm_visited[fsm_type] = TRUE; + + if(f->shared->fs_man[fsm_type]) { + /* Only allocate file space if the target free space manager + * doesn't allocate file space for free space managers. Note + * that this is also the deciding factor as to whether a FSM + * in in the raw data FSM ring. */ - if(fs_stat.serial_sect_count > 0) { - /* Sanity check */ - HDassert(!H5F_addr_defined(fs_stat.addr)); - - /* Allocate FSM header */ - if(H5FS_alloc_hdr(f, f->shared->fs_man[fsm_type], &f->shared->fs_addr[fsm_type], dxpl_id) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocated free-space header") - - /* Allocate FSM section info */ - HDassert(!H5F_addr_defined(fs_stat.sect_addr)); - HDassert(fs_stat.alloc_sect_size == 0); - if(H5FS_alloc_sect(f, f->shared->fs_man[fsm_type], dxpl_id) < 0 ) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate free-space section info") + if(!H5MF__fsm_type_is_self_referential(f, fsm_type)) { + /* The current ring should be H5AC_RING_RDFSM */ + HDassert(curr_ring == H5AC_RING_RDFSM); + + /* Query free space manager info for this type */ + if(H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0 ) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info") + + /* If the free space manager contains section info, + * allocate space for the header and sinfo (note that + * space must not be allocated at present -- verify + * verify this with assertions). + */ + if(fs_stat.serial_sect_count > 0) { + /* Sanity check */ + HDassert(!H5F_addr_defined(fs_stat.addr)); + + /* Allocate FSM header */ + if(H5FS_alloc_hdr(f, f->shared->fs_man[fsm_type], &f->shared->fs_addr[fsm_type], dxpl_id) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocated free-space header") + + /* Allocate FSM section info */ + HDassert(!H5F_addr_defined(fs_stat.sect_addr)); + HDassert(fs_stat.alloc_sect_size == 0); + if(H5FS_alloc_sect(f, f->shared->fs_man[fsm_type], dxpl_id) < 0 ) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate free-space section info") #ifndef NDEBUG - /* Re-Query free space manager info for this type */ - if(H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info") - - HDassert(H5F_addr_defined(fs_stat.addr)); - HDassert(H5F_addr_defined(fs_stat.sect_addr)); - HDassert(fs_stat.serial_sect_count > 0); - HDassert(fs_stat.alloc_sect_size > 0); - HDassert(fs_stat.alloc_sect_size == fs_stat.sect_size); + /* Re-Query free space manager info for this type */ + if(H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info") + + HDassert(H5F_addr_defined(fs_stat.addr)); + HDassert(H5F_addr_defined(fs_stat.sect_addr)); + HDassert(fs_stat.serial_sect_count > 0); + HDassert(fs_stat.alloc_sect_size > 0); + HDassert(fs_stat.alloc_sect_size == fs_stat.sect_size); #endif /* NDEBUG */ + } /* end if */ + else { + HDassert(!H5F_addr_defined(fs_stat.addr)); + HDassert(!H5F_addr_defined(fs_stat.sect_addr)); + HDassert(fs_stat.serial_sect_count == 0); + HDassert(fs_stat.alloc_sect_size == 0); + } /* end else */ } /* end if */ - else { - HDassert(!H5F_addr_defined(fs_stat.addr)); - HDassert(!H5F_addr_defined(fs_stat.sect_addr)); - HDassert(fs_stat.serial_sect_count == 0); - HDassert(fs_stat.alloc_sect_size == 0); - } /* end else */ } /* end if */ - } /* end if */ - /* Close any opened FSMs */ - if(fsm_opened[fsm_type]) { - if(H5MF__alloc_close(f, dxpl_id, fsm_type) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't close file free space manager") - fsm_opened[fsm_type] = FALSE; + /* Close any opened FSMs */ + if(fsm_opened[fsm_type]) { + if(H5MF__close_fstype(f, dxpl_id, fsm_type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't close file free space manager") + fsm_opened[fsm_type] = FALSE; + } /* end if */ } /* end if */ - } /* end if */ + } /* end for */ } /* end for */ /* verify that all opened FSMs were closed */ - for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) - HDassert(!fsm_opened[type]); + for(fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; H5_INC_ENUM(H5F_mem_page_t, fsm_type)) + HDassert(!fsm_opened[fsm_type]); /* Indicate that the FSM was settled successfully */ *fsm_settled = TRUE; @@ -1640,11 +3130,11 @@ done: * * Purpose: If the free space manager is persistent, handle any tasks * required before the metadata cache can serialize or flush - * the metadata free space manager(sI) that handle file space + * the metadata free space manager(s) that handle file space * allocation for free space managers. * * In most cases, there will be only one manager assigned - * to this role. However, since for reason or reason unknown, + * to this role. However, since for reasons unknown, * free space manager headers and section info blocks are * different classes of memory, it is possible that two free * space managers will be involved. @@ -1652,7 +3142,7 @@ done: * On entry to this function, the raw data settle routine * (H5MF_settle_raw_data_fsm()) should have: * - * 1) Freed the accumulators. + * 1) Freed the aggregators. * * 2) Freed all file space allocated to the free space managers. * @@ -1688,9 +3178,12 @@ done: * 1) Verify that the free space manager(s) involved in file * space allocation for free space managers are still floating. * - * 2) Free the accumulators. + * 2) Free the aggregators. * - * 3) Reduce the EOA to the extent possible. + * 3) Reduce the EOA to the extent possible, and make note + * of the resulting value. This value will be stored + * in the fsinfo superblock extension message and be used + * in the subsequent file open. * * 4) Re-allocate space for any free space manager(s) that: * @@ -1724,6 +3217,9 @@ done: * severe time pressure at the moment, the above brute * force solution is attractive. * + * 5) Make note of the EOA -- used for sanity checking on + * FSM shutdown. + * * Return: SUCCEED/FAIL * * Programmer: John Mainzer @@ -1734,10 +3230,23 @@ done: herr_t H5MF_settle_meta_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled) { + H5F_mem_page_t sm_fshdr_fs_type; /* small fs hdr fsm */ + H5F_mem_page_t sm_fssinfo_fs_type; /* small fs sinfo fsm */ + H5F_mem_page_t lg_fshdr_fs_type; /* large fs hdr fsm */ + H5F_mem_page_t lg_fssinfo_fs_type; /* large fs sinfo fsm */ + H5FS_t *sm_hdr_fspace = NULL; /* ptr to sm FSM hdr alloc FSM */ + H5FS_t *sm_sinfo_fspace = NULL; /* ptr to sm FSM sinfo alloc FSM */ + H5FS_t *lg_hdr_fspace = NULL; /* ptr to lg FSM hdr alloc FSM */ + H5FS_t *lg_sinfo_fspace = NULL; /* ptr to lg FSM sinfo alloc FSM */ + haddr_t eoa_pre_fsm_fsalloc; /* eoa pre file space allocation */ + /* for self referential FSMs */ + haddr_t eoa_post_fsm_fsalloc; /* eoa post file space allocation */ + /* for self referential FSMs */ + H5FS_stat_t fs_stat; /* Information for hdr FSM */ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ hbool_t reset_ring = FALSE; /* Whether we set the ring */ - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) @@ -1746,29 +3255,49 @@ H5MF_settle_meta_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled) HDassert(f->shared); HDassert(fsm_settled); - /* Only need to settle things if we are persisting the free space info */ - if(f->shared->fs_strategy == H5F_FILE_SPACE_ALL_PERSIST) { - H5FS_t *hdr_fspace; /* Ptr to FSM hdr alloc FSM */ - H5FS_t *sinfo_fspace; /* Ptr to FSM sinfo alloc FSM */ - H5FS_stat_t fs_stat; /* Information for FSM */ - H5FD_mem_t hdr_fsm_alloc_type; /* FSM hdr alloc type */ - H5FD_mem_t sinfo_fsm_alloc_type; /* FSM info alloc type */ - - /* Get the file memory types for the FSM header & section info */ - hdr_fsm_alloc_type = H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR); - sinfo_fsm_alloc_type = H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO); - - /* Sanity checks */ - HDassert(hdr_fsm_alloc_type > H5FD_MEM_NOLIST); - HDassert(hdr_fsm_alloc_type < H5FD_MEM_NTYPES); - HDassert(sinfo_fsm_alloc_type > H5FD_MEM_NOLIST); - HDassert(sinfo_fsm_alloc_type < H5FD_MEM_NTYPES); - HDassert(!H5F_addr_defined(f->shared->fs_addr[hdr_fsm_alloc_type])); - HDassert(!H5F_addr_defined(f->shared->fs_addr[sinfo_fsm_alloc_type])); - - /* Note that in most cases, hdr_fspace will equal sinfo_fspace. */ - hdr_fspace = f->shared->fs_man[hdr_fsm_alloc_type]; - sinfo_fspace = f->shared->fs_man[sinfo_fsm_alloc_type]; + /* Only need to settle things if we are persisting the free space info + * and allocation/deallocation has occurred. + */ + if(f->shared->fs_persist && !f->shared->first_alloc_dealloc) { + /* Sanity check */ + HDassert(f->shared->lf); + + /* should only be called if file is opened R/W */ + HDassert(H5F_INTENT(f) & H5F_ACC_RDWR); + + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fs_type); + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fs_type); + + HDassert(sm_fshdr_fs_type > H5F_MEM_PAGE_DEFAULT); + HDassert(sm_fshdr_fs_type < H5F_MEM_PAGE_LARGE_SUPER); + + HDassert(sm_fssinfo_fs_type > H5F_MEM_PAGE_DEFAULT); + HDassert(sm_fssinfo_fs_type < H5F_MEM_PAGE_LARGE_SUPER); + + HDassert(!H5F_addr_defined(f->shared->fs_addr[sm_fshdr_fs_type])); + HDassert(!H5F_addr_defined(f->shared->fs_addr[sm_fssinfo_fs_type])); + + /* Note that in most cases, sm_hdr_fspace will equal sm_sinfo_fspace. */ + sm_hdr_fspace = f->shared->fs_man[sm_fshdr_fs_type]; + sm_sinfo_fspace = f->shared->fs_man[sm_fssinfo_fs_type]; + + if(H5F_PAGED_AGGR(f)) { + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, f->shared->fs_page_size + 1, &lg_fshdr_fs_type); + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, f->shared->fs_page_size + 1, &lg_fssinfo_fs_type); + + HDassert(lg_fshdr_fs_type >= H5F_MEM_PAGE_LARGE_SUPER); + HDassert(lg_fshdr_fs_type < H5F_MEM_PAGE_NTYPES); + + HDassert(lg_fssinfo_fs_type >= H5F_MEM_PAGE_LARGE_SUPER); + HDassert(lg_fssinfo_fs_type < H5F_MEM_PAGE_NTYPES); + + HDassert(!H5F_addr_defined(f->shared->fs_addr[lg_fshdr_fs_type])); + HDassert(!H5F_addr_defined(f->shared->fs_addr[lg_fssinfo_fs_type])); + + /* Note that in most cases, lg_hdr_fspace will equal lg_sinfo_fspace. */ + lg_hdr_fspace = f->shared->fs_man[lg_fshdr_fs_type]; + lg_sinfo_fspace = f->shared->fs_man[lg_fssinfo_fs_type]; + } /* end if */ /* Set the ring in the dxpl appropriately for subsequent calls */ if(H5AC_set_ring(dxpl_id, H5AC_RING_MDFSM, &dxpl, &orig_ring) < 0) @@ -1776,41 +3305,109 @@ H5MF_settle_meta_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled) reset_ring = TRUE; #ifndef NDEBUG - /* Verify that hdr_fspace is floating if it exists */ - if(hdr_fspace) { + /* Verify that sm_hdr_fspace is floating if it exists */ + if(sm_hdr_fspace) { /* Query free space manager info for this type */ - if(H5FS_stat_info(f, hdr_fspace, &fs_stat) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info") + if(H5FS_stat_info(f, sm_hdr_fspace, &fs_stat) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info") HDassert(!H5F_addr_defined(fs_stat.addr)); HDassert(!H5F_addr_defined(fs_stat.sect_addr)); HDassert(fs_stat.alloc_sect_size == 0); } /* end if */ - /* Verify that sinfo_fspace is floating if it exists */ - if((sinfo_fspace) && (hdr_fspace != sinfo_fspace)) { + /* Verify that sm_sinfo_fspace is floating if it exists and is distinct */ + if((sm_sinfo_fspace) && (sm_hdr_fspace != sm_sinfo_fspace)) { /* Query free space manager info for this type */ - if(H5FS_stat_info(f, sinfo_fspace, &fs_stat) < 0) + if(H5FS_stat_info(f, sm_sinfo_fspace, &fs_stat) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info") HDassert(!H5F_addr_defined(fs_stat.addr)); HDassert(!H5F_addr_defined(fs_stat.sect_addr)); HDassert(fs_stat.alloc_sect_size == 0); } /* end if */ + + if(H5F_PAGED_AGGR(f)) { + /* Verify that lg_hdr_fspace is floating if it exists */ + if(lg_hdr_fspace) { + /* Query free space manager info for this type */ + if(H5FS_stat_info(f, lg_hdr_fspace, &fs_stat) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info (3)") + + HDassert(!H5F_addr_defined(fs_stat.addr)); + HDassert(!H5F_addr_defined(fs_stat.sect_addr)); + HDassert(fs_stat.alloc_sect_size == 0); + } /* end if */ + + /* Verify that lg_sinfo_fspace is floating if it + * exists and is distinct + */ + if((lg_sinfo_fspace) && (lg_hdr_fspace != lg_sinfo_fspace)) { + /* Query free space manager info for this type */ + if(H5FS_stat_info(f, lg_sinfo_fspace, &fs_stat) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info (4)") + + HDassert(!H5F_addr_defined(fs_stat.addr)); + HDassert(!H5F_addr_defined(fs_stat.sect_addr)); + HDassert(fs_stat.alloc_sect_size == 0); + } /* end if */ + } /* end if */ #endif /* NDEBUG */ /* Free the space in the metadata aggregator. Do this via the * H5MF_free_aggrs() call. Note that the raw data aggregator must * have already been freed. Sanity checks for this? + * + * Note that the aggregators will not exist if paged aggregation + * is enabled -- don't attempt to free if this is the case. */ + /* Vailin -- is this correct? */ /* (for space not at EOF, it may be put into free space managers) */ - if(H5MF_free_aggrs(f, dxpl_id) < 0) + if((!H5F_PAGED_AGGR(f)) && (H5MF_free_aggrs(f, dxpl_id) < 0)) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free aggregators") /* Trying shrinking the EOA for the file */ if(H5MF__close_shrink_eoa(f, dxpl_id) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa") + /* At this point, the EOA should be set to a value that contains + * the allocation for all user data, all non self referential FSMs, + * the superblock and all superblock extension messages. + * + * Make note of the current EOA. We will store this value in the + * free space manager superblock extension message. Since space for + * everything other than the self referential FSMs (and possibly the + * cache image) has been allocated at this point, this allows us to + * to float the self referential FSMs on the first file space allocation / + * deallocaiton and then set the EOA to this value before we handle + * the allocation / deallocation. (If a cache image exists, the + * first allocation / deallocation will be the deallocation of space + * for the cache image). + * + * WARNING: This approach settling the self referential free space + * managers and allocating space for them in the file will + * not work as currently implemented with the split and + * multi file drivers, as the self referential free space + * manager header and section info can be stored in up to + * two different files -- requiring that up to two EOA's + * be stored in the the free space managers super block + * extension message. + * + * As of this writing, we are solving this problem by + * simply not supporting persistant FSMs with the split + * and multi file drivers. + * + * Current plans are to do away with the multi file + * driver, so this should be a non-issue in this case. + * + * We should be able to support the split file driver + * without a file format change. However, the code to + * do so does not exist at present. + */ + if(HADDR_UNDEF == (eoa_pre_fsm_fsalloc = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT))) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get EOA") + + /* ******************* PROBLEM: ******************** * * If the file has an alignement other than 1, and if @@ -1859,15 +3456,39 @@ H5MF_settle_meta_data_fsm(H5F_t *f, hid_t dxpl_id, hbool_t *fsm_settled) * This is isn't good, but due to schedule pressure, we will just drop * the fragment on the floor for now. */ - if(hdr_fspace) - if(H5FS_alloc_vfd_alloc_hdr_and_section_info(f, dxpl_id, hdr_fspace, - &(f->shared->fs_addr[hdr_fsm_alloc_type])) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate hdr FSM file space") + if(sm_hdr_fspace) + if(H5FS_vfd_alloc_hdr_and_section_info_if_needed(f, dxpl_id, sm_hdr_fspace, &(f->shared->fs_addr[sm_fshdr_fs_type])) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate sm hdr FSM file space") + + if(sm_sinfo_fspace && (sm_sinfo_fspace != sm_hdr_fspace)) + if(H5FS_vfd_alloc_hdr_and_section_info_if_needed(f, dxpl_id, sm_sinfo_fspace, &(f->shared->fs_addr[sm_fssinfo_fs_type])) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate sm sinfo FSM file space") + + if(H5F_PAGED_AGGR(f)) { + if(lg_hdr_fspace) + if(H5FS_vfd_alloc_hdr_and_section_info_if_needed(f, dxpl_id, lg_hdr_fspace, &(f->shared->fs_addr[lg_fshdr_fs_type])) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate lg hdr FSM file space") + + if(lg_sinfo_fspace && (lg_sinfo_fspace != lg_hdr_fspace)) + if(H5FS_vfd_alloc_hdr_and_section_info_if_needed(f, dxpl_id, lg_sinfo_fspace, &(f->shared->fs_addr[lg_fssinfo_fs_type])) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate lg sinfo FSM file space") + } /* end if */ - if(sinfo_fspace && (sinfo_fspace != hdr_fspace)) - if(H5FS_alloc_vfd_alloc_hdr_and_section_info(f, dxpl_id, sinfo_fspace, - &(f->shared->fs_addr[sinfo_fsm_alloc_type])) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate sinfo FSM file space") + /* Get the eoa after allocation of file space for the self referential + * free space managers. Assuming no cache image, this should be the + * final EOA of the file. + */ + if(HADDR_UNDEF == (eoa_post_fsm_fsalloc = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT))) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size") + + /* All free space managers should have file space allocated for them + * now, and should see no further allocations / deallocations. Store + * the pre and post file space allocaton for self referential FSMs EOA + * for use when we actually write the free space manager superblock + * extension message. + */ + f->shared->eoa_pre_fsm_fsalloc = eoa_pre_fsm_fsalloc; + f->shared->eoa_post_fsm_fsalloc = eoa_post_fsm_fsalloc; /* Indicate that the FSM was settled successfully */ *fsm_settled = TRUE; @@ -1878,479 +3499,410 @@ done: if(H5AC_reset_ring(dxpl, orig_ring) < 0) HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") - FUNC_LEAVE_NOAPI(ret_value) + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) } /* H5MF_settle_meta_data_fsm() */ /*------------------------------------------------------------------------- - * Function: H5MF__close_delete + * Function: H5MF__fsm_type_is_self_referential() * - * Purpose: Common code for closing and deleting freespace managers from - * the file. + * Purpose: Return TRUE if the indicated free space manager allocates + * file space for free space managers. Return FALSE otherwise. * - * Return: SUCCEED/FAIL + * Return: TRUE/FALSE * - * Programmer: Vailin Choi - * Jan 2016 + * Programmer: John Mainzer + * 12/6/16 * *------------------------------------------------------------------------- */ -static herr_t -H5MF__close_delete(H5F_t *f, hid_t dxpl_id, H5P_genplist_t **dxpl) +hbool_t +H5MF__fsm_type_is_self_referential(H5F_t *f, H5F_mem_page_t fsm_type) { - H5FD_mem_t type; /* Memory type for iteration */ - H5AC_ring_t curr_ring = H5AC_RING_INV; /* current ring value */ - herr_t ret_value = SUCCEED; /* Return value */ + H5F_mem_page_t sm_fshdr_fsm; + H5F_mem_page_t sm_fssinfo_fsm; + H5F_mem_page_t lg_fshdr_fsm; + H5F_mem_page_t lg_fssinfo_fsm; + hbool_t result = FALSE; - FUNC_ENTER_STATIC_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) -#ifdef H5MF_ALLOC_DEBUG -HDfprintf(stderr, "%s: Entering\n", FUNC); -#endif /* H5MF_ALLOC_DEBUG */ + FUNC_ENTER_NOAPI_NOINIT_NOERR - /* check args */ + /* Sanity check */ HDassert(f); HDassert(f->shared); + HDassert(fsm_type >= H5F_MEM_PAGE_DEFAULT); + HDassert(fsm_type < H5F_MEM_PAGE_NTYPES); - /* Iterate over all the free space types that have managers and get each free list's space */ - for(type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { - H5AC_ring_t needed_ring; /* Ring value needed for this iteration */ + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fsm); + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fsm); -#ifdef H5MF_ALLOC_DEBUG_MORE -HDfprintf(stderr, "%s: Check 1.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]); -#endif /* H5MF_ALLOC_DEBUG_MORE */ + if(H5F_PAGED_AGGR(f)) { + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, f->shared->fs_page_size + 1, &lg_fshdr_fsm); + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, f->shared->fs_page_size + 1, &lg_fssinfo_fsm); - /* test to see if we need to switch rings -- do so if required */ - if((H5MF_ALLOC_TO_FS_TYPE(f, type) == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (H5MF_ALLOC_TO_FS_TYPE(f, type) == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) - needed_ring = H5AC_RING_MDFSM; + result = (fsm_type == sm_fshdr_fsm) || (fsm_type == sm_fssinfo_fsm) + || (fsm_type == lg_fshdr_fsm) || (fsm_type == lg_fssinfo_fsm); + } /* end if */ + else { + /* In principle, fsm_type should always be less than + * H5F_MEM_PAGE_LARGE_SUPER whenever paged aggregation + * is not enabled. However, since there is code that does + * not observe this prinicple, force the result to FALSE if + * fsm_type is greater than or equal to H5F_MEM_PAGE_LARGE_SUPER. + */ + if(fsm_type >= H5F_MEM_PAGE_LARGE_SUPER) + result = FALSE; else - needed_ring = H5AC_RING_RDFSM; - - if(needed_ring != curr_ring) { - if(H5AC_set_ring(dxpl_id, needed_ring, dxpl, &curr_ring) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (4)") - curr_ring = needed_ring; - } /* end if */ - - /* If the free space manager for this type is open, close it */ - if(f->shared->fs_man[type]) { -#ifdef H5MF_ALLOC_DEBUG_MORE -HDfprintf(stderr, "%s: Before closing free space manager\n", FUNC); -#endif /* H5MF_ALLOC_DEBUG_MORE */ - if(H5FS_close(f, dxpl_id, f->shared->fs_man[type]) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free space info") - f->shared->fs_man[type] = NULL; - f->shared->fs_state[type] = H5F_FS_STATE_CLOSED; - } /* end if */ -#ifdef H5MF_ALLOC_DEBUG_MORE -HDfprintf(stderr, "%s: Check 2.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %a\n", FUNC, (unsigned)type, f->shared->fs_man[type], (unsigned)type, f->shared->fs_addr[type]); -#endif /* H5MF_ALLOC_DEBUG_MORE */ - - /* If there is free space manager info for this type, delete it */ - if(H5F_addr_defined(f->shared->fs_addr[type])) { - haddr_t tmp_fs_addr; /* Temporary holder for free space manager address */ - - /* Put address into temporary variable and reset it */ - /* (Avoids loopback in file space freeing routine) */ - tmp_fs_addr = f->shared->fs_addr[type]; - f->shared->fs_addr[type] = HADDR_UNDEF; - - /* Shift to "deleting" state, to make certain we don't track any - * file space freed as a result of deleting the free space manager. - */ - f->shared->fs_state[type] = H5F_FS_STATE_DELETING; - -#ifdef H5MF_ALLOC_DEBUG_MORE -HDfprintf(stderr, "%s: Before deleting free space manager\n", FUNC); -#endif /* H5MF_ALLOC_DEBUG_MORE */ - - /* Delete free space manager for this type */ - if(H5FS_delete(f, dxpl_id, tmp_fs_addr) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't delete free space manager") - - /* Shift [back] to closed state */ - HDassert(f->shared->fs_state[type] == H5F_FS_STATE_DELETING); - f->shared->fs_state[type] = H5F_FS_STATE_CLOSED; - - /* Sanity check that the free space manager for this type wasn't started up again */ - HDassert(!H5F_addr_defined(f->shared->fs_addr[type])); - } /* end if */ - } /* end for */ + result = (fsm_type == sm_fshdr_fsm) || (fsm_type == sm_fssinfo_fsm); + } /* end else */ -done: -#ifdef H5MF_ALLOC_DEBUG -HDfprintf(stderr, "%s: Leaving\n", FUNC); -#endif /* H5MF_ALLOC_DEBUG */ - FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) -} /* H5MF__close_delete() */ + FUNC_LEAVE_NOAPI(result) +} /* H5MF__fsm_type_is_self_referential() */ /*------------------------------------------------------------------------- - * Function: H5MF_try_close + * Function: H5MF__fsm_is_self_referential() * - * Purpose: This is called by H5Fformat_convert() to close and delete - * free-space managers when downgrading persistent free-space - * to non-persistent. + * Purpose: Return TRUE if the indicated free space manager allocates + * file space for free space managers. Return FALSE otherwise. * - * Return: SUCCEED/FAIL + * Return: TRUE/FALSE * - * Programmer: Vailin Choi - * Jan 2016 + * Programmer: John Mainzer + * 12/6/16 * *------------------------------------------------------------------------- */ -herr_t -H5MF_try_close(H5F_t *f, hid_t dxpl_id) +static hbool_t +H5MF__fsm_is_self_referential(H5F_t *f, H5FS_t *fspace) { - H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ - H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ - hbool_t reset_ring = FALSE; /* Whether the ring was set */ - herr_t ret_value = SUCCEED; /* Return value */ + H5F_mem_page_t sm_fshdr_fsm; + H5F_mem_page_t sm_fssinfo_fsm; + hbool_t result = FALSE; - FUNC_ENTER_NOAPI(FAIL) -#ifdef H5MF_ALLOC_DEBUG -HDfprintf(stderr, "%s: Entering\n", FUNC); -#endif /* H5MF_ALLOC_DEBUG */ + FUNC_ENTER_STATIC_NOERR - /* check args */ + /* Sanity check */ HDassert(f); + HDassert(f->shared); + HDassert(fspace); - /* Set the ring type in the DXPL */ - if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") - reset_ring = TRUE; + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fsm); + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fsm); - /* Close and delete freespace managers from the file */ - if(H5MF__close_delete(f, dxpl_id, &dxpl) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to close delete free-space managers") + if(H5F_PAGED_AGGR(f)) { + H5F_mem_page_t lg_fshdr_fsm; + H5F_mem_page_t lg_fssinfo_fsm; -done: - /* Reset the ring in the DXPL */ - if(reset_ring) - if(H5AC_reset_ring(dxpl, orig_ring) < 0) - HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, f->shared->fs_page_size + 1, &lg_fshdr_fsm); + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, f->shared->fs_page_size + 1, &lg_fssinfo_fsm); -#ifdef H5MF_ALLOC_DEBUG -HDfprintf(stderr, "%s: Leaving\n", FUNC); -#endif /* H5MF_ALLOC_DEBUG */ - FUNC_LEAVE_NOAPI(ret_value) -} /* H5MF_try_close() */ + result = (fspace == f->shared->fs_man[sm_fshdr_fsm]) || + (fspace == f->shared->fs_man[sm_fssinfo_fsm]) || + (fspace == f->shared->fs_man[lg_fshdr_fsm]) || + (fspace == f->shared->fs_man[lg_fssinfo_fsm]); + } /* end if */ + else + result = (fspace == f->shared->fs_man[sm_fshdr_fsm]) || + (fspace == f->shared->fs_man[sm_fssinfo_fsm]); + + FUNC_LEAVE_NOAPI(result) +} /* H5MF__fsm_is_self_referential() */ /*------------------------------------------------------------------------- - * Function: H5MF_close - * - * Purpose: Close the free space tracker(s) for a file + * Function: H5MF_tidy_self_referential_fsm_hack + * + * Purpose: As discussed in the comments of the settle routines above, + * the existence of self referential free space managers + * as currently implemented creates the possibility of + * infinite loops at file close. + * + * As a hack to avoid this, we have added code to settle + * self referential free space managers, and then allocate + * space for them directly from the file driver. + * + * To avoid dropping ever increasing amounts of file space + * on the floor with each subsequent file close/open cycle, + * we need to clean this up on file open. To avoid this, + * this function is called on the first file space allocation + * or deallocation after file open to float the self referential + * free space managers and reduce the EOA to the value it + * had before the direct allocation of space for the self + * referential free space managers. + * + * The function proceeds as follows: + * + * 1) Verify that f->shared->first_alloc_dealloc is TRUE, + * and then set it to FALSE. + * + * 2) Get the current EOA. Verify that it is greater than + * or equal to f->shared->eoa_pre_fsm_fsalloc. If the + * current eoa is equal to f->shared->eoa_pre_fsm_fsalloc, + * no self referential FSMs were stored, and we are done. + * + * NOTE: This will have to be reworked somewhat for + * cache image. + * + * 3) Load the self referential FSMs. In passing verify that + * the lowest address of a FSM header is equal to + * f->shared->eoa_pre_fsm_fsalloc.' + * + * Note that we don't have to use any special I/O for + * this -- we can use the regular I/O methods even if + * paged aggregation and page buffering is enabled. + * + * 4) Float the FSMs. Ensure that the file space is NOT + * released. + * + * 5) Set EOA equal to f->shared->eoa_pre_fsm_fsalloc, + * and then set f->shared->eoa_pre_fsm_fsalloc to + * HADDR_UNDEF. + * + * If page buffering, verify that the new EOA is + * on a page boundary, and expunge any pages in the + * page buffer after the new EOA. + * + * Note that this function is also called from test code + * when it is necessary to startup a self referential + * free space manager prior to the first file space + * allocation / deallocation. Failure to do so will + * result in assertion failures in this function on + * the first file space allocation / deallocation. + * + * Return: SUCCEED/FAIL * - * Return: SUCCEED/FAIL - * - * Programmer: Quincey Koziol - * Tuesday, January 22, 2008 + * Programmer: John Mainzer + * 12/11/16 * - * Modifications: - * Vailin Choi; July 2012 - * As the default free-list mapping is changed to H5FD_FLMAP_DICHOTOMY, - * modifications are needed to shrink EOA if the last section of each free-space manager - * and the remaining space in the two aggregators are at EOA. - *------------------------------------------------------------------------- */ herr_t -H5MF_close(H5F_t *f, hid_t dxpl_id) +H5MF_tidy_self_referential_fsm_hack(H5F_t *f, hid_t dxpl_id) { + haddr_t eoa; /* EOA of file */ + hsize_t tail_size = 0; /* Size of chunk to free */ H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ - H5AC_ring_t curr_ring; /* Current ring value */ - H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ - H5FD_mem_t type; /* Memory type for iteration */ + H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ + haddr_t first_srfsm_hdr = HADDR_UNDEF; /* Addr of first self referential */ + /* fsm header in file */ + H5FS_stat_t fs_stat; /* Information for hdr FSM */ + H5F_mem_page_t sm_fshdr_fs_type; /* Small fs hdr fsm */ + H5F_mem_page_t sm_fssinfo_fs_type; /* Small fs sinfo fsm */ + H5F_mem_page_t lg_fshdr_fs_type; /* Large fs hdr fsm */ + H5F_mem_page_t lg_fssinfo_fs_type; /* Large fs sinfo fsm */ hbool_t reset_ring = FALSE; /* Whether the ring was set */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) -#ifdef H5MF_ALLOC_DEBUG -HDfprintf(stderr, "%s: Entering\n", FUNC); -#endif /* H5MF_ALLOC_DEBUG */ /* check args */ HDassert(f); HDassert(f->shared); - HDassert(f->shared->lf); - HDassert(f->shared->sblock); + HDassert(f->shared->fs_persist); + HDassert(f->shared->first_alloc_dealloc); - /* Set the ring type in the DXPL. In most cases, we will - * need H5AC_RING_RDFSM, so initialy set the ring in - * the DXPL to that value. We will alter this later if - * needed. + /* Set the ring type in the DXPL. Since we are only dealing with + * self referential FSMs, we will only need H5AC_RING_MDFSM. */ - if(H5AC_set_ring(dxpl_id, H5AC_RING_RDFSM, &dxpl, &orig_ring) < 0) + if(H5AC_set_ring(dxpl_id, H5AC_RING_MDFSM, &dxpl, &orig_ring) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") reset_ring = TRUE; - curr_ring = H5AC_RING_RDFSM; - /* Free the space in aggregators */ - /* (for space not at EOF, it may be put into free space managers) */ - if(H5MF_free_aggrs(f, dxpl_id) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators") + /* 1) Verify that f->shared->first_alloc_dealloc is TRUE, + * and then set it to FALSE. + */ + HDassert(f->shared->first_alloc_dealloc); + f->shared->first_alloc_dealloc = FALSE; - /* Trying shrinking the EOA for the file */ - if(H5MF__close_shrink_eoa(f, dxpl_id) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa") - /* Making free-space managers persistent for superblock version >= 2 */ - if(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2 - && f->shared->fs_strategy == H5F_FILE_SPACE_ALL_PERSIST) { - H5O_fsinfo_t fsinfo; /* Free space manager info message */ + /* 2) Get the current EOA. Verify that it is greater than + * or equal to f->shared->eoa_pre_fsm_fsalloc. If the + * current eoa is equal to f->shared->eoa_pre_fsm_fsalloc, + * no self referential FSMs were stored, and we are done. + * + * NOTE: This will have to be reworked somewhat for + * cache image. + */ + if(HADDR_UNDEF == (eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT))) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get EOA") + HDassert(H5F_addr_le(f->shared->eoa_pre_fsm_fsalloc, eoa)); - /* Superblock extension and free space manager message should - * exist at this point -- verify at least the former. - */ - HDassert(H5F_addr_defined(f->shared->sblock->ext_addr)); + if(H5F_addr_eq(f->shared->eoa_pre_fsm_fsalloc, eoa)) + HGOTO_DONE(SUCCEED) - /* Note that unlike the previous version of this code, we do not - * delete free space managers that have no section to store. - * - * Can't do this, as that would involve freeing file space, which would - * dirty the free space manager in question. - * - * Fortunately, the code doesn't seem to care about this. - */ - /* Gather data for the free space manager superblock extension message. - * - * In passing, verify that all the free space managers are closed. - */ - for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) - fsinfo.fs_addr[type - 1] = f->shared->fs_addr[type]; - fsinfo.strategy = f->shared->fs_strategy; - fsinfo.threshold = f->shared->fs_threshold; + /* 3) Load the self referential FSMs. In passing verify that + * the lowest address of a FSM header is equal to + * f->shared->eoa_pre_fsm_fsalloc.' + * + * Note that we don't have to use any special I/O for + * this -- we can use the regular I/O methods even if + * paged aggregation and page buffering is enabled. + */ + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fs_type); + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fs_type); + HDassert(sm_fshdr_fs_type > H5F_MEM_PAGE_DEFAULT); + HDassert(sm_fshdr_fs_type < H5F_MEM_PAGE_LARGE_SUPER); - /* Write the free space manager message -- message must already exist */ - if(H5F_super_ext_write_msg(f, dxpl_id, H5O_FSINFO_ID, &fsinfo, FALSE, H5O_MSG_NO_FLAGS_SET) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, "error in writing message to superblock extension") + HDassert(sm_fssinfo_fs_type > H5F_MEM_PAGE_DEFAULT); + HDassert(sm_fssinfo_fs_type < H5F_MEM_PAGE_LARGE_SUPER); - /* Final close of free-space managers */ - for(type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t, type)) { - if(f->shared->fs_man[type]) { - H5AC_ring_t needed_ring; /* Ring value needed for this iteration */ + HDassert(NULL == f->shared->fs_man[sm_fshdr_fs_type]); + HDassert(NULL == f->shared->fs_man[sm_fssinfo_fs_type]); - /* test to see if we need to switch rings -- do so if required */ - if((H5MF_ALLOC_TO_FS_TYPE(f, type) == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (H5MF_ALLOC_TO_FS_TYPE(f, type) == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) - needed_ring = H5AC_RING_MDFSM; - else - needed_ring = H5AC_RING_RDFSM; + if(H5F_addr_defined(f->shared->fs_addr[sm_fshdr_fs_type])) { + first_srfsm_hdr = f->shared->fs_addr[sm_fshdr_fs_type]; - if(needed_ring != curr_ring) { - if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (3)") - curr_ring = needed_ring; - } /* end if */ + /* open the FSM */ + if(H5MF_open_fstype(f, dxpl_id, sm_fshdr_fs_type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager") - HDassert(f->shared->fs_state[type] == H5F_FS_STATE_OPEN); - if(H5FS_close(f, dxpl_id, f->shared->fs_man[type]) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close free space manager") - f->shared->fs_man[type] = NULL; - f->shared->fs_state[type] = H5F_FS_STATE_CLOSED; - } /* end if */ - f->shared->fs_addr[type] = HADDR_UNDEF; - } /* end for */ + HDassert(f->shared->fs_man[sm_fshdr_fs_type]); + } /* end if */ - /* Verify that we haven't dirtied any metadata cache entries - * from the metadata free space manager ring out. - */ - HDassert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM)); + if((sm_fshdr_fs_type != sm_fssinfo_fs_type) && + (H5F_addr_defined(f->shared->fs_addr[sm_fssinfo_fs_type]))) { - /* Verify that the aggregators are still shutdown. */ - HDassert(f->shared->sdata_aggr.tot_size == 0); - HDassert(f->shared->sdata_aggr.addr == 0); - HDassert(f->shared->sdata_aggr.size == 0); - HDassert(f->shared->meta_aggr.tot_size == 0); - HDassert(f->shared->meta_aggr.addr == 0); - HDassert(f->shared->meta_aggr.size == 0); - } /* end if */ - else { /* super_vers can be 0, 1, 2 */ - /* Close and delete freespace managers from the file */ - if(H5MF__close_delete(f, dxpl_id, &dxpl) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space") + if(!H5F_addr_defined(first_srfsm_hdr) || + (H5F_addr_defined(first_srfsm_hdr) && + H5F_addr_lt(f->shared->fs_addr[sm_fssinfo_fs_type], first_srfsm_hdr))) + first_srfsm_hdr = f->shared->fs_addr[sm_fssinfo_fs_type]; - /* moved code that was for both the persistant and non persistant free - * space managers to the non-persistant case. In the persistant - * case, the EOA should already be as shrunked as it can be, and the - * aggregators should alread be shut down. - */ + HDassert(NULL == f->shared->fs_man[sm_fssinfo_fs_type]); - /* Free the space in aggregators (again) */ - /* (in case any free space information re-started them) */ - if(H5MF_free_aggrs(f, dxpl_id) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators") + /* open the FSM */ + if(H5MF_open_fstype(f, dxpl_id, sm_fssinfo_fs_type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager") - /* Trying shrinking the EOA for the file */ - /* (in case any free space is now at the EOA) */ - if(H5MF__close_shrink_eoa(f, dxpl_id) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa") - } /* end else */ + HDassert(f->shared->fs_man[sm_fssinfo_fs_type]); + } /* end if */ -done: - /* Reset the ring in the DXPL */ - if(reset_ring) - if(H5AC_reset_ring(dxpl, orig_ring) < 0) - HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") + if(H5F_PAGED_AGGR(f)) { + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_HDR, f->shared->fs_page_size + 1, &lg_fshdr_fs_type); + H5MF_alloc_to_fs_type(f, H5FD_MEM_FSPACE_SINFO, f->shared->fs_page_size + 1, &lg_fssinfo_fs_type); -#ifdef H5MF_ALLOC_DEBUG -HDfprintf(stderr, "%s: Leaving\n", FUNC); -#endif /* H5MF_ALLOC_DEBUG */ - FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) -} /* end H5MF_close() */ + HDassert(lg_fshdr_fs_type >= H5F_MEM_PAGE_LARGE_SUPER); + HDassert(lg_fshdr_fs_type < H5F_MEM_PAGE_NTYPES); - -/*------------------------------------------------------------------------- - * Function: H5MF_sects_cb() - * - * Purpose: Iterator callback for each free-space section - * Retrieve address and size into user data - * - * Return: Always succeed - * - * Programmer: Vailin Choi - * July 1st, 2009 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5MF_sects_cb(H5FS_section_info_t *_sect, void *_udata) -{ - H5MF_free_section_t *sect = (H5MF_free_section_t *)_sect; - H5MF_sect_iter_ud_t *udata = (H5MF_sect_iter_ud_t *)_udata; + HDassert(lg_fssinfo_fs_type >= H5F_MEM_PAGE_LARGE_SUPER); + HDassert(lg_fssinfo_fs_type < H5F_MEM_PAGE_NTYPES); - FUNC_ENTER_NOAPI_NOINIT_NOERR + HDassert(NULL == f->shared->fs_man[lg_fshdr_fs_type]); + HDassert(NULL == f->shared->fs_man[lg_fssinfo_fs_type]); - if(udata->sect_idx < udata->sect_count) { - udata->sects[udata->sect_idx].addr = sect->sect_info.addr; - udata->sects[udata->sect_idx].size = sect->sect_info.size; - udata->sect_idx++; - } /* end if */ + if(H5F_addr_defined(f->shared->fs_addr[lg_fshdr_fs_type])) { + if(!H5F_addr_defined(first_srfsm_hdr) || + (H5F_addr_defined(first_srfsm_hdr) && + H5F_addr_lt(f->shared->fs_addr[lg_fshdr_fs_type], first_srfsm_hdr))) + first_srfsm_hdr = f->shared->fs_addr[lg_fshdr_fs_type]; - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5MF_sects_cb() */ + HDassert(NULL == f->shared->fs_man[lg_fshdr_fs_type]); - -/*------------------------------------------------------------------------- - * Function: H5MF_get_free_sections() - * - * Purpose: To iterate over one or all free-space managers for: - * # of sections - * section info as defined in H5F_sect_info_t - * - * Return: SUCCEED/FAIL - * - * Programmer: Vailin Choi - * July 1st, 2009 - * - *------------------------------------------------------------------------- - */ -ssize_t -H5MF_get_free_sections(H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, size_t nsects, H5F_sect_info_t *sect_info) -{ - size_t total_sects = 0; /* total number of sections */ - H5MF_sect_iter_ud_t sect_udata; /* User data for callback */ - H5P_genplist_t *dxpl = NULL; /* DXPL for setting ring */ - H5AC_ring_t curr_ring; /* Current ring value */ - H5AC_ring_t needed_ring; /* Ring value needed for this iteration */ - H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ - H5FD_mem_t start_type, end_type; /* Memory types to iterate over */ - H5FD_mem_t ty; /* Memory type for iteration */ - hbool_t reset_ring = FALSE; /* Whether the ring was set */ - ssize_t ret_value = -1; /* Return value */ + /* open the FSM */ + if(H5MF_open_fstype(f, dxpl_id, lg_fshdr_fs_type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager") + HDassert(f->shared->fs_man[lg_fshdr_fs_type]); + } /* end if */ - FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__FREESPACE_TAG, FAIL) + if(lg_fshdr_fs_type != lg_fssinfo_fs_type && H5F_addr_defined(f->shared->fs_addr[lg_fssinfo_fs_type])) { + if(!H5F_addr_defined(first_srfsm_hdr) || + (H5F_addr_defined(first_srfsm_hdr) && + H5F_addr_lt(f->shared->fs_addr[lg_fssinfo_fs_type], first_srfsm_hdr))) + first_srfsm_hdr = f->shared->fs_addr[lg_fssinfo_fs_type]; - /* check args */ - HDassert(f); - HDassert(f->shared); - HDassert(f->shared->lf); + HDassert(NULL == f->shared->fs_man[lg_fssinfo_fs_type]); - /* Determine start/end points for loop */ - if(type == H5FD_MEM_DEFAULT) { - start_type = H5FD_MEM_SUPER; - end_type = H5FD_MEM_NTYPES; + /* open the FSM */ + if(H5MF_open_fstype(f, dxpl_id, lg_fssinfo_fs_type) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space manager") + HDassert(f->shared->fs_man[lg_fssinfo_fs_type]); + } /* end if */ + } /* end if */ + HDassert(H5F_addr_eq(first_srfsm_hdr, f->shared->eoa_pre_fsm_fsalloc)); + + /* 4) Float the FSMs. Ensure that the file space is NOT released. */ + if(f->shared->fs_man[sm_fshdr_fs_type]) { + /* Sanity check: Query free space manager info for this type */ + if(H5FS_stat_info(f, f->shared->fs_man[sm_fshdr_fs_type], &fs_stat) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info") + + HDassert(H5F_addr_defined(fs_stat.addr)); + HDassert(H5F_addr_defined(fs_stat.sect_addr)); + if(H5FS_free(f, f->shared->fs_man[sm_fshdr_fs_type], dxpl_id, FALSE) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free-space headers") + f->shared->fs_addr[sm_fshdr_fs_type] = HADDR_UNDEF; } /* end if */ - else { - start_type = end_type = type; - H5_INC_ENUM(H5FD_mem_t, end_type); - } /* end else */ - - /* Set up user data for section iteration */ - sect_udata.sects = sect_info; - sect_udata.sect_count = nsects; - sect_udata.sect_idx = 0; - /* Set the ring type in the DXPL. Note that if we are - * scanning a number of different free space managers, - * we may have to change the ring - */ - if((H5MF_ALLOC_TO_FS_TYPE(f, start_type) == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (H5MF_ALLOC_TO_FS_TYPE(f, start_type) == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) - needed_ring = H5AC_RING_MDFSM; - else - needed_ring = H5AC_RING_RDFSM; - curr_ring = needed_ring; - if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &orig_ring) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value") - reset_ring = TRUE; + if(sm_fshdr_fs_type != sm_fssinfo_fs_type && f->shared->fs_man[sm_fssinfo_fs_type]) { + /* Sanity check: Query free space manager info for this type */ + if(H5FS_stat_info(f, f->shared->fs_man[sm_fssinfo_fs_type], &fs_stat) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info") - /* Iterate over memory types, retrieving the number of sections of each type */ - for(ty = start_type; ty < end_type; H5_INC_ENUM(H5FD_mem_t, ty)) { - hbool_t fs_started = FALSE; + HDassert(H5F_addr_defined(fs_stat.addr)); + HDassert(H5F_addr_defined(fs_stat.sect_addr)); + if(H5FS_free(f, f->shared->fs_man[sm_fssinfo_fs_type], dxpl_id, FALSE) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free-space headers") + f->shared->fs_addr[sm_fssinfo_fs_type] = HADDR_UNDEF; + } /* end if */ - /* test to see if we need to switch rings -- do so if required */ - if((H5MF_ALLOC_TO_FS_TYPE(f, ty) == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_HDR)) - || (H5MF_ALLOC_TO_FS_TYPE(f, ty) == H5MF_ALLOC_TO_FS_TYPE(f, H5FD_MEM_FSPACE_SINFO))) - needed_ring = H5AC_RING_MDFSM; - else - needed_ring = H5AC_RING_RDFSM; + if(H5F_PAGED_AGGR(f)) { + if(f->shared->fs_man[lg_fshdr_fs_type]) { + /* Sanity check: Query free space manager info for this type */ + if(H5FS_stat_info(f, f->shared->fs_man[lg_fshdr_fs_type], &fs_stat) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info") - if(needed_ring != curr_ring) { - if(H5AC_set_ring(dxpl_id, needed_ring, &dxpl, &curr_ring) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set ring value (2)") - curr_ring = needed_ring; + HDassert(H5F_addr_defined(fs_stat.addr)); + HDassert(H5F_addr_defined(fs_stat.sect_addr)); + if(H5FS_free(f, f->shared->fs_man[lg_fshdr_fs_type], dxpl_id, FALSE) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't float free-space headers") + f->shared->fs_addr[lg_fshdr_fs_type] = HADDR_UNDEF; } /* end if */ - /* Open free space manager of this type, if it isn't already */ - if(!f->shared->fs_man[ty] && H5F_addr_defined(f->shared->fs_addr[ty])) { - if(H5MF__alloc_open(f, dxpl_id, ty) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, FAIL, "can't initialize file free space") - HDassert(f->shared->fs_man[ty]); - fs_started = TRUE; - } /* end if */ - - /* Check if f there's free space sections of this type */ - if(f->shared->fs_man[ty]) { - hsize_t hnums = 0; /* Total # of sections */ - size_t nums; /* Total # of sections, cast to a size_t */ - - /* Query how many sections of this type */ - if(H5FS_sect_stats(f->shared->fs_man[ty], NULL, &hnums) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats") - H5_CHECKED_ASSIGN(nums, size_t, hnums, hsize_t); - - /* Increment total # of sections */ - total_sects += nums; - - /* Check if we should retrieve the section info */ - if(sect_info && nums > 0) { - /* Iterate over all the free space sections of this type, adding them to the user's section info */ - if(H5FS_sect_iterate(f, dxpl_id, f->shared->fs_man[ty], H5MF_sects_cb, §_udata) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_BADITER, FAIL, "can't iterate over sections") - } /* end if */ + if(lg_fshdr_fs_type != lg_fssinfo_fs_type && f->shared->fs_man[lg_fssinfo_fs_type]) { + /* Sanity check: Query free space manager info for this type */ + if(H5FS_stat_info(f, f->shared->fs_man[lg_fssinfo_fs_type], &fs_stat) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info") + + HDassert(H5F_addr_defined(fs_stat.addr)); + HDassert(H5F_addr_defined(fs_stat.sect_addr)); + if(H5FS_free(f, f->shared->fs_man[lg_fssinfo_fs_type], dxpl_id, FALSE) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't float free-space headers") + f->shared->fs_addr[lg_fssinfo_fs_type] = HADDR_UNDEF; } /* end if */ + } /* end if */ - /* Close the free space manager of this type, if we started it here */ - if(fs_started) - if(H5MF__alloc_close(f, dxpl_id, ty) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCLOSEOBJ, FAIL, "can't close file free space") - } /* end for */ + /* 5) Set EOA equal to f->shared->eoa_pre_fsm_fsalloc, + * and then set f->shared->eoa_pre_fsm_fsalloc to + * HADDR_UNDEF. + * + * If page buffering, verify that the new EOA is + * on a page boundary, and expunge any pages in the + * page buffer after the new EOA. + */ + if(!H5F_PAGED_AGGR(f)) { + /* Verify that the aggregators are still shutdown. */ + HDassert(f->shared->sdata_aggr.tot_size == 0); + HDassert(f->shared->sdata_aggr.addr == 0); + HDassert(f->shared->sdata_aggr.size == 0); - /* Set return value */ - ret_value = (ssize_t)total_sects; + HDassert(f->shared->meta_aggr.tot_size == 0); + HDassert(f->shared->meta_aggr.addr == 0); + HDassert(f->shared->meta_aggr.size == 0); + } /* end if */ + + tail_size = (hsize_t)(eoa - f->shared->eoa_pre_fsm_fsalloc); + + /* Release file space allocated to self referential FSMs */ + if(H5F_free(f, dxpl_id, H5FD_MEM_DEFAULT, f->shared->eoa_pre_fsm_fsalloc, tail_size) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "driver free request failed") + if(HADDR_UNDEF == (eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT))) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get EOA") + HDassert(H5F_addr_eq(f->shared->eoa_pre_fsm_fsalloc, eoa)); + + f->shared->eoa_pre_fsm_fsalloc = HADDR_UNDEF; + + HDassert((!H5F_PAGED_AGGR(f)) || (0 == (eoa % f->shared->fs_page_size))); done: /* Reset the ring in the DXPL */ @@ -2359,5 +3911,5 @@ done: HDONE_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "unable to set property value") FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) -} /* H5MF_get_free_sections() */ +} /* H5MF_tidy_self_referential_fsm_hack() */ |