From d6c27d4b4d82d794e860770f5903e84511596d19 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sat, 6 Jan 2007 15:50:45 -0500 Subject: [svn-r13115] Description: Allow a heap to be marked for deletion while it is still open and being accessed. (Blocks further opens though). Tested on: FreeBSD/32 6.1 (duty) --- src/H5HF.c | 102 ++++++++++++++---------------------- src/H5HFcache.c | 2 + src/H5HFhdr.c | 114 +++++++++++++++++++++++++++++++++++++++++ src/H5HFpkg.h | 6 ++- test/fheap.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 313 insertions(+), 67 deletions(-) diff --git a/src/H5HF.c b/src/H5HF.c index e53a793..7e9a06b 100644 --- a/src/H5HF.c +++ b/src/H5HF.c @@ -240,6 +240,10 @@ HDfprintf(stderr, "%s: fh_addr = %a\n", FUNC, fh_addr); HDfprintf(stderr, "%s: hdr->rc = %u, hdr->fspace = %p\n", FUNC, hdr->rc, hdr->fspace); #endif /* QAK */ + /* Check for pending heap deletion */ + if(hdr->pending_delete) + HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, NULL, "can't open fractal heap pending deletion") + /* Create fractal heap info */ if(NULL == (fh = H5FL_MALLOC(H5HF_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for fractal heap info") @@ -771,6 +775,8 @@ done: herr_t H5HF_close(H5HF_t *fh, hid_t dxpl_id) { + hbool_t pending_delete = FALSE; /* Whether the heap is pending deletion */ + haddr_t heap_addr = HADDR_UNDEF; /* Address of heap (for deletion) */ herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5HF_close, FAIL) @@ -819,12 +825,37 @@ HDfprintf(stderr, "%s; After iterator reset fh->hdr->rc = %Zu\n", FUNC, fh->hdr- */ if(H5HF_huge_term(fh->hdr, dxpl_id) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release 'huge' object info") + + /* Check for pending heap deletion */ + if(fh->hdr->pending_delete) { + /* Set local info, so heap deletion can occur after decrementing the + * header's ref count + */ + pending_delete = TRUE; + heap_addr = fh->hdr->heap_addr; + } /* end if */ } /* end if */ /* Decrement the reference count on the heap header */ if(H5HF_hdr_decr(fh->hdr) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header") + /* Check for pending heap deletion */ + if(pending_delete) { + H5HF_hdr_t *hdr; /* Another pointer to fractal heap header */ + + /* Lock the heap header into memory */ + if(NULL == (hdr = H5AC_protect(fh->f, dxpl_id, H5AC_FHEAP_HDR, heap_addr, NULL, NULL, H5AC_WRITE))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTLOAD, FAIL, "unable to load fractal heap header") + + /* Set the shared heap header's file context for this operation */ + hdr->f = fh->f; + + /* Delete heap, starting with header (unprotects header) */ + if(H5HF_hdr_delete(hdr, dxpl_id) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "unable to delete fractal heap") + } /* end if */ + /* Release the fractal heap wrapper */ H5FL_FREE(H5HF_t, fh); @@ -869,73 +900,14 @@ HDfprintf(stderr, "%s: fh_addr = %a\n", FUNC, fh_addr); /* Check for files using shared heap header */ if(hdr->file_rc) - HGOTO_ERROR(H5E_HEAP, H5E_OBJOPEN, FAIL, "heap still open") - - /* Check for free space manager for heap */ - /* (must occur before attempting to delete the heap, so indirect blocks - * will get unpinned) - */ - if(H5F_addr_defined(hdr->fs_addr)) { -#ifdef QAK -HDfprintf(stderr, "%s: hdr->fs_addr = %a\n", FUNC, hdr->fs_addr); -#endif /* QAK */ - /* Delete free space manager for heap */ - if(H5HF_space_delete(hdr, dxpl_id) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap free space manager") - } /* end if */ - - /* Check for root direct/indirect block */ - if(H5F_addr_defined(hdr->man_dtable.table_addr)) { -#ifdef QAK -HDfprintf(stderr, "%s: hdr->man_dtable.table_addr = %a\n", FUNC, hdr->man_dtable.table_addr); -#endif /* QAK */ - if(hdr->man_dtable.curr_root_rows == 0) { - hsize_t dblock_size; /* Size of direct block */ - - /* Check for I/O filters on this heap */ - if(hdr->filter_len > 0) { - dblock_size = (hsize_t)hdr->pline_root_direct_size; -#ifdef QAK -HDfprintf(stderr, "%s: hdr->pline_root_direct_size = %Zu\n", FUNC, hdr->pline_root_direct_size); -#endif /* QAK */ - - /* Reset the header's pipeline information */ - hdr->pline_root_direct_size = 0; - hdr->pline_root_direct_filter_mask = 0; - } /* end else */ - else - dblock_size = (hsize_t)hdr->man_dtable.cparam.start_block_size; - - /* Delete root direct block */ - if(H5HF_man_dblock_delete(f, dxpl_id, hdr->man_dtable.table_addr, dblock_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap root direct block") - } /* end if */ - else { - /* Delete root indirect block */ - if(H5HF_man_iblock_delete(hdr, dxpl_id, hdr->man_dtable.table_addr, hdr->man_dtable.curr_root_rows, NULL, 0) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap root indirect block") - } /* end else */ - } /* end if */ - - /* Check for 'huge' objects in heap */ - if(H5F_addr_defined(hdr->huge_bt2_addr)) { -#ifdef QAK -HDfprintf(stderr, "%s: hdr->huge_bt2_addr = %a\n", FUNC, hdr->huge_bt2_addr); -#endif /* QAK */ - /* Delete huge objects in heap and their tracker */ - if(H5HF_huge_delete(hdr, dxpl_id) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap 'huge' objects and tracker") + hdr->pending_delete = TRUE; + else { + /* Delete heap now, starting with header (unprotects header) */ + if(H5HF_hdr_delete(hdr, dxpl_id) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "unable to delete fractal heap") + hdr = NULL; } /* end if */ - /* Release header's disk space */ - if(H5MF_xfree(f, H5FD_MEM_FHEAP_HDR, dxpl_id, fh_addr, (hsize_t)hdr->heap_size) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap header") - - /* Finished deleting header */ - if(H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__DIRTIED_FLAG|H5AC__DELETED_FLAG) < 0) - HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap header") - hdr = NULL; - done: /* Unprotect the header, if an error occurred */ if(hdr && H5AC_unprotect(f, dxpl_id, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0) diff --git a/src/H5HFcache.c b/src/H5HFcache.c index 880c36d..0fbafba 100644 --- a/src/H5HFcache.c +++ b/src/H5HFcache.c @@ -307,6 +307,7 @@ HDfprintf(stderr, "%s: Load heap header, addr = %a\n", FUNC, addr); /* Heap status flags */ /* (bit 0: "huge" object IDs have wrapped) */ + /* (bit 1: checksum direct blocks) */ heap_flags = *p++; hdr->huge_ids_wrapped = heap_flags & H5HF_HDR_FLAGS_HUGE_ID_WRAPPED; hdr->checksum_dblocks = heap_flags & H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS; @@ -491,6 +492,7 @@ HDfprintf(stderr, "%s: Flushing heap header, addr = %a, destroy = %u\n", FUNC, a /* Heap status flags */ /* (bit 0: "huge" object IDs have wrapped) */ + /* (bit 1: checksum direct blocks) */ heap_flags = 0; heap_flags |= (hdr->huge_ids_wrapped ? H5HF_HDR_FLAGS_HUGE_ID_WRAPPED : 0); heap_flags |= (hdr->checksum_dblocks ? H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS : 0); diff --git a/src/H5HFhdr.c b/src/H5HFhdr.c index 4b61063..6267e76 100644 --- a/src/H5HFhdr.c +++ b/src/H5HFhdr.c @@ -1481,3 +1481,117 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF_hdr_empty() */ + +/*------------------------------------------------------------------------- + * Function: H5HF_hdr_delete + * + * Purpose: Delete a fractal heap, starting with the header + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jan 5 2007 + * + *------------------------------------------------------------------------- + */ +herr_t +H5HF_hdr_delete(H5HF_hdr_t *hdr, hid_t dxpl_id) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5HF_hdr_delete, FAIL) + + /* + * Check arguments. + */ + HDassert(hdr); + HDassert(!hdr->file_rc); + +#ifndef NDEBUG +{ + unsigned hdr_status = 0; /* Heap header's status in the metadata cache */ + + /* Check the heap header's status in the metadata cache */ + if(H5AC_get_entry_status(hdr->f, hdr->heap_addr, &hdr_status) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for heap header") + + /* Sanity checks on heap header */ + HDassert(hdr_status & H5AC_ES__IN_CACHE); + HDassert(hdr_status & H5AC_ES__IS_PROTECTED); +} /* end block */ +#endif /* NDEBUG */ + + /* Check for free space manager for heap */ + /* (must occur before attempting to delete the heap, so indirect blocks + * will get unpinned) + */ + if(H5F_addr_defined(hdr->fs_addr)) { +#ifdef QAK +HDfprintf(stderr, "%s: hdr->fs_addr = %a\n", FUNC, hdr->fs_addr); +#endif /* QAK */ + /* Delete free space manager for heap */ + if(H5HF_space_delete(hdr, dxpl_id) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap free space manager") + } /* end if */ + + /* Check for root direct/indirect block */ + if(H5F_addr_defined(hdr->man_dtable.table_addr)) { +#ifdef QAK +HDfprintf(stderr, "%s: hdr->man_dtable.table_addr = %a\n", FUNC, hdr->man_dtable.table_addr); +#endif /* QAK */ + if(hdr->man_dtable.curr_root_rows == 0) { + hsize_t dblock_size; /* Size of direct block */ + + /* Check for I/O filters on this heap */ + if(hdr->filter_len > 0) { + dblock_size = (hsize_t)hdr->pline_root_direct_size; +#ifdef QAK +HDfprintf(stderr, "%s: hdr->pline_root_direct_size = %Zu\n", FUNC, hdr->pline_root_direct_size); +#endif /* QAK */ + + /* Reset the header's pipeline information */ + hdr->pline_root_direct_size = 0; + hdr->pline_root_direct_filter_mask = 0; + } /* end else */ + else + dblock_size = (hsize_t)hdr->man_dtable.cparam.start_block_size; + + /* Delete root direct block */ + if(H5HF_man_dblock_delete(hdr->f, dxpl_id, hdr->man_dtable.table_addr, dblock_size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap root direct block") + } /* end if */ + else { + /* Delete root indirect block */ + if(H5HF_man_iblock_delete(hdr, dxpl_id, hdr->man_dtable.table_addr, hdr->man_dtable.curr_root_rows, NULL, 0) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap root indirect block") + } /* end else */ + } /* end if */ + + /* Check for 'huge' objects in heap */ + if(H5F_addr_defined(hdr->huge_bt2_addr)) { +#ifdef QAK +HDfprintf(stderr, "%s: hdr->huge_bt2_addr = %a\n", FUNC, hdr->huge_bt2_addr); +#endif /* QAK */ + /* Delete huge objects in heap and their tracker */ + if(H5HF_huge_delete(hdr, dxpl_id) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap 'huge' objects and tracker") + } /* end if */ + + /* Release header's disk space */ + if(H5MF_xfree(hdr->f, H5FD_MEM_FHEAP_HDR, dxpl_id, hdr->heap_addr, (hsize_t)hdr->heap_size) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to release fractal heap header") + + /* Finished deleting header */ + if(H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_HDR, hdr->heap_addr, hdr, H5AC__DIRTIED_FLAG|H5AC__DELETED_FLAG) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap header") + hdr = NULL; + +done: + /* Unprotect the header, if an error occurred */ + if(hdr && H5AC_unprotect(hdr->f, dxpl_id, H5AC_FHEAP_HDR, hdr->heap_addr, hdr, H5AC__NO_FLAGS_SET) < 0) + HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap header") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF_hdr_delete() */ + diff --git a/src/H5HFpkg.h b/src/H5HFpkg.h index 676a63e..6e6951d 100644 --- a/src/H5HFpkg.h +++ b/src/H5HFpkg.h @@ -71,8 +71,8 @@ ) /* Flags for status byte */ -#define H5HF_HDR_FLAGS_HUGE_ID_WRAPPED 0x01 -#define H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS 0x02 +#define H5HF_HDR_FLAGS_HUGE_ID_WRAPPED 0x01 /* "huge" object IDs have wrapped */ +#define H5HF_HDR_FLAGS_CHECKSUM_DBLOCKS 0x02 /* checksum direct blocks */ /* Size of the fractal heap header on disk */ /* (this is the fixed-len portion, the variable-len I/O filter information @@ -348,6 +348,7 @@ typedef struct H5HF_hdr_t { H5AC_protect_t mode; /* Access mode for heap */ H5F_t *f; /* Pointer to file for heap */ size_t file_rc; /* Reference count of files using heap header */ + hbool_t pending_delete; /* Heap is pending deletion */ size_t sizeof_size; /* Size of file sizes */ size_t sizeof_addr; /* Size of file addresses */ struct H5HF_indirect_t *root_iblock; /* Pointer to pinned root indirect block */ @@ -569,6 +570,7 @@ H5_DLL herr_t H5HF_hdr_reverse_iter(H5HF_hdr_t *hdr, hid_t dxpl_id, haddr_t dblock_addr); H5_DLL herr_t H5HF_hdr_reset_iter(H5HF_hdr_t *hdr, hsize_t curr_off); H5_DLL herr_t H5HF_hdr_empty(H5HF_hdr_t *hdr); +H5_DLL herr_t H5HF_hdr_delete(H5HF_hdr_t *hdr, hid_t dxpl_id); /* Indirect block routines */ H5_DLL herr_t H5HF_iblock_incr(H5HF_indirect_t *iblock); diff --git a/test/fheap.c b/test/fheap.c index c8087fa..0502a23 100644 --- a/test/fheap.c +++ b/test/fheap.c @@ -2136,6 +2136,155 @@ error: /*------------------------------------------------------------------------- + * Function: test_delete_open + * + * Purpose: Delete opened fractal heap (& open deleted heap) + * + * Return: Success: 0 + * Failure: 1 + * + * Programmer: Quincey Koziol + * Friday, January 5, 2007 + * + *------------------------------------------------------------------------- + */ +static int +test_delete_open(hid_t fapl, H5HF_create_t *cparam, fheap_test_param_t UNUSED *tparam) +{ + hid_t file = -1; /* File ID */ + char filename[FHEAP_FILENAME_LEN]; /* Filename to use */ + H5F_t *f = NULL; /* Internal file object pointer */ + H5HF_create_t test_cparam; /* Creation parameters for heap */ + H5HF_t *fh = NULL; /* Fractal heap wrapper */ + H5HF_t *fh2 = NULL; /* 2nd fractal heap wrapper */ + haddr_t fh_addr; /* Address of fractal heap */ + size_t id_len; /* Size of fractal heap IDs */ + h5_stat_size_t empty_size; /* Size of a file with an empty heap */ + h5_stat_size_t file_size; /* Size of file currently */ + fheap_heap_state_t state; /* State of fractal heap */ + + /* Set the filename to use for this test (dependent on fapl) */ + h5_fixname(FILENAME[0], fapl, filename, sizeof(filename)); + + /* Create the file to work on */ + if((file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) + TEST_ERROR + + /* Close file */ + if(H5Fclose(file) < 0) + FAIL_STACK_ERROR + + /* Get the size of a file w/no heap*/ + if((empty_size = h5_get_file_size(filename)) < 0) + TEST_ERROR + + /* Re-open the file */ + if((file = H5Fopen(filename, H5F_ACC_RDWR, fapl)) < 0) + FAIL_STACK_ERROR + + /* Get a pointer to the internal file object */ + if(NULL == (f = H5I_object(file))) + STACK_ERROR + + /* Display test banner */ + TESTING("deleting open fractal heap"); + + /* Create heap */ + if(NULL == (fh = H5HF_create(f, H5P_DATASET_XFER_DEFAULT, cparam))) + FAIL_STACK_ERROR + if(H5HF_get_id_len(fh, &id_len) < 0) + FAIL_STACK_ERROR + if(id_len > HEAP_ID_LEN) + TEST_ERROR + if(H5HF_get_heap_addr(fh, &fh_addr) < 0) + FAIL_STACK_ERROR + if(!H5F_addr_defined(fh_addr)) + TEST_ERROR + HDmemset(&state, 0, sizeof(fheap_heap_state_t)); + if(check_stats(fh, &state)) + TEST_ERROR + + /* Open the heap again */ + if(NULL == (fh2 = H5HF_open(f, H5P_DATASET_XFER_DEFAULT, fh_addr))) + FAIL_STACK_ERROR + + /* Request that the heap be deleted */ + if(H5HF_delete(f, H5P_DATASET_XFER_DEFAULT, fh_addr) < 0) + FAIL_STACK_ERROR + + /* Query the type of address mapping */ + HDmemset(&test_cparam, 0, sizeof(H5HF_create_t)); + if(H5HF_get_cparam_test(fh2, &test_cparam) < 0) + FAIL_STACK_ERROR + if(H5HF_cmp_cparam_test(cparam, &test_cparam)) + TEST_ERROR + + /* Close the second fractal heap wrapper */ + if(H5HF_close(fh2, H5P_DATASET_XFER_DEFAULT) < 0) + FAIL_STACK_ERROR + fh2 = NULL; + + /* Try re-opening the heap again (should fail, as heap will be deleted) */ + H5E_BEGIN_TRY { + fh2 = H5HF_open(f, H5P_DATASET_XFER_DEFAULT, fh_addr); + } H5E_END_TRY; + if(fh2) { + /* Close opened heap */ + H5HF_close(fh2, H5P_DATASET_XFER_DEFAULT); + + /* Indicate error */ + TEST_ERROR + } /* end if */ + + /* Close the first fractal heap wrapper */ + if(H5HF_close(fh, H5P_DATASET_XFER_DEFAULT) < 0) + FAIL_STACK_ERROR + fh = NULL; + +#ifdef QAK + /* Try re-opening the heap again (should fail, as heap is now deleted) */ + H5E_BEGIN_TRY { + fh = H5HF_open(f, H5P_DATASET_XFER_DEFAULT, fh_addr); + } H5E_END_TRY; + if(fh) { + /* Close opened heap */ + H5HF_close(fh, H5P_DATASET_XFER_DEFAULT); + + /* Indicate error */ + TEST_ERROR + } /* end if */ +#endif /* QAK */ + + /* Close the file */ + if(H5Fclose(file) < 0) + FAIL_STACK_ERROR + + /* Get the size of the file */ + if((file_size = h5_get_file_size(filename)) < 0) + TEST_ERROR + + /* Verify the file is correct size */ + if(file_size != empty_size) + TEST_ERROR + + /* All tests passed */ + PASSED() + + return(0); + +error: + H5E_BEGIN_TRY { + if(fh) + H5HF_close(fh, H5P_DATASET_XFER_DEFAULT); + if(fh2) + H5HF_close(fh2, H5P_DATASET_XFER_DEFAULT); + H5Fclose(file); + } H5E_END_TRY; + return(1); +} /* test_delete_open() */ + + +/*------------------------------------------------------------------------- * Function: test_id_limits * * Purpose: Test limits for heap ID lengths @@ -14989,6 +15138,7 @@ error: } /* test_random_pow2() */ #endif /* QAK */ +#ifndef QAK /*------------------------------------------------------------------------- * Function: test_write @@ -15194,6 +15344,7 @@ error: } H5E_END_TRY; return(1); } /* test_write() */ +#endif /* QAK */ #ifndef QAK @@ -15453,6 +15604,7 @@ curr_test = FHEAP_TEST_NORMAL; nerrors += test_create(fapl, &small_cparam, &tparam); nerrors += test_reopen(fapl, &small_cparam, &tparam); nerrors += test_open_twice(fapl, &small_cparam, &tparam); + nerrors += test_delete_open(fapl, &small_cparam, &tparam); nerrors += test_id_limits(fapl, &small_cparam); nerrors += test_filtered_create(fapl, &small_cparam); @@ -15812,6 +15964,7 @@ HDfprintf(stderr, "Uncomment tests!\n"); HDfprintf(stderr, "Uncomment tests!\n"); #endif /* QAK */ +#ifndef QAK /* Test object writing support */ /* Basic object writing */ @@ -15823,6 +15976,9 @@ HDfprintf(stderr, "Uncomment tests!\n"); /* Reset block compression */ tparam.comp = FHEAP_TEST_NO_COMPRESS; +#else /* QAK */ +HDfprintf(stderr, "Uncomment tests!\n"); +#endif /* QAK */ #ifndef QAK } /* end for */ #endif /* QAK */ -- cgit v0.12