1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 * Copyright by The HDF Group. * 3 * Copyright by the Board of Trustees of the University of Illinois. * 4 * All rights reserved. * 5 * * 6 * This file is part of HDF5. The full HDF5 copyright notice, including * 7 * terms governing use, modification, and redistribution, is contained in * 8 * the COPYING file, which can be found at the root of the source code * 9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * 10 * If you do not have access to either file, you may request a copy from * 11 * help@hdfgroup.org. * 12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 13 14 /*------------------------------------------------------------------------- 15 * 16 * Created: H5HL.c 17 * Jul 16 1997 18 * Robb Matzke <matzke@llnl.gov> 19 * 20 * Purpose: Heap functions for the local heaps used by symbol 21 * tables to store names (among other things). 22 * 23 *------------------------------------------------------------------------- 24 */ 25 26 /****************/ 27 /* Module Setup */ 28 /****************/ 29 30 #include "H5HLmodule.h" /* This source code file is part of the H5HL module */ 31 32 33 /***********/ 34 /* Headers */ 35 /***********/ 36 #include "H5private.h" /* Generic Functions */ 37 #include "H5Eprivate.h" /* Error handling */ 38 #include "H5Fprivate.h" /* File access */ 39 #include "H5HLpkg.h" /* Local Heaps */ 40 #include "H5MFprivate.h" /* File memory management */ 41 42 43 /****************/ 44 /* Local Macros */ 45 /****************/ 46 47 #define H5HL_MIN_HEAP 128 /* Minimum size to reduce heap buffer to */ 48 49 50 /******************/ 51 /* Local Typedefs */ 52 /******************/ 53 54 55 /********************/ 56 /* Package Typedefs */ 57 /********************/ 58 59 60 /********************/ 61 /* Local Prototypes */ 62 /********************/ 63 64 static H5HL_free_t *H5HL__remove_free(H5HL_t *heap, H5HL_free_t *fl); 65 static herr_t H5HL__minimize_heap_space(H5F_t *f, hid_t dxpl_id, H5HL_t *heap); 66 static herr_t H5HL__dirty(H5HL_t *heap); 67 68 69 /*********************/ 70 /* Package Variables */ 71 /*********************/ 72 73 /* Package initialization variable */ 74 hbool_t H5_PKG_INIT_VAR = FALSE; 75 76 /* Declare a free list to manage the H5HL_free_t struct */ 77 H5FL_DEFINE(H5HL_free_t); 78 79 /* Declare a PQ free list to manage the heap chunk information */ 80 H5FL_BLK_DEFINE(lheap_chunk); 81 82 83 /*****************************/ 84 /* Library Private Variables */ 85 /*****************************/ 86 87 88 /*******************/ 89 /* Local Variables */ 90 /*******************/ 91 92 93 94 /*------------------------------------------------------------------------- 95 * Function: H5HL_create 96 * 97 * Purpose: Creates a new heap data structure on disk and caches it 98 * in memory. SIZE_HINT is a hint for the initial size of the 99 * data area of the heap. If size hint is invalid then a 100 * reasonable (but probably not optimal) size will be chosen. 101 * 102 * Return: Success: SUCCEED. The file address of new heap is 103 * returned through the ADDR argument. 104 * Failure: FAIL. addr_p will be HADDR_UNDEF. 105 * 106 * Programmer: Robb Matzke 107 * Jul 16 1997 108 * 109 *------------------------------------------------------------------------- 110 */ 111 BEGIN_FUNC(PRIV, ERR, 112 herr_t, SUCCEED, FAIL, 113 H5HL_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, haddr_t *addr_p/*out*/)) 114 115 H5HL_t *heap = NULL; /* Heap created */ 116 H5HL_prfx_t *prfx = NULL; /* Heap prefix */ 117 hsize_t total_size = 0; /* Total heap size on disk */ 118 119 /* check arguments */ 120 HDassert(f); 121 HDassert(addr_p); 122 123 /* Adjust size hint as necessary */ 124 if(size_hint && size_hint < H5HL_SIZEOF_FREE(f)) 125 size_hint = H5HL_SIZEOF_FREE(f); 126 size_hint = H5HL_ALIGN(size_hint); 127 128 /* Allocate new heap structure */ 129 if(NULL == (heap = H5HL__new(H5F_SIZEOF_SIZE(f), H5F_SIZEOF_ADDR(f), H5HL_SIZEOF_HDR(f)))) 130 H5E_THROW(H5E_CANTALLOC, "can't allocate new heap struct"); 131 132 /* Allocate file space */ 133 total_size = heap->prfx_size + size_hint; 134 if(HADDR_UNDEF == (heap->prfx_addr = H5MF_alloc(f, H5FD_MEM_LHEAP, dxpl_id, total_size))) 135 H5E_THROW(H5E_CANTALLOC, "unable to allocate file memory"); 136 137 /* Initialize info */ 138 heap->single_cache_obj = TRUE; 139 heap->dblk_addr = heap->prfx_addr + (hsize_t)heap->prfx_size; 140 heap->dblk_size = size_hint; 141 if(size_hint) 142 if(NULL == (heap->dblk_image = H5FL_BLK_CALLOC(lheap_chunk, size_hint))) 143 H5E_THROW(H5E_CANTALLOC, "memory allocation failed"); 144 145 /* free list */ 146 if(size_hint) { 147 if(NULL == (heap->freelist = H5FL_MALLOC(H5HL_free_t))) 148 H5E_THROW(H5E_CANTALLOC, "memory allocation failed"); 149 heap->freelist->offset = 0; 150 heap->freelist->size = size_hint; 151 heap->freelist->prev = heap->freelist->next = NULL; 152 heap->free_block = 0; 153 } /* end if */ 154 else { 155 heap->freelist = NULL; 156 heap->free_block = H5HL_FREE_NULL; 157 } /* end else */ 158 159 /* Allocate the heap prefix */ 160 if(NULL == (prfx = H5HL__prfx_new(heap))) 161 H5E_THROW(H5E_CANTALLOC, "memory allocation failed"); 162 163 /* Add to cache */ 164 if(FAIL == H5AC_insert_entry(f, dxpl_id, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, H5AC__NO_FLAGS_SET)) 165 H5E_THROW(H5E_CANTINIT, "unable to cache local heap prefix"); 166 167 /* Set address to return */ 168 *addr_p = heap->prfx_addr; 169 170 CATCH 171 if(ret_value < 0) { 172 *addr_p = HADDR_UNDEF; 173 if(prfx) { 174 if(FAIL == H5HL__prfx_dest(prfx)) 175 H5E_THROW(H5E_CANTFREE, "unable to destroy local heap prefix"); 176 } /* end if */ 177 else { 178 if(heap) { 179 if(H5F_addr_defined(heap->prfx_addr)) 180 if(FAIL == H5MF_xfree(f, H5FD_MEM_LHEAP, dxpl_id, heap->prfx_addr, total_size)) 181 H5E_THROW(H5E_CANTFREE, "can't release heap data?"); 182 if(FAIL == H5HL__dest(heap)) 183 H5E_THROW(H5E_CANTFREE, "unable to destroy local heap"); 184 } /* end if */ 185 } /* end else */ 186 } /* end if */ 187 188 END_FUNC(PRIV) /* end H5HL_create() */ 189 190 191 /*------------------------------------------------------------------------- 192 * Function: H5HL__minimize_heap_space 193 * 194 * Purpose: Go through the heap's freelist and determine if we can 195 * eliminate the free blocks at the tail of the buffer. 196 * 197 * Return: SUCCEED/FAIL 198 * 199 * Programmer: Bill Wendling 200 * Sept. 16, 2003 201 * 202 *------------------------------------------------------------------------- 203 */ 204 BEGIN_FUNC(STATIC, ERR, 205 herr_t, SUCCEED, FAIL, 206 H5HL__minimize_heap_space(H5F_t *f, hid_t dxpl_id, H5HL_t *heap)) 207 208 size_t new_heap_size = heap->dblk_size; /* New size of heap */ 209 210 /* check args */ 211 HDassert(f); 212 HDassert(heap); 213 214 /* 215 * Check to see if we can reduce the size of the heap in memory by 216 * eliminating free blocks at the tail of the buffer before flushing the 217 * buffer out. 218 */ 219 if(heap->freelist) { 220 H5HL_free_t *tmp_fl; 221 H5HL_free_t *last_fl = NULL; 222 223 /* Search for a free block at the end of the buffer */ 224 for(tmp_fl = heap->freelist; tmp_fl; tmp_fl = tmp_fl->next) 225 /* Check if the end of this free block is at the end of the buffer */ 226 if(tmp_fl->offset + tmp_fl->size == heap->dblk_size) { 227 last_fl = tmp_fl; 228 break; 229 } /* end if */ 230 231 /* 232 * Found free block at the end of the buffer, decide what to do 233 * about it 234 */ 235 if(last_fl) { 236 /* 237 * If the last free block's size is more than half the memory 238 * buffer size (and the memory buffer is larger than the 239 * minimum size), reduce or eliminate it. 240 */ 241 if(last_fl->size >= (heap->dblk_size / 2) && heap->dblk_size > H5HL_MIN_HEAP) { 242 /* 243 * Reduce size of buffer until it's too small or would 244 * eliminate the free block 245 */ 246 while(new_heap_size > H5HL_MIN_HEAP && 247 new_heap_size >= (last_fl->offset + H5HL_SIZEOF_FREE(f))) 248 new_heap_size /= 2; 249 250 /* 251 * Check if reducing the memory buffer size would 252 * eliminate the free block 253 */ 254 if(new_heap_size < (last_fl->offset + H5HL_SIZEOF_FREE(f))) { 255 /* Check if this is the only block on the free list */ 256 if(last_fl->prev == NULL && last_fl->next == NULL) { 257 /* Double the new memory size */ 258 new_heap_size *= 2; 259 260 /* Truncate the free block */ 261 last_fl->size = H5HL_ALIGN(new_heap_size - last_fl->offset); 262 new_heap_size = last_fl->offset + last_fl->size; 263 HDassert(last_fl->size >= H5HL_SIZEOF_FREE(f)); 264 } /* end if */ 265 else { 266 /* 267 * Set the size of the memory buffer to the start 268 * of the free list 269 */ 270 new_heap_size = last_fl->offset; 271 272 /* Eliminate the free block from the list */ 273 last_fl = H5HL__remove_free(heap, last_fl); 274 } /* end else */ 275 } /* end if */ 276 else { 277 /* Truncate the free block */ 278 last_fl->size = H5HL_ALIGN(new_heap_size - last_fl->offset); 279 new_heap_size = last_fl->offset + last_fl->size; 280 HDassert(last_fl->size >= H5HL_SIZEOF_FREE(f)); 281 HDassert(last_fl->size == H5HL_ALIGN(last_fl->size)); 282 } /* end else */ 283 } /* end if */ 284 } /* end if */ 285 } /* end if */ 286 287 /* 288 * If the heap grew smaller than disk storage then move the 289 * data segment of the heap to another contiguous block of disk 290 * storage. 291 */ 292 if(new_heap_size != heap->dblk_size) { 293 HDassert(new_heap_size < heap->dblk_size); 294 295 /* Resize the memory buffer */ 296 if(NULL == (heap->dblk_image = H5FL_BLK_REALLOC(lheap_chunk, heap->dblk_image, new_heap_size))) 297 H5E_THROW(H5E_CANTALLOC, "memory allocation failed"); 298 299 /* Reallocate data block in file */ 300 if(FAIL == H5HL__dblk_realloc(f, dxpl_id, heap, new_heap_size)) 301 H5E_THROW(H5E_CANTRESIZE, "reallocating data block failed"); 302 } /* end if */ 303 304 CATCH 305 /* No special processing on errors */ 306 307 END_FUNC(STATIC) /* H5HL__minimize_heap_space() */ 308 309 310 /*------------------------------------------------------------------------- 311 * Function: H5HL_protect 312 * 313 * Purpose: This function is a wrapper for the H5AC_protect call. 314 * 315 * Return: Success: Non-NULL pointer to the local heap prefix. 316 * Failure: NULL 317 * 318 * Programmer: Bill Wendling 319 * Sept. 17, 2003 320 * 321 *------------------------------------------------------------------------- 322 */ 323 BEGIN_FUNC(PRIV, ERR, 324 H5HL_t *, NULL, NULL, 325 H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags)) 326 327 H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */ 328 H5HL_prfx_t *prfx = NULL; /* Local heap prefix */ 329 H5HL_dblk_t *dblk = NULL; /* Local heap data block */ 330 H5HL_t *heap = NULL; /* Heap data structure */ 331 unsigned prfx_cache_flags = H5AC__NO_FLAGS_SET; /* Cache flags for unprotecting prefix entry */ 332 unsigned dblk_cache_flags = H5AC__NO_FLAGS_SET; /* Cache flags for unprotecting data block entry */ 333 334 /* check arguments */ 335 HDassert(f); 336 HDassert(H5F_addr_defined(addr)); 337 338 /* only the H5AC__READ_ONLY_FLAG may appear in flags */ 339 HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); 340 341 /* Construct the user data for protect callback */ 342 prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); 343 prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); 344 prfx_udata.prfx_addr = addr; 345 prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); 346 347 /* Protect the local heap prefix */ 348 if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, flags))) 349 H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix"); 350 351 /* Get the pointer to the heap */ 352 heap = prfx->heap; 353 354 /* Check if the heap is already pinned in memory */ 355 /* (for re-entrant situation) */ 356 if(heap->prots == 0) { 357 /* Check if heap has separate data block */ 358 if(heap->single_cache_obj) 359 /* Set the flag for pinning the prefix when unprotecting it */ 360 prfx_cache_flags |= H5AC__PIN_ENTRY_FLAG; 361 else { 362 /* Protect the local heap data block */ 363 if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, heap, flags))) 364 H5E_THROW(H5E_CANTPROTECT, "unable to load heap data block"); 365 366 /* Set the flag for pinning the data block when unprotecting it */ 367 dblk_cache_flags |= H5AC__PIN_ENTRY_FLAG; 368 } /* end if */ 369 } /* end if */ 370 371 /* Increment # of times heap is protected */ 372 heap->prots++; 373 374 /* Set return value */ 375 ret_value = heap; 376 377 CATCH 378 /* Release the prefix from the cache, now pinned */ 379 if(prfx && heap && H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, prfx_cache_flags) < 0) 380 H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap prefix"); 381 382 /* Release the data block from the cache, now pinned */ 383 if(dblk && heap && H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, dblk, dblk_cache_flags) < 0) 384 H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap data block"); 385 386 END_FUNC(PRIV) /* end H5HL_protect() */ 387 388 389 /*------------------------------------------------------------------------- 390 * Function: H5HL_offset_into 391 * 392 * Purpose: Called directly after the call to H5HL_protect so that 393 * a pointer to the object in the heap can be obtained. 394 * 395 * Return: Success: Valid pointer. 396 * Failure: Can't fail 397 * 398 * Programmer: Bill Wendling 399 * Sept. 17, 2003 400 * 401 *------------------------------------------------------------------------- 402 */ 403 BEGIN_FUNC(PRIV, NOERR, 404 void *, NULL, -, 405 H5HL_offset_into(const H5HL_t *heap, size_t offset)) 406 407 /* Sanity check */ 408 HDassert(heap); 409 HDassert(offset < heap->dblk_size); 410 411 ret_value = heap->dblk_image + offset; 412 413 END_FUNC(PRIV) /* end H5HL_offset_into() */ 414 415 416 /*------------------------------------------------------------------------- 417 * Function: H5HL_unprotect 418 * 419 * Purpose: Unprotect the data retrieved by the H5HL_protect call. 420 * 421 * Return: SUCCEED/FAIL 422 * 423 * Programmer: Bill Wendling 424 * Sept. 17, 2003 425 * 426 *------------------------------------------------------------------------- 427 */ 428 BEGIN_FUNC(PRIV, ERR, 429 herr_t, SUCCEED, FAIL, 430 H5HL_unprotect(H5HL_t *heap)) 431 432 /* check arguments */ 433 HDassert(heap); 434 435 /* Decrement # of times heap is protected */ 436 heap->prots--; 437 438 /* Check for last unprotection of heap */ 439 if(heap->prots == 0) { 440 /* Check for separate heap data block */ 441 if(heap->single_cache_obj) { 442 /* Mark local heap prefix as evictable again */ 443 if(FAIL == H5AC_unpin_entry(heap->prfx)) 444 H5E_THROW(H5E_CANTUNPIN, "unable to unpin local heap data block"); 445 } /* end if */ 446 else { 447 /* Sanity check */ 448 HDassert(heap->dblk); 449 450 /* Mark local heap data block as evictable again */ 451 /* (data block still pins prefix) */ 452 if(FAIL == H5AC_unpin_entry(heap->dblk)) 453 H5E_THROW(H5E_CANTUNPIN, "unable to unpin local heap data block"); 454 } /* end else */ 455 } /* end if */ 456 457 CATCH 458 /* No special processing on errors */ 459 460 END_FUNC(PRIV) /* end H5HL_unprotect() */ 461 462 463 /*------------------------------------------------------------------------- 464 * Function: H5HL__remove_free 465 * 466 * Purpose: Removes free list element FL from the specified heap and 467 * frees it. 468 * 469 * Return: NULL 470 * 471 * Programmer: Robb Matzke 472 * Jul 17 1997 473 * 474 *------------------------------------------------------------------------- 475 */ 476 BEGIN_FUNC(STATIC, NOERR, 477 H5HL_free_t *, NULL, -, 478 H5HL__remove_free(H5HL_t *heap, H5HL_free_t *fl)) 479 480 if(fl->prev) 481 fl->prev->next = fl->next; 482 if(fl->next) 483 fl->next->prev = fl->prev; 484 485 if(!fl->prev) 486 heap->freelist = fl->next; 487 488 /* H5FL_FREE always returns NULL so we can't check for errors */ 489 ret_value = (H5HL_free_t *)H5FL_FREE(H5HL_free_t, fl); 490 491 END_FUNC(STATIC) /* end H5HL__remove_free() */ 492 493 494 /*------------------------------------------------------------------------- 495 * Function: H5HL__dirty 496 * 497 * Purpose: Mark heap as dirty 498 * 499 * Return: SUCCEED/FAIL 500 * 501 * Programmer: Quincey Koziol 502 * Oct 12 2008 503 * 504 *------------------------------------------------------------------------- 505 */ 506 BEGIN_FUNC(STATIC, ERR, 507 herr_t, SUCCEED, FAIL, 508 H5HL__dirty(H5HL_t *heap)) 509 510 /* check arguments */ 511 HDassert(heap); 512 HDassert(heap->prfx); 513 514 /* Mark heap data block as dirty, if there is one */ 515 if(!heap->single_cache_obj) { 516 /* Sanity check */ 517 HDassert(heap->dblk); 518 519 if(FAIL == H5AC_mark_entry_dirty(heap->dblk)) 520 H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark heap data block as dirty"); 521 } /* end if */ 522 523 /* Mark heap prefix as dirty */ 524 if(FAIL == H5AC_mark_entry_dirty(heap->prfx)) 525 H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark heap prefix as dirty"); 526 527 CATCH 528 /* No special processing on errors */ 529 530 END_FUNC(STATIC) /* end H5HL__dirty() */ 531 532 533 /*------------------------------------------------------------------------- 534 * Function: H5HL_insert 535 * 536 * Purpose: Inserts a new item into the heap. 537 * 538 * Return: Success: Offset of new item within heap. 539 * Failure: UFAIL 540 * 541 * Programmer: Robb Matzke 542 * Jul 17 1997 543 * 544 *------------------------------------------------------------------------- 545 */ 546 BEGIN_FUNC(PRIV, ERR, 547 size_t, UFAIL, UFAIL, 548 H5HL_insert(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t buf_size, const void *buf)) 549 550 H5HL_free_t *fl = NULL, *last_fl = NULL; 551 size_t offset = 0; 552 size_t need_size; 553 hbool_t found; 554 555 /* check arguments */ 556 HDassert(f); 557 HDassert(heap); 558 HDassert(buf_size > 0); 559 HDassert(buf); 560 561 /* Mark heap as dirty in cache */ 562 /* (A bit early in the process, but it's difficult to determine in the 563 * code below where to mark the heap as dirty, especially in error cases, 564 * so we just accept that an extra flush of the heap info could occur 565 * if an error occurs -QAK) 566 */ 567 if(FAIL == H5HL__dirty(heap)) 568 H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark heap as dirty"); 569 570 /* 571 * In order to keep the free list descriptors aligned on word boundaries, 572 * whatever that might mean, we round the size up to the next multiple of 573 * a word. 574 */ 575 need_size = H5HL_ALIGN(buf_size); 576 577 /* 578 * Look for a free slot large enough for this object and which would 579 * leave zero or at least H5G_SIZEOF_FREE bytes left over. 580 */ 581 for(fl = heap->freelist, found = FALSE; fl; fl = fl->next) { 582 if(fl->size > need_size && fl->size - need_size >= H5HL_SIZEOF_FREE(f)) { 583 /* a big enough free block was found */ 584 offset = fl->offset; 585 fl->offset += need_size; 586 fl->size -= need_size; 587 HDassert(fl->offset == H5HL_ALIGN(fl->offset)); 588 HDassert(fl->size == H5HL_ALIGN(fl->size)); 589 found = TRUE; 590 break; 591 } else if(fl->size == need_size) { 592 /* free block of exact size found */ 593 offset = fl->offset; 594 fl = H5HL__remove_free(heap, fl); 595 found = TRUE; 596 break; 597 } else if(!last_fl || last_fl->offset < fl->offset) { 598 /* track free space that's closest to end of heap */ 599 last_fl = fl; 600 } 601 } /* end for */ 602 603 /* 604 * If no free chunk was large enough, then allocate more space and 605 * add it to the free list. If the heap ends with a free chunk, we 606 * can extend that free chunk. Otherwise we'll have to make another 607 * free chunk. If the heap must expand, we double its size. 608 */ 609 if(found == FALSE) { 610 size_t need_more; /* How much more space we need */ 611 size_t new_dblk_size; /* Final size of space allocated for heap data block */ 612 size_t old_dblk_size; /* Previous size of space allocated for heap data block */ 613 htri_t was_extended; /* Whether the local heap's data segment on disk was extended */ 614 615 /* At least double the heap's size, making certain there's enough room 616 * for the new object */ 617 need_more = MAX(need_size, heap->dblk_size); 618 619 /* If there is no last free block or it's not at the end of the heap, 620 * and the amount of space to allocate is not big enough to include at 621 * least the new object and a free-list info, trim down the amount of 622 * space requested to just the amount of space needed. (Generally 623 * speaking, this only occurs when the heap is small -QAK) 624 */ 625 if(!(last_fl && last_fl->offset + last_fl->size == heap->dblk_size) 626 && (need_more < (need_size + H5HL_SIZEOF_FREE(f)))) 627 need_more = need_size; 628 629 new_dblk_size = heap->dblk_size + need_more; 630 HDassert(heap->dblk_size < new_dblk_size); 631 old_dblk_size = heap->dblk_size; 632 H5_CHECK_OVERFLOW(heap->dblk_size, size_t, hsize_t); 633 H5_CHECK_OVERFLOW(new_dblk_size, size_t, hsize_t); 634 635 /* Extend current heap if possible */ 636 was_extended = H5MF_try_extend(f, dxpl_id, H5FD_MEM_LHEAP, heap->dblk_addr, (hsize_t)(heap->dblk_size), (hsize_t)need_more); 637 if(FAIL == was_extended) 638 H5E_THROW(H5E_CANTEXTEND, "error trying to extend heap"); 639 640 /* Check if we extended the heap data block in file */ 641 if(was_extended == TRUE) { 642 /* Check for prefix & data block contiguous */ 643 if(heap->single_cache_obj) { 644 /* Resize prefix+data block */ 645 if(FAIL == H5AC_resize_entry(heap->prfx, (size_t)(heap->prfx_size + new_dblk_size))) 646 H5E_THROW(H5E_CANTRESIZE, "unable to resize heap prefix in cache"); 647 } /* end if */ 648 else { 649 /* Resize 'standalone' data block */ 650 if(FAIL == H5AC_resize_entry(heap->dblk, (size_t)new_dblk_size)) 651 H5E_THROW(H5E_CANTRESIZE, "unable to resize heap data block in cache"); 652 } /* end else */ 653 654 /* Note new size */ 655 heap->dblk_size = new_dblk_size; 656 } /* end if */ 657 else { /* ...if we can't, allocate a new chunk & release the old */ 658 /* Reallocate data block in file */ 659 if(FAIL == H5HL__dblk_realloc(f, dxpl_id, heap, new_dblk_size)) 660 H5E_THROW(H5E_CANTRESIZE, "reallocating data block failed"); 661 } /* end if */ 662 663 /* If the last free list in the heap is at the end of the heap, extend it */ 664 if(last_fl && last_fl->offset + last_fl->size == old_dblk_size) { 665 /* 666 * Increase the size of the last free block. 667 */ 668 offset = last_fl->offset; 669 last_fl->offset += need_size; 670 last_fl->size += need_more - need_size; 671 HDassert(last_fl->offset == H5HL_ALIGN(last_fl->offset)); 672 HDassert(last_fl->size == H5HL_ALIGN(last_fl->size)); 673 674 if (last_fl->size < H5HL_SIZEOF_FREE(f)) { 675 #ifdef H5HL_DEBUG 676 if (H5DEBUG(HL) && last_fl->size) { 677 HDfprintf(H5DEBUG(HL), "H5HL: lost %lu bytes at line %d\n", 678 (unsigned long)(last_fl->size), __LINE__); 679 } 680 #endif 681 last_fl = H5HL__remove_free(heap, last_fl); 682 } 683 } /* end if */ 684 else { 685 /* 686 * Create a new free list element large enough that we can 687 * take some space out of it right away. 688 */ 689 offset = old_dblk_size; 690 if(need_more - need_size >= H5HL_SIZEOF_FREE(f)) { 691 if(NULL == (fl = H5FL_MALLOC(H5HL_free_t))) 692 H5E_THROW(H5E_CANTALLOC, "memory allocation failed"); 693 fl->offset = old_dblk_size + need_size; 694 fl->size = need_more - need_size; 695 HDassert(fl->offset == H5HL_ALIGN(fl->offset)); 696 HDassert(fl->size == H5HL_ALIGN(fl->size)); 697 fl->prev = NULL; 698 fl->next = heap->freelist; 699 if(heap->freelist) 700 heap->freelist->prev = fl; 701 heap->freelist = fl; 702 #ifdef H5HL_DEBUG 703 } else if (H5DEBUG(HL) && need_more > need_size) { 704 HDfprintf(H5DEBUG(HL), "H5HL_insert: lost %lu bytes at line %d\n", 705 (unsigned long)(need_more - need_size), __LINE__); 706 #endif 707 } 708 } /* end else */ 709 710 #ifdef H5HL_DEBUG 711 if (H5DEBUG(HL)) { 712 HDfprintf(H5DEBUG(HL), "H5HL: resize mem buf from %lu to %lu bytes\n", 713 (unsigned long)(old_dblk_size), 714 (unsigned long)(old_dblk_size + need_more)); 715 } 716 #endif 717 if(NULL == (heap->dblk_image = H5FL_BLK_REALLOC(lheap_chunk, heap->dblk_image, heap->dblk_size))) 718 H5E_THROW(H5E_CANTALLOC, "memory allocation failed"); 719 720 /* Clear new section so junk doesn't appear in the file */ 721 /* (Avoid clearing section which will be overwritten with newly inserted data) */ 722 HDmemset(heap->dblk_image + offset + buf_size, 0, (new_dblk_size - (offset + buf_size))); 723 } /* end if */ 724 725 /* Copy the data into the heap */ 726 HDmemcpy(heap->dblk_image + offset, buf, buf_size); 727 728 /* Set return value */ 729 ret_value = offset; 730 731 CATCH 732 /* No special processing on errors */ 733 734 END_FUNC(PRIV) /* H5HL_insert() */ 735 736 737 /*------------------------------------------------------------------------- 738 * Function: H5HL_remove 739 * 740 * Purpose: Removes an object or part of an object from the heap at 741 * address ADDR of file F. The object (or part) to remove 742 * begins at byte OFFSET from the beginning of the heap and 743 * continues for SIZE bytes. 744 * 745 * Once part of an object is removed, one must not attempt 746 * to access that part. Removing the beginning of an object 747 * results in the object OFFSET increasing by the amount 748 * truncated. Removing the end of an object results in 749 * object truncation. Removing the middle of an object results 750 * in two separate objects, one at the original offset and 751 * one at the first offset past the removed portion. 752 * 753 * Return: SUCCEED/FAIL 754 * 755 * Programmer: Robb Matzke 756 * Jul 16 1997 757 * 758 *------------------------------------------------------------------------- 759 */ 760 BEGIN_FUNC(PRIV, ERR, 761 herr_t, SUCCEED, FAIL, 762 H5HL_remove(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t offset, size_t size)) 763 764 H5HL_free_t *fl = NULL; 765 766 /* check arguments */ 767 HDassert(f); 768 HDassert(heap); 769 HDassert(size > 0); 770 HDassert(offset == H5HL_ALIGN(offset)); 771 772 size = H5HL_ALIGN(size); 773 774 HDassert(offset < heap->dblk_size); 775 HDassert(offset + size <= heap->dblk_size); 776 777 /* Mark heap as dirty in cache */ 778 /* (A bit early in the process, but it's difficult to determine in the 779 * code below where to mark the heap as dirty, especially in error cases, 780 * so we just accept that an extra flush of the heap info could occur 781 * if an error occurs -QAK) 782 */ 783 if(FAIL == H5HL__dirty(heap)) 784 H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark heap as dirty"); 785 786 /* 787 * Check if this chunk can be prepended or appended to an already 788 * free chunk. It might also fall between two chunks in such a way 789 * that all three chunks can be combined into one. 790 */ 791 fl = heap->freelist; 792 while(fl) { 793 H5HL_free_t *fl2 = NULL; 794 795 if((offset + size) == fl->offset) { 796 fl->offset = offset; 797 fl->size += size; 798 HDassert(fl->offset == H5HL_ALIGN(fl->offset)); 799 HDassert(fl->size == H5HL_ALIGN(fl->size)); 800 fl2 = fl->next; 801 while(fl2) { 802 if((fl2->offset + fl2->size) == fl->offset) { 803 fl->offset = fl2->offset; 804 fl->size += fl2->size; 805 HDassert(fl->offset == H5HL_ALIGN(fl->offset)); 806 HDassert(fl->size == H5HL_ALIGN(fl->size)); 807 fl2 = H5HL__remove_free(heap, fl2); 808 if(((fl->offset + fl->size) == heap->dblk_size) && 809 ((2 * fl->size) > heap->dblk_size)) { 810 if(FAIL == H5HL__minimize_heap_space(f, dxpl_id, heap)) 811 H5E_THROW(H5E_CANTFREE, "heap size minimization failed"); 812 } 813 H5_LEAVE(SUCCEED); 814 } 815 fl2 = fl2->next; 816 } 817 if(((fl->offset + fl->size) == heap->dblk_size) && 818 ((2 * fl->size) > heap->dblk_size)) { 819 if(FAIL == H5HL__minimize_heap_space(f, dxpl_id, heap)) 820 H5E_THROW(H5E_CANTFREE, "heap size minimization failed"); 821 } 822 H5_LEAVE(SUCCEED); 823 } else if(fl->offset + fl->size == offset) { 824 fl->size += size; 825 fl2 = fl->next; 826 HDassert(fl->size == H5HL_ALIGN(fl->size)); 827 while(fl2) { 828 if(fl->offset + fl->size == fl2->offset) { 829 fl->size += fl2->size; 830 HDassert(fl->size == H5HL_ALIGN(fl->size)); 831 fl2 = H5HL__remove_free(heap, fl2); 832 if(((fl->offset + fl->size) == heap->dblk_size) && 833 ((2 * fl->size) > heap->dblk_size)) { 834 if(FAIL == H5HL__minimize_heap_space(f, dxpl_id, heap)) 835 H5E_THROW(H5E_CANTFREE, "heap size minimization failed"); 836 } /* end if */ 837 H5_LEAVE(SUCCEED); 838 } /* end if */ 839 fl2 = fl2->next; 840 } /* end while */ 841 if(((fl->offset + fl->size) == heap->dblk_size) && 842 ((2 * fl->size) > heap->dblk_size)) { 843 if(FAIL == H5HL__minimize_heap_space(f, dxpl_id, heap)) 844 H5E_THROW(H5E_CANTFREE, "heap size minimization failed"); 845 } /* end if */ 846 H5_LEAVE(SUCCEED); 847 } /* end if */ 848 fl = fl->next; 849 } /* end while */ 850 851 /* 852 * The amount which is being removed must be large enough to 853 * hold the free list data. If not, the freed chunk is forever 854 * lost. 855 */ 856 if(size < H5HL_SIZEOF_FREE(f)) { 857 #ifdef H5HL_DEBUG 858 if(H5DEBUG(HL)) { 859 HDfprintf(H5DEBUG(HL), "H5HL: lost %lu bytes\n", (unsigned long) size); 860 } 861 #endif 862 H5_LEAVE(SUCCEED); 863 } /* end if */ 864 865 /* 866 * Add an entry to the free list. 867 */ 868 if(NULL == (fl = H5FL_MALLOC(H5HL_free_t))) 869 H5E_THROW(H5E_CANTALLOC, "memory allocation failed"); 870 fl->offset = offset; 871 fl->size = size; 872 HDassert(fl->offset == H5HL_ALIGN(fl->offset)); 873 HDassert(fl->size == H5HL_ALIGN(fl->size)); 874 fl->prev = NULL; 875 fl->next = heap->freelist; 876 if(heap->freelist) 877 heap->freelist->prev = fl; 878 heap->freelist = fl; 879 880 if(((fl->offset + fl->size) == heap->dblk_size) && 881 ((2 * fl->size) > heap->dblk_size)) { 882 if(FAIL == H5HL__minimize_heap_space(f, dxpl_id, heap)) 883 H5E_THROW(H5E_CANTFREE, "heap size minimization failed"); 884 } /* end if */ 885 886 CATCH 887 /* No special processing on exit */ 888 889 END_FUNC(PRIV) /* end H5HL_remove() */ 890 891 892 /*------------------------------------------------------------------------- 893 * Function: H5HL_delete 894 * 895 * Purpose: Deletes a local heap from disk, freeing disk space used. 896 * 897 * Return: SUCCEED/FAIL 898 * 899 * Programmer: Quincey Koziol 900 * Mar 22 2003 901 * 902 *------------------------------------------------------------------------- 903 */ 904 BEGIN_FUNC(PRIV, ERR, 905 herr_t, SUCCEED, FAIL, 906 H5HL_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr)) 907 908 H5HL_t *heap = NULL; /* Local heap to delete */ 909 H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */ 910 H5HL_prfx_t *prfx = NULL; /* Local heap prefix */ 911 H5HL_dblk_t *dblk = NULL; /* Local heap data block */ 912 unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting heap */ 913 914 /* check arguments */ 915 HDassert(f); 916 HDassert(H5F_addr_defined(addr)); 917 918 /* Construct the user data for protect callback */ 919 prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); 920 prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); 921 prfx_udata.prfx_addr = addr; 922 prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); 923 924 /* Protect the local heap prefix */ 925 if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__NO_FLAGS_SET))) 926 H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix"); 927 928 /* Get the pointer to the heap */ 929 heap = prfx->heap; 930 931 /* Check if heap has separate data block */ 932 if(!heap->single_cache_obj) 933 /* Protect the local heap data block */ 934 if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, heap, H5AC__NO_FLAGS_SET))) 935 H5E_THROW(H5E_CANTPROTECT, "unable to load heap data block"); 936 937 /* Set the flags for releasing the prefix and data block */ 938 cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; 939 940 CATCH 941 /* Release the data block from the cache, now deleted */ 942 if(dblk && heap && H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, dblk, cache_flags) < 0) 943 H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap data block"); 944 945 /* Release the prefix from the cache, now deleted */ 946 if(prfx && heap && H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, cache_flags) < 0) 947 H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap prefix"); 948 949 END_FUNC(PRIV) /* end H5HL_delete() */ 950 951 952 /*------------------------------------------------------------------------- 953 * Function: H5HL_get_size 954 * 955 * Purpose: Retrieves the current size of a heap 956 * 957 * Return: SUCCEED/FAIL 958 * 959 * Programmer: Quincey Koziol 960 * Nov 7 2005 961 * 962 *------------------------------------------------------------------------- 963 */ 964 BEGIN_FUNC(PRIV, ERR, 965 herr_t, SUCCEED, FAIL, 966 H5HL_get_size(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t *size)) 967 968 H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */ 969 H5HL_prfx_t *prfx = NULL; /* Local heap prefix */ 970 H5HL_t *heap; /* Heap data structure */ 971 972 /* check arguments */ 973 HDassert(f); 974 HDassert(H5F_addr_defined(addr)); 975 HDassert(size); 976 977 /* Construct the user data for protect callback */ 978 prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); 979 prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); 980 prfx_udata.prfx_addr = addr; 981 prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); 982 983 /* Protect the local heap prefix */ 984 if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__READ_ONLY_FLAG))) 985 H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix"); 986 987 /* Get the pointer to the heap */ 988 heap = prfx->heap; 989 990 /* Set the size to return */ 991 *size = heap->dblk_size; 992 993 CATCH 994 if(prfx && FAIL == H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, H5AC__NO_FLAGS_SET)) 995 H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap prefix"); 996 997 END_FUNC(PRIV) /* end H5HL_get_size() */ 998 999 1000 /*------------------------------------------------------------------------- 1001 * Function: H5HL_heapsize 1002 * 1003 * Purpose: Compute the size in bytes of the specified instance of 1004 * H5HL_t via H5HL_size() 1005 * 1006 * Return: SUCCEED/FAIL 1007 * 1008 * Programmer: Vailin Choi 1009 * June 19 2007 1010 * 1011 *------------------------------------------------------------------------- 1012 */ 1013 BEGIN_FUNC(PRIV, ERR, 1014 herr_t, SUCCEED, FAIL, 1015 H5HL_heapsize(H5F_t *f, hid_t dxpl_id, haddr_t addr, hsize_t *heap_size)) 1016 1017 H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */ 1018 H5HL_prfx_t *prfx = NULL; /* Local heap prefix */ 1019 H5HL_t *heap; /* Heap data structure */ 1020 1021 /* check arguments */ 1022 HDassert(f); 1023 HDassert(H5F_addr_defined(addr)); 1024 HDassert(heap_size); 1025 1026 /* Construct the user data for protect callback */ 1027 prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); 1028 prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); 1029 prfx_udata.prfx_addr = addr; 1030 prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); 1031 1032 /* Protect the local heap prefix */ 1033 if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__READ_ONLY_FLAG))) 1034 H5E_THROW(H5E_CANTPROTECT, "unable to load heap prefix"); 1035 1036 /* Get the pointer to the heap */ 1037 heap = prfx->heap; 1038 1039 /* Accumulate the size of the local heap */ 1040 *heap_size += (hsize_t)(heap->prfx_size + heap->dblk_size); 1041 1042 CATCH 1043 if(prfx && FAIL == H5AC_unprotect(f, dxpl_id, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, H5AC__NO_FLAGS_SET)) 1044 H5E_THROW(H5E_CANTUNPROTECT, "unable to release local heap prefix"); 1045 1046 END_FUNC(PRIV) /* end H5HL_heapsize() */ 1047 1048