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: H5EAsblock.c 17 * Sep 30 2008 18 * Quincey Koziol <koziol@hdfgroup.org> 19 * 20 * Purpose: Super 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_sblock_t); 84 85 /* Declare a free list to manage the haddr_t sequence information */ 86 H5FL_SEQ_DEFINE_STATIC(haddr_t); 87 88 /* Declare a free list to manage blocks of 'page init' bitmasks */ 89 H5FL_BLK_DEFINE(page_init); 90 91 92 93 /*------------------------------------------------------------------------- 94 * Function: H5EA__sblock_alloc 95 * 96 * Purpose: Allocate extensible array super block 97 * 98 * Return: Non-NULL pointer to super block on success/NULL on failure 99 * 100 * Programmer: Quincey Koziol 101 * koziol@hdfgroup.org 102 * Sep 30 2008 103 * 104 *------------------------------------------------------------------------- 105 */ 106 BEGIN_FUNC(PKG, ERR, 107 H5EA_sblock_t *, NULL, NULL, 108 H5EA__sblock_alloc(H5EA_hdr_t *hdr, H5EA_iblock_t *parent, unsigned sblk_idx)) 109 110 /* Local variables */ 111 H5EA_sblock_t *sblock = NULL; /* Extensible array super block */ 112 113 /* Check arguments */ 114 HDassert(hdr); 115 116 /* Allocate memory for the index block */ 117 if(NULL == (sblock = H5FL_CALLOC(H5EA_sblock_t))) 118 H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array super 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 sblock->hdr = hdr; 124 125 /* Set non-zero internal fields */ 126 sblock->parent = parent; 127 sblock->addr = HADDR_UNDEF; 128 129 /* Compute/cache information */ 130 sblock->idx = sblk_idx; 131 sblock->ndblks = hdr->sblk_info[sblk_idx].ndblks; 132 HDassert(sblock->ndblks); 133 sblock->dblk_nelmts = hdr->sblk_info[sblk_idx].dblk_nelmts; 134 135 /* Allocate buffer for data block addresses in super block */ 136 if(NULL == (sblock->dblk_addrs = H5FL_SEQ_MALLOC(haddr_t, sblock->ndblks))) 137 H5E_THROW(H5E_CANTALLOC, "memory allocation failed for super block data block addresses") 138 139 /* Check if # of elements in data blocks requires paging */ 140 if(sblock->dblk_nelmts > hdr->dblk_page_nelmts) { 141 /* Compute # of pages in each data block from this super block */ 142 sblock->dblk_npages = sblock->dblk_nelmts / hdr->dblk_page_nelmts; 143 144 /* Sanity check that we have at least 2 pages in data block */ 145 HDassert(sblock->dblk_npages > 1); 146 147 /* Sanity check for integer truncation */ 148 HDassert((sblock->dblk_npages * hdr->dblk_page_nelmts) == sblock->dblk_nelmts); 149 150 /* Compute size of buffer for each data block's 'page init' bitmask */ 151 sblock->dblk_page_init_size = ((sblock->dblk_npages) + 7) / 8; 152 HDassert(sblock->dblk_page_init_size > 0); 153 154 /* Allocate buffer for all 'page init' bitmasks in super block */ 155 if(NULL == (sblock->page_init = H5FL_BLK_CALLOC(page_init, sblock->ndblks * sblock->dblk_page_init_size))) 156 H5E_THROW(H5E_CANTALLOC, "memory allocation failed for super block page init bitmask") 157 158 /* Compute data block page size */ 159 sblock->dblk_page_size = (hdr->dblk_page_nelmts * hdr->cparam.raw_elmt_size) 160 + H5EA_SIZEOF_CHKSUM; 161 } /* end if */ 162 163 /* Set the return value */ 164 ret_value = sblock; 165 166 CATCH 167 if(!ret_value) 168 if(sblock && H5EA__sblock_dest(sblock) < 0) 169 H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array super block") 170 171 END_FUNC(PKG) /* end H5EA__sblock_alloc() */ 172 173 174 /*------------------------------------------------------------------------- 175 * Function: H5EA__sblock_create 176 * 177 * Purpose: Creates a new extensible array super block in the file 178 * 179 * Return: Valid file address on success/HADDR_UNDEF on failure 180 * 181 * Programmer: Quincey Koziol 182 * koziol@hdfgroup.org 183 * Sep 30 2008 184 * 185 *------------------------------------------------------------------------- 186 */ 187 BEGIN_FUNC(PKG, ERR, 188 haddr_t, HADDR_UNDEF, HADDR_UNDEF, 189 H5EA__sblock_create(H5EA_hdr_t *hdr, H5EA_iblock_t *parent, hbool_t *stats_changed, 190 unsigned sblk_idx)) 191 192 /* Local variables */ 193 H5EA_sblock_t *sblock = NULL; /* Extensible array super block */ 194 haddr_t sblock_addr; /* Extensible array super block address */ 195 haddr_t tmp_addr = HADDR_UNDEF; /* Address value to fill data block addresses with */ 196 hbool_t inserted = FALSE; /* Whether the header was inserted into cache */ 197 198 /* Sanity check */ 199 HDassert(hdr); 200 HDassert(stats_changed); 201 202 /* Allocate the super block */ 203 if(NULL == (sblock = H5EA__sblock_alloc(hdr, parent, sblk_idx))) 204 H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array super block") 205 206 /* Set size of super block on disk */ 207 sblock->size = H5EA_SBLOCK_SIZE(sblock); 208 209 /* Set offset of block in array's address space */ 210 sblock->block_off = hdr->sblk_info[sblk_idx].start_idx; 211 212 /* Allocate space for the super block on disk */ 213 if(HADDR_UNDEF == (sblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_EARRAY_SBLOCK, (hsize_t)sblock->size))) 214 H5E_THROW(H5E_CANTALLOC, "file allocation failed for extensible array super block") 215 sblock->addr = sblock_addr; 216 217 /* Reset data block addresses to "undefined" address value */ 218 H5VM_array_fill(sblock->dblk_addrs, &tmp_addr, sizeof(haddr_t), sblock->ndblks); 219 220 /* Cache the new extensible array super block */ 221 if(H5AC_insert_entry(hdr->f, H5AC_EARRAY_SBLOCK, sblock_addr, sblock, H5AC__NO_FLAGS_SET) < 0) 222 H5E_THROW(H5E_CANTINSERT, "can't add extensible array super block to cache") 223 inserted = TRUE; 224 225 /* Add super block as child of 'top' proxy */ 226 if(hdr->top_proxy) { 227 if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, sblock) < 0) 228 H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy") 229 sblock->top_proxy = hdr->top_proxy; 230 } /* end if */ 231 232 /* Update extensible array super block statistics */ 233 hdr->stats.stored.nsuper_blks++; 234 hdr->stats.stored.super_blk_size += sblock->size; 235 236 /* Mark the statistics as changed */ 237 *stats_changed = TRUE; 238 239 /* Set address of super block to return */ 240 ret_value = sblock_addr; 241 242 CATCH 243 if(!H5F_addr_defined(ret_value)) 244 if(sblock) { 245 /* Remove from cache, if inserted */ 246 if(inserted) 247 if(H5AC_remove_entry(sblock) < 0) 248 H5E_THROW(H5E_CANTREMOVE, "unable to remove extensible array super block from cache") 249 250 /* Release super block's disk space */ 251 if(H5F_addr_defined(sblock->addr) && H5MF_xfree(hdr->f, H5FD_MEM_EARRAY_SBLOCK, sblock->addr, (hsize_t)sblock->size) < 0) 252 H5E_THROW(H5E_CANTFREE, "unable to release extensible array super block") 253 254 /* Destroy super block */ 255 if(H5EA__sblock_dest(sblock) < 0) 256 H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array super block") 257 } /* end if */ 258 259 END_FUNC(PKG) /* end H5EA__sblock_create() */ 260 261 262 /*------------------------------------------------------------------------- 263 * Function: H5EA__sblock_protect 264 * 265 * Purpose: Convenience wrapper around protecting extensible array super block 266 * 267 * Return: Non-NULL pointer to data block on success/NULL on failure 268 * 269 * Programmer: Quincey Koziol 270 * koziol@hdfgroup.org 271 * Sep 30 2008 272 * 273 *------------------------------------------------------------------------- 274 */ 275 BEGIN_FUNC(PKG, ERR, 276 H5EA_sblock_t *, NULL, NULL, 277 H5EA__sblock_protect(H5EA_hdr_t *hdr, H5EA_iblock_t *parent, 278 haddr_t sblk_addr, unsigned sblk_idx, unsigned flags)) 279 280 /* Local variables */ 281 H5EA_sblock_t *sblock = NULL; /* Pointer to super block */ 282 H5EA_sblock_cache_ud_t udata; /* Information needed for loading super block */ 283 284 /* Sanity check */ 285 HDassert(hdr); 286 HDassert(H5F_addr_defined(sblk_addr)); 287 288 /* only the H5AC__READ_ONLY_FLAG may be set */ 289 HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); 290 291 /* Set up user data */ 292 udata.hdr = hdr; 293 udata.parent = parent; 294 udata.sblk_idx = sblk_idx; 295 udata.sblk_addr = sblk_addr; 296 297 /* Protect the super block */ 298 if(NULL == (sblock = (H5EA_sblock_t *)H5AC_protect(hdr->f, H5AC_EARRAY_SBLOCK, sblk_addr, &udata, flags))) 299 H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array super block, address = %llu", (unsigned long long)sblk_addr) 300 301 /* Create top proxy, if it doesn't exist */ 302 if(hdr->top_proxy && NULL == sblock->top_proxy) { 303 /* Add super block as child of 'top' proxy */ 304 if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, sblock) < 0) 305 H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy") 306 sblock->top_proxy = hdr->top_proxy; 307 } /* end if */ 308 309 /* Set return value */ 310 ret_value = sblock; 311 312 CATCH 313 /* Clean up on error */ 314 if(!ret_value) { 315 /* Release the super block, if it was protected */ 316 if(sblock && H5AC_unprotect(hdr->f, H5AC_EARRAY_SBLOCK, sblock->addr, sblock, H5AC__NO_FLAGS_SET) < 0) 317 H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array super block, address = %llu", (unsigned long long)sblock->addr) 318 } /* end if */ 319 320 END_FUNC(PKG) /* end H5EA__sblock_protect() */ 321 322 323 /*------------------------------------------------------------------------- 324 * Function: H5EA__sblock_unprotect 325 * 326 * Purpose: Convenience wrapper around unprotecting extensible array super block 327 * 328 * Return: Non-negative on success/Negative on failure 329 * 330 * Programmer: Quincey Koziol 331 * koziol@hdfgroup.org 332 * Sep 30 2008 333 * 334 *------------------------------------------------------------------------- 335 */ 336 BEGIN_FUNC(PKG, ERR, 337 herr_t, SUCCEED, FAIL, 338 H5EA__sblock_unprotect(H5EA_sblock_t *sblock, unsigned cache_flags)) 339 340 /* Local variables */ 341 342 /* Sanity check */ 343 HDassert(sblock); 344 345 /* Unprotect the super block */ 346 if(H5AC_unprotect(sblock->hdr->f, H5AC_EARRAY_SBLOCK, sblock->addr, sblock, cache_flags) < 0) 347 H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array super block, address = %llu", (unsigned long long)sblock->addr) 348 349 CATCH 350 351 END_FUNC(PKG) /* end H5EA__sblock_unprotect() */ 352 353 354 /*------------------------------------------------------------------------- 355 * Function: H5EA__sblock_delete 356 * 357 * Purpose: Delete a super block 358 * 359 * Return: SUCCEED/FAIL 360 * 361 * Programmer: Quincey Koziol 362 * koziol@hdfgroup.org 363 * Sep 30 2008 364 * 365 *------------------------------------------------------------------------- 366 */ 367 BEGIN_FUNC(PKG, ERR, 368 herr_t, SUCCEED, FAIL, 369 H5EA__sblock_delete(H5EA_hdr_t *hdr, H5EA_iblock_t *parent, 370 haddr_t sblk_addr, unsigned sblk_idx)) 371 372 /* Local variables */ 373 H5EA_sblock_t *sblock = NULL; /* Pointer to super block */ 374 size_t u; /* Local index variable */ 375 376 /* Sanity check */ 377 HDassert(hdr); 378 HDassert(H5F_addr_defined(sblk_addr)); 379 380 /* Protect super block */ 381 if(NULL == (sblock = H5EA__sblock_protect(hdr, parent, sblk_addr, sblk_idx, H5AC__NO_FLAGS_SET))) 382 H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array super block, address = %llu", (unsigned long long)sblk_addr) 383 384 /* Iterate over data blocks */ 385 for(u = 0; u < sblock->ndblks; u++) { 386 /* Check for data block existing */ 387 if(H5F_addr_defined(sblock->dblk_addrs[u])) { 388 /* Delete data block */ 389 if(H5EA__dblock_delete(hdr, sblock, sblock->dblk_addrs[u], sblock->dblk_nelmts) < 0) 390 H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array data block") 391 sblock->dblk_addrs[u] = HADDR_UNDEF; 392 } /* end if */ 393 } /* end for */ 394 395 CATCH 396 /* Finished deleting super block in metadata cache */ 397 if(sblock && H5EA__sblock_unprotect(sblock, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0) 398 H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array super block") 399 400 END_FUNC(PKG) /* end H5EA__sblock_delete() */ 401 402 403 /*------------------------------------------------------------------------- 404 * Function: H5EA__sblock_dest 405 * 406 * Purpose: Destroys an extensible array super block in memory. 407 * 408 * Return: Non-negative on success/Negative on failure 409 * 410 * Programmer: Quincey Koziol 411 * koziol@hdfgroup.org 412 * Sep 30 2008 413 * 414 *------------------------------------------------------------------------- 415 */ 416 BEGIN_FUNC(PKG, ERR, 417 herr_t, SUCCEED, FAIL, 418 H5EA__sblock_dest(H5EA_sblock_t *sblock)) 419 420 /* Sanity check */ 421 HDassert(sblock); 422 HDassert(!sblock->has_hdr_depend); 423 424 /* Check if shared header field has been initialized */ 425 if(sblock->hdr) { 426 /* Free buffer for super block data block addresses, if there are any */ 427 if(sblock->dblk_addrs) 428 sblock->dblk_addrs = H5FL_SEQ_FREE(haddr_t, sblock->dblk_addrs); 429 430 /* Free buffer for super block 'page init' bitmask, if there is one */ 431 if(sblock->page_init) { 432 HDassert(sblock->dblk_npages > 0); 433 sblock->page_init = H5FL_BLK_FREE(page_init, sblock->page_init); 434 } /* end if */ 435 436 /* Decrement reference count on shared info */ 437 if(H5EA__hdr_decr(sblock->hdr) < 0) 438 H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header") 439 sblock->hdr = NULL; 440 } /* end if */ 441 442 /* Sanity check */ 443 HDassert(NULL == sblock->top_proxy); 444 445 /* Free the super block itself */ 446 sblock = H5FL_FREE(H5EA_sblock_t, sblock); 447 448 CATCH 449 450 END_FUNC(PKG) /* end H5EA__sblock_dest() */ 451 452