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: H5EAiblock.c 17 * Sep 9 2008 18 * Quincey Koziol <koziol@hdfgroup.org> 19 * 20 * Purpose: Index block routines for extensible arrays. 21 * 22 *------------------------------------------------------------------------- 23 */ 24 25 /**********************/ 26 /* Module Declaration */ 27 /**********************/ 28 29 #include "H5EAmodule.h" /* This source code file is part of the H5EA module */ 30 31 32 /***********************/ 33 /* Other Packages Used */ 34 /***********************/ 35 36 37 /***********/ 38 /* Headers */ 39 /***********/ 40 #include "H5private.h" /* Generic Functions */ 41 #include "H5Eprivate.h" /* Error handling */ 42 #include "H5EApkg.h" /* Extensible Arrays */ 43 #include "H5FLprivate.h" /* Free Lists */ 44 #include "H5MFprivate.h" /* File memory management */ 45 #include "H5VMprivate.h" /* Vectors and arrays */ 46 47 48 /****************/ 49 /* Local Macros */ 50 /****************/ 51 52 53 /******************/ 54 /* Local Typedefs */ 55 /******************/ 56 57 58 /********************/ 59 /* Package Typedefs */ 60 /********************/ 61 62 63 /********************/ 64 /* Local Prototypes */ 65 /********************/ 66 67 68 /*********************/ 69 /* Package Variables */ 70 /*********************/ 71 72 73 /*****************************/ 74 /* Library Private Variables */ 75 /*****************************/ 76 77 78 /*******************/ 79 /* Local Variables */ 80 /*******************/ 81 82 /* Declare a free list to manage the H5EA_iblock_t struct */ 83 H5FL_DEFINE_STATIC(H5EA_iblock_t); 84 85 /* Declare a free list to manage the index block elements */ 86 H5FL_BLK_DEFINE_STATIC(idx_blk_elmt_buf); 87 88 /* Declare a free list to manage the haddr_t sequence information */ 89 H5FL_SEQ_DEFINE_STATIC(haddr_t); 90 91 92 93 /*------------------------------------------------------------------------- 94 * Function: H5EA__iblock_alloc 95 * 96 * Purpose: Allocate extensible array index block 97 * 98 * Return: Non-NULL pointer to index block on success/NULL on failure 99 * 100 * Programmer: Quincey Koziol 101 * koziol@hdfgroup.org 102 * Sep 9 2008 103 * 104 *------------------------------------------------------------------------- 105 */ 106 BEGIN_FUNC(PKG, ERR, 107 H5EA_iblock_t *, NULL, NULL, 108 H5EA__iblock_alloc(H5EA_hdr_t *hdr)) 109 110 /* Local variables */ 111 H5EA_iblock_t *iblock = NULL; /* Extensible array index block */ 112 113 /* Check arguments */ 114 HDassert(hdr); 115 116 /* Allocate memory for the index block */ 117 if(NULL == (iblock = H5FL_CALLOC(H5EA_iblock_t))) 118 H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array index block") 119 120 /* Share common array information */ 121 if(H5EA__hdr_incr(hdr) < 0) 122 H5E_THROW(H5E_CANTINC, "can't increment reference count on shared array header") 123 iblock->hdr = hdr; 124 125 /* Set non-zero internal fields */ 126 iblock->addr = HADDR_UNDEF; 127 128 /* Compute information */ 129 iblock->nsblks = H5EA_SBLK_FIRST_IDX(hdr->cparam.sup_blk_min_data_ptrs); 130 iblock->ndblk_addrs = 2 * ((size_t)hdr->cparam.sup_blk_min_data_ptrs - 1); 131 iblock->nsblk_addrs = hdr->nsblks - iblock->nsblks; 132 #ifdef QAK 133 HDfprintf(stderr, "%s: iblock->nsblks = %u\n", FUNC, iblock->nsblks); 134 HDfprintf(stderr, "%s: iblock->ndblk_addrs = %Zu\n", FUNC, iblock->ndblk_addrs); 135 HDfprintf(stderr, "%s: iblock->nsblk_addrs = %Zu\n", FUNC, iblock->nsblk_addrs); 136 #endif /* QAK */ 137 138 /* Allocate buffer for elements in index block */ 139 if(hdr->cparam.idx_blk_elmts > 0) 140 if(NULL == (iblock->elmts = H5FL_BLK_MALLOC(idx_blk_elmt_buf, (size_t)(hdr->cparam.idx_blk_elmts * hdr->cparam.cls->nat_elmt_size)))) 141 H5E_THROW(H5E_CANTALLOC, "memory allocation failed for index block data element buffer") 142 143 /* Allocate buffer for data block addresses in index block */ 144 if(iblock->ndblk_addrs > 0) 145 if(NULL == (iblock->dblk_addrs = H5FL_SEQ_MALLOC(haddr_t, iblock->ndblk_addrs))) 146 H5E_THROW(H5E_CANTALLOC, "memory allocation failed for index block data block addresses") 147 148 /* Allocate buffer for super block addresses in index block */ 149 if(iblock->nsblk_addrs > 0) 150 if(NULL == (iblock->sblk_addrs = H5FL_SEQ_MALLOC(haddr_t, iblock->nsblk_addrs))) 151 H5E_THROW(H5E_CANTALLOC, "memory allocation failed for index block super block addresses") 152 153 /* Set the return value */ 154 ret_value = iblock; 155 156 CATCH 157 if(!ret_value) 158 if(iblock && H5EA__iblock_dest(iblock) < 0) 159 H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array index block") 160 161 END_FUNC(PKG) /* end H5EA__iblock_alloc() */ 162 163 164 /*------------------------------------------------------------------------- 165 * Function: H5EA__iblock_create 166 * 167 * Purpose: Creates a new extensible array index block in the file 168 * 169 * Return: Valid file address on success/HADDR_UNDEF on failure 170 * 171 * Programmer: Quincey Koziol 172 * koziol@hdfgroup.org 173 * Sep 9 2008 174 * 175 *------------------------------------------------------------------------- 176 */ 177 BEGIN_FUNC(PKG, ERR, 178 haddr_t, HADDR_UNDEF, HADDR_UNDEF, 179 H5EA__iblock_create(H5EA_hdr_t *hdr, hbool_t *stats_changed)) 180 181 /* Local variables */ 182 H5EA_iblock_t *iblock = NULL; /* Extensible array index block */ 183 haddr_t iblock_addr; /* Extensible array index block address */ 184 hbool_t inserted = FALSE; /* Whether the header was inserted into cache */ 185 186 #ifdef QAK 187 HDfprintf(stderr, "%s: Called\n", FUNC); 188 #endif /* QAK */ 189 190 /* Sanity check */ 191 HDassert(hdr); 192 HDassert(stats_changed); 193 194 /* Allocate the index block */ 195 if(NULL == (iblock = H5EA__iblock_alloc(hdr))) 196 H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array index block") 197 198 /* Set size of index block on disk */ 199 iblock->size = H5EA_IBLOCK_SIZE(iblock); 200 #ifdef QAK 201 HDfprintf(stderr, "%s: iblock->size = %Zu\n", FUNC, iblock->size); 202 #endif /* QAK */ 203 204 /* Allocate space for the index block on disk */ 205 if(HADDR_UNDEF == (iblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_EARRAY_IBLOCK, (hsize_t)iblock->size))) 206 H5E_THROW(H5E_CANTALLOC, "file allocation failed for extensible array index block") 207 iblock->addr = iblock_addr; 208 209 /* Clear any elements in index block to fill value */ 210 if(hdr->cparam.idx_blk_elmts > 0) { 211 /* Call the class's 'fill' callback */ 212 if((hdr->cparam.cls->fill)(iblock->elmts, (size_t)hdr->cparam.idx_blk_elmts) < 0) 213 H5E_THROW(H5E_CANTSET, "can't set extensible array index block elements to class's fill value") 214 } /* end if */ 215 216 /* Reset any data block addresses in the index block */ 217 if(iblock->ndblk_addrs > 0) { 218 haddr_t tmp_addr = HADDR_UNDEF; /* Address value to fill data block addresses with */ 219 220 /* Set all the data block addresses to "undefined" address value */ 221 H5VM_array_fill(iblock->dblk_addrs, &tmp_addr, sizeof(haddr_t), iblock->ndblk_addrs); 222 } /* end if */ 223 224 /* Reset any super block addresses in the index block */ 225 if(iblock->nsblk_addrs > 0) { 226 haddr_t tmp_addr = HADDR_UNDEF; /* Address value to fill super block addresses with */ 227 228 /* Set all the super block addresses to "undefined" address value */ 229 H5VM_array_fill(iblock->sblk_addrs, &tmp_addr, sizeof(haddr_t), iblock->nsblk_addrs); 230 } /* end if */ 231 232 /* Cache the new extensible array index block */ 233 if(H5AC_insert_entry(hdr->f, H5AC_EARRAY_IBLOCK, iblock_addr, iblock, H5AC__NO_FLAGS_SET) < 0) 234 H5E_THROW(H5E_CANTINSERT, "can't add extensible array index block to cache") 235 inserted = TRUE; 236 237 /* Add index block as child of 'top' proxy */ 238 if(hdr->top_proxy) { 239 if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, iblock) < 0) 240 H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy") 241 iblock->top_proxy = hdr->top_proxy; 242 } /* end if */ 243 244 /* Update extensible array index block statistics */ 245 HDassert(0 == hdr->stats.computed.nindex_blks); 246 HDassert(0 == hdr->stats.computed.index_blk_size); 247 hdr->stats.computed.nindex_blks = 1; 248 hdr->stats.computed.index_blk_size = iblock->size; 249 250 /* Increment count of elements "realized" */ 251 hdr->stats.stored.nelmts += hdr->cparam.idx_blk_elmts; 252 253 /* Mark the statistics as changed */ 254 *stats_changed = TRUE; 255 256 /* Set address of index block to return */ 257 ret_value = iblock_addr; 258 259 CATCH 260 if(!H5F_addr_defined(ret_value)) 261 if(iblock) { 262 /* Remove from cache, if inserted */ 263 if(inserted) 264 if(H5AC_remove_entry(iblock) < 0) 265 H5E_THROW(H5E_CANTREMOVE, "unable to remove extensible array index block from cache") 266 267 /* Release index block's disk space */ 268 if(H5F_addr_defined(iblock->addr) && H5MF_xfree(hdr->f, H5FD_MEM_EARRAY_IBLOCK, iblock->addr, (hsize_t)iblock->size) < 0) 269 H5E_THROW(H5E_CANTFREE, "unable to release file space for extensible array index block") 270 271 /* Destroy index block */ 272 if(H5EA__iblock_dest(iblock) < 0) 273 H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array index block") 274 } /* end if */ 275 276 END_FUNC(PKG) /* end H5EA__iblock_create() */ 277 278 279 /*------------------------------------------------------------------------- 280 * Function: H5EA__iblock_protect 281 * 282 * Purpose: Convenience wrapper around protecting extensible array index block 283 * 284 * Return: Non-NULL pointer to index block on success/NULL on failure 285 * 286 * Programmer: Quincey Koziol 287 * koziol@hdfgroup.org 288 * Sep 9 2008 289 * 290 *------------------------------------------------------------------------- 291 */ 292 BEGIN_FUNC(PKG, ERR, 293 H5EA_iblock_t *, NULL, NULL, 294 H5EA__iblock_protect(H5EA_hdr_t *hdr, unsigned flags)) 295 296 /* Local variables */ 297 H5EA_iblock_t *iblock = NULL; /* Pointer to index block */ 298 299 #ifdef QAK 300 HDfprintf(stderr, "%s: Called\n", FUNC); 301 #endif /* QAK */ 302 303 /* Sanity check */ 304 HDassert(hdr); 305 306 /* only the H5AC__READ_ONLY_FLAG may be set */ 307 HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); 308 309 /* Protect the index block */ 310 if(NULL == (iblock = (H5EA_iblock_t *)H5AC_protect(hdr->f, H5AC_EARRAY_IBLOCK, hdr->idx_blk_addr, hdr, flags))) 311 H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr) 312 313 /* Create top proxy, if it doesn't exist */ 314 if(hdr->top_proxy && NULL == iblock->top_proxy) { 315 /* Add index block as child of 'top' proxy */ 316 if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, iblock) < 0) 317 H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy") 318 iblock->top_proxy = hdr->top_proxy; 319 } /* end if */ 320 321 /* Set return value */ 322 ret_value = iblock; 323 324 CATCH 325 /* Clean up on error */ 326 if(!ret_value) { 327 /* Release the index block, if it was protected */ 328 if(iblock && H5AC_unprotect(hdr->f, H5AC_EARRAY_IBLOCK, iblock->addr, iblock, H5AC__NO_FLAGS_SET) < 0) 329 H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array index block, address = %llu", (unsigned long long)iblock->addr) 330 } /* end if */ 331 332 END_FUNC(PKG) /* end H5EA__iblock_protect() */ 333 334 335 /*------------------------------------------------------------------------- 336 * Function: H5EA__iblock_unprotect 337 * 338 * Purpose: Convenience wrapper around unprotecting extensible array index block 339 * 340 * Return: Non-negative on success/Negative on failure 341 * 342 * Programmer: Quincey Koziol 343 * koziol@hdfgroup.org 344 * Sep 9 2008 345 * 346 *------------------------------------------------------------------------- 347 */ 348 BEGIN_FUNC(PKG, ERR, 349 herr_t, SUCCEED, FAIL, 350 H5EA__iblock_unprotect(H5EA_iblock_t *iblock, unsigned cache_flags)) 351 352 /* Local variables */ 353 354 #ifdef QAK 355 HDfprintf(stderr, "%s: Called\n", FUNC); 356 #endif /* QAK */ 357 358 /* Sanity check */ 359 HDassert(iblock); 360 361 /* Unprotect the index block */ 362 if(H5AC_unprotect(iblock->hdr->f, H5AC_EARRAY_IBLOCK, iblock->addr, iblock, cache_flags) < 0) 363 H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array index block, address = %llu", (unsigned long long)iblock->addr) 364 365 CATCH 366 367 END_FUNC(PKG) /* end H5EA__iblock_unprotect() */ 368 369 370 /*------------------------------------------------------------------------- 371 * Function: H5EA__iblock_delete 372 * 373 * Purpose: Delete index block 374 * 375 * Return: SUCCEED/FAIL 376 * 377 * Programmer: Quincey Koziol 378 * koziol@hdfgroup.org 379 * Sep 9 2008 380 * 381 *------------------------------------------------------------------------- 382 */ 383 BEGIN_FUNC(PKG, ERR, 384 herr_t, SUCCEED, FAIL, 385 H5EA__iblock_delete(H5EA_hdr_t *hdr)) 386 387 /* Local variables */ 388 H5EA_iblock_t *iblock = NULL; /* Pointer to index block */ 389 390 #ifdef QAK 391 HDfprintf(stderr, "%s: Called\n", FUNC); 392 #endif /* QAK */ 393 394 /* Sanity check */ 395 HDassert(hdr); 396 HDassert(H5F_addr_defined(hdr->idx_blk_addr)); 397 398 /* Protect index block */ 399 if(NULL == (iblock = H5EA__iblock_protect(hdr, H5AC__NO_FLAGS_SET))) 400 H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr) 401 402 /* Check for index block having data block pointers */ 403 if(iblock->ndblk_addrs > 0) { 404 unsigned sblk_idx; /* Current super block index */ 405 unsigned dblk_idx; /* Current data block index w/in super block */ 406 size_t u; /* Local index variable */ 407 408 /* Iterate over data blocks */ 409 sblk_idx = dblk_idx = 0; 410 for(u = 0; u < iblock->ndblk_addrs; u++) { 411 /* Check for data block existing */ 412 if(H5F_addr_defined(iblock->dblk_addrs[u])) { 413 /* Delete data block */ 414 if(H5EA__dblock_delete(hdr, iblock, iblock->dblk_addrs[u], hdr->sblk_info[sblk_idx].dblk_nelmts) < 0) 415 H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array data block") 416 iblock->dblk_addrs[u] = HADDR_UNDEF; 417 } /* end if */ 418 419 /* Advance to next data block w/in super block */ 420 dblk_idx++; 421 422 /* Check for moving to next super block */ 423 if(dblk_idx >= hdr->sblk_info[sblk_idx].ndblks) { 424 sblk_idx++; 425 dblk_idx = 0; 426 } /* end if */ 427 } /* end for */ 428 } /* end if */ 429 430 /* Check for index block having data block pointers (not yet) */ 431 if(iblock->nsblk_addrs > 0) { 432 size_t u; /* Local index variable */ 433 434 /* Iterate over super blocks */ 435 for(u = 0; u < iblock->nsblk_addrs; u++) { 436 /* Check for data block existing */ 437 if(H5F_addr_defined(iblock->sblk_addrs[u])) { 438 /* Delete super block */ 439 if(H5EA__sblock_delete(hdr, iblock, iblock->sblk_addrs[u], (unsigned)(u + iblock->nsblks)) < 0) 440 H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array super block") 441 iblock->sblk_addrs[u] = HADDR_UNDEF; 442 } /* end if */ 443 } /* end for */ 444 } /* end if */ 445 446 CATCH 447 /* Finished deleting index block in metadata cache */ 448 if(iblock && H5EA__iblock_unprotect(iblock, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0) 449 H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array index block") 450 451 END_FUNC(PKG) /* end H5EA__iblock_delete() */ 452 453 454 /*------------------------------------------------------------------------- 455 * Function: H5EA__iblock_dest 456 * 457 * Purpose: Destroys an extensible array index block in memory. 458 * 459 * Return: Non-negative on success/Negative on failure 460 * 461 * Programmer: Quincey Koziol 462 * koziol@hdfgroup.org 463 * Sep 11 2008 464 * 465 *------------------------------------------------------------------------- 466 */ 467 BEGIN_FUNC(PKG, ERR, 468 herr_t, SUCCEED, FAIL, 469 H5EA__iblock_dest(H5EA_iblock_t *iblock)) 470 471 /* Sanity check */ 472 HDassert(iblock); 473 474 /* Check if shared header field has been initialized */ 475 if(iblock->hdr) { 476 /* Check if we've got elements in the index block */ 477 if(iblock->elmts) { 478 /* Free buffer for index block elements */ 479 HDassert(iblock->hdr->cparam.idx_blk_elmts > 0); 480 iblock->elmts = H5FL_BLK_FREE(idx_blk_elmt_buf, iblock->elmts); 481 } /* end if */ 482 483 /* Check if we've got data block addresses in the index block */ 484 if(iblock->dblk_addrs) { 485 /* Free buffer for index block data block addresses */ 486 HDassert(iblock->ndblk_addrs > 0); 487 iblock->dblk_addrs = H5FL_SEQ_FREE(haddr_t, iblock->dblk_addrs); 488 iblock->ndblk_addrs = 0; 489 } /* end if */ 490 491 /* Check if we've got super block addresses in the index block */ 492 if(iblock->sblk_addrs) { 493 /* Free buffer for index block super block addresses */ 494 HDassert(iblock->nsblk_addrs > 0); 495 iblock->sblk_addrs = H5FL_SEQ_FREE(haddr_t, iblock->sblk_addrs); 496 iblock->nsblk_addrs = 0; 497 } /* end if */ 498 499 /* Decrement reference count on shared info */ 500 if(H5EA__hdr_decr(iblock->hdr) < 0) 501 H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header") 502 iblock->hdr = NULL; 503 } /* end if */ 504 505 /* Sanity check */ 506 HDassert(NULL == iblock->top_proxy); 507 508 /* Free the index block itself */ 509 iblock = H5FL_FREE(H5EA_iblock_t, iblock); 510 511 CATCH 512 513 END_FUNC(PKG) /* end H5EA__iblock_dest() */ 514 515