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://www.hdfgroup.org/licenses. *
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: H5HF.c
17 * Feb 24 2006
18 * Quincey Koziol
19 *
20 * Purpose: Implements a "fractal heap" for storing variable-
21 * length objects in a file.
22 *
23 * Please see the documentation in:
24 * doc/html/TechNotes/FractalHeap.html for a full description
25 * of how they work, etc.
26 *
27 *-------------------------------------------------------------------------
28 */
29
30 /****************/
31 /* Module Setup */
32 /****************/
33
34 #include "H5HFmodule.h" /* This source code file is part of the H5HF module */
35
36 /***********/
37 /* Headers */
38 /***********/
39 #include "H5private.h" /* Generic Functions */
40 #include "H5Eprivate.h" /* Error handling */
41 #include "H5FOprivate.h" /* File objects */
42 #include "H5HFpkg.h" /* Fractal heaps */
43 #include "H5MFprivate.h" /* File memory management */
44 #include "H5MMprivate.h" /* Memory management */
45
46 /****************/
47 /* Local Macros */
48 /****************/
49
50 /******************/
51 /* Local Typedefs */
52 /******************/
53
54 /********************/
55 /* Package Typedefs */
56 /********************/
57
58 /********************/
59 /* Local Prototypes */
60 /********************/
61
62 /*********************/
63 /* Package Variables */
64 /*********************/
65
66 /* Package initialization variable */
67 hbool_t H5_PKG_INIT_VAR = FALSE;
68
69 /*****************************/
70 /* Library Private Variables */
71 /*****************************/
72
73 /*******************/
74 /* Local Variables */
75 /*******************/
76
77 /* Declare a free list to manage the H5HF_t struct */
78 H5FL_DEFINE_STATIC(H5HF_t);
79
80 /*-------------------------------------------------------------------------
81 * Function: H5HF__op_read
82 *
83 * Purpose: Performs a 'read' operation for a heap 'op' callback
84 *
85 * Return: SUCCEED/FAIL
86 *
87 * Programmer: Quincey Koziol
88 * Sep 11 2006
89 *
90 *-------------------------------------------------------------------------
91 */
92 herr_t
H5HF__op_read(const void * obj,size_t obj_len,void * op_data)93 H5HF__op_read(const void *obj, size_t obj_len, void *op_data)
94 {
95 FUNC_ENTER_PACKAGE_NOERR
96
97 /* Perform "read", using memcpy() */
98 H5MM_memcpy(op_data, obj, obj_len);
99
100 FUNC_LEAVE_NOAPI(SUCCEED)
101 } /* end H5HF__op_read() */
102
103 /*-------------------------------------------------------------------------
104 * Function: H5HF__op_write
105 *
106 * Purpose: Performs a 'write' operation for a heap 'op' callback
107 *
108 * Return: SUCCEED/FAIL
109 *
110 * Programmer: Quincey Koziol
111 * Dec 18 2006
112 *
113 *-------------------------------------------------------------------------
114 */
115 herr_t
H5HF__op_write(const void * obj,size_t obj_len,void * op_data)116 H5HF__op_write(const void *obj, size_t obj_len, void *op_data)
117 {
118 FUNC_ENTER_PACKAGE_NOERR
119
120 /* Perform "write", using memcpy() */
121 H5MM_memcpy((void *)obj, op_data, obj_len); /* Casting away const OK -QAK */
122
123 FUNC_LEAVE_NOAPI(SUCCEED)
124 } /* end H5HF__op_write() */
125
126 /*-------------------------------------------------------------------------
127 * Function: H5HF_create
128 *
129 * Purpose: Creates a new empty fractal heap in the file.
130 *
131 * Return: Pointer to heap wrapper on success
132 * NULL on failure
133 *
134 * Programmer: Quincey Koziol
135 * Feb 24 2006
136 *
137 *-------------------------------------------------------------------------
138 */
139 H5HF_t *
H5HF_create(H5F_t * f,const H5HF_create_t * cparam)140 H5HF_create(H5F_t *f, const H5HF_create_t *cparam)
141 {
142 H5HF_t * fh = NULL; /* Pointer to new fractal heap */
143 H5HF_hdr_t *hdr = NULL; /* The fractal heap header information */
144 haddr_t fh_addr; /* Heap header address */
145 H5HF_t * ret_value = NULL; /* Return value */
146
147 FUNC_ENTER_NOAPI(NULL)
148
149 /*
150 * Check arguments.
151 */
152 HDassert(f);
153 HDassert(cparam);
154
155 /* Create shared fractal heap header */
156 if (HADDR_UNDEF == (fh_addr = H5HF__hdr_create(f, cparam)))
157 HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't create fractal heap header")
158
159 /* Allocate fractal heap wrapper */
160 if (NULL == (fh = H5FL_MALLOC(H5HF_t)))
161 HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed for fractal heap info")
162
163 /* Lock the heap header into memory */
164 if (NULL == (hdr = H5HF__hdr_protect(f, fh_addr, H5AC__NO_FLAGS_SET)))
165 HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header")
166
167 /* Point fractal heap wrapper at header and bump it's ref count */
168 fh->hdr = hdr;
169 if (H5HF__hdr_incr(fh->hdr) < 0)
170 HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared heap header")
171
172 /* Increment # of files using this heap header */
173 if (H5HF__hdr_fuse_incr(fh->hdr) < 0)
174 HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment file reference count on shared heap header")
175
176 /* Set file pointer for this heap open context */
177 fh->f = f;
178
179 /* Set the return value */
180 ret_value = fh;
181
182 done:
183 if (hdr && H5AC_unprotect(f, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
184 HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release fractal heap header")
185 if (!ret_value && fh)
186 if (H5HF_close(fh) < 0)
187 HDONE_ERROR(H5E_HEAP, H5E_CANTCLOSEOBJ, NULL, "unable to close fractal heap")
188
189 FUNC_LEAVE_NOAPI(ret_value)
190 } /* end H5HF_create() */
191
192 /*-------------------------------------------------------------------------
193 * Function: H5HF_open
194 *
195 * Purpose: Opens an existing fractal heap in the file.
196 *
197 * Return: Pointer to heap wrapper on success
198 * NULL on failure
199 *
200 * Programmer: Quincey Koziol
201 * Apr 18 2006
202 *
203 *-------------------------------------------------------------------------
204 */
205 H5HF_t *
H5HF_open(H5F_t * f,haddr_t fh_addr)206 H5HF_open(H5F_t *f, haddr_t fh_addr)
207 {
208 H5HF_t * fh = NULL; /* Pointer to new fractal heap */
209 H5HF_hdr_t *hdr = NULL; /* The fractal heap header information */
210 H5HF_t * ret_value = NULL; /* Return value */
211
212 FUNC_ENTER_NOAPI(NULL)
213
214 /*
215 * Check arguments.
216 */
217 HDassert(f);
218 HDassert(H5F_addr_defined(fh_addr));
219
220 /* Load the heap header into memory */
221 if (NULL == (hdr = H5HF__hdr_protect(f, fh_addr, H5AC__READ_ONLY_FLAG)))
222 HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap header")
223
224 /* Check for pending heap deletion */
225 if (hdr->pending_delete)
226 HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, NULL, "can't open fractal heap pending deletion")
227
228 /* Create fractal heap info */
229 if (NULL == (fh = H5FL_MALLOC(H5HF_t)))
230 HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed for fractal heap info")
231
232 /* Point fractal heap wrapper at header */
233 fh->hdr = hdr;
234 if (H5HF__hdr_incr(fh->hdr) < 0)
235 HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment reference count on shared heap header")
236
237 /* Increment # of files using this heap header */
238 if (H5HF__hdr_fuse_incr(fh->hdr) < 0)
239 HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, NULL, "can't increment file reference count on shared heap header")
240
241 /* Set file pointer for this heap open context */
242 fh->f = f;
243
244 /* Set the return value */
245 ret_value = fh;
246
247 done:
248 if (hdr && H5AC_unprotect(f, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
249 HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release fractal heap header")
250 if (!ret_value && fh)
251 if (H5HF_close(fh) < 0)
252 HDONE_ERROR(H5E_HEAP, H5E_CANTCLOSEOBJ, NULL, "unable to close fractal heap")
253
254 FUNC_LEAVE_NOAPI(ret_value)
255 } /* end H5HF_open() */
256
257 /*-------------------------------------------------------------------------
258 * Function: H5HF_get_id_len
259 *
260 * Purpose: Get the size of IDs for entries in a fractal heap
261 *
262 * Return: SUCCEED/FAIL
263 *
264 * Programmer: Quincey Koziol
265 * Apr 17 2006
266 *
267 *-------------------------------------------------------------------------
268 */
269 herr_t
H5HF_get_id_len(H5HF_t * fh,size_t * id_len_p)270 H5HF_get_id_len(H5HF_t *fh, size_t *id_len_p)
271 {
272 FUNC_ENTER_NOAPI_NOINIT_NOERR
273
274 /*
275 * Check arguments.
276 */
277 HDassert(fh);
278 HDassert(id_len_p);
279
280 /* Retrieve the ID length for entries in this heap */
281 *id_len_p = fh->hdr->id_len;
282
283 FUNC_LEAVE_NOAPI(SUCCEED)
284 } /* end H5HF_get_id_len() */
285
286 /*-------------------------------------------------------------------------
287 * Function: H5HF_get_heap_addr
288 *
289 * Purpose: Get the address of a fractal heap
290 *
291 * Return: SUCCEED/FAIL
292 *
293 * Programmer: Quincey Koziol
294 * Apr 18 2006
295 *
296 *-------------------------------------------------------------------------
297 */
298 herr_t
H5HF_get_heap_addr(const H5HF_t * fh,haddr_t * heap_addr_p)299 H5HF_get_heap_addr(const H5HF_t *fh, haddr_t *heap_addr_p)
300 {
301 FUNC_ENTER_NOAPI_NOINIT_NOERR
302
303 /*
304 * Check arguments.
305 */
306 HDassert(fh);
307 HDassert(heap_addr_p);
308
309 /* Retrieve the heap header address for this heap */
310 *heap_addr_p = fh->hdr->heap_addr;
311
312 FUNC_LEAVE_NOAPI(SUCCEED)
313 } /* end H5HF_get_heap_addr() */
314
315 /*-------------------------------------------------------------------------
316 * Function: H5HF_insert
317 *
318 * Purpose: Insert a new object into a fractal heap.
319 *
320 * Return: Non-negative on success (with heap ID of new object
321 * filled in), negative on failure
322 *
323 * Programmer: Quincey Koziol
324 * Feb 24 2006
325 *
326 *-------------------------------------------------------------------------
327 */
328 herr_t
H5HF_insert(H5HF_t * fh,size_t size,const void * obj,void * id)329 H5HF_insert(H5HF_t *fh, size_t size, const void *obj, void *id /*out*/)
330 {
331 H5HF_hdr_t *hdr = NULL; /* The fractal heap header information */
332 herr_t ret_value = SUCCEED;
333
334 FUNC_ENTER_NOAPI(FAIL)
335
336 /* Sanity check */
337 HDassert(fh);
338 HDassert(obj);
339 HDassert(id);
340
341 /* Check arguments */
342 if (size == 0)
343 HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "can't insert 0-sized objects")
344
345 /* Set the shared heap header's file context for this operation */
346 fh->hdr->f = fh->f;
347
348 /* Get the fractal heap header */
349 hdr = fh->hdr;
350
351 /* Check for 'huge' object */
352 if (size > hdr->max_man_size) {
353 /* Store 'huge' object in heap */
354 /* (Casting away const OK - QAK) */
355 if (H5HF__huge_insert(hdr, size, (void *)obj, id) < 0)
356 HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't store 'huge' object in fractal heap")
357 } /* end if */
358 /* Check for 'tiny' object */
359 else if (size <= hdr->tiny_max_len) {
360 /* Store 'tiny' object in heap */
361 if (H5HF__tiny_insert(hdr, size, obj, id) < 0)
362 HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't store 'tiny' object in fractal heap")
363 } /* end if */
364 else {
365 /* Check if we are in "append only" mode, or if there's enough room for the object */
366 if (hdr->write_once) {
367 HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "'write once' managed blocks not supported yet")
368 } /* end if */
369 else {
370 /* Allocate space for object in 'managed' heap */
371 if (H5HF__man_insert(hdr, size, obj, id) < 0)
372 HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "can't store 'managed' object in fractal heap")
373 } /* end else */
374 } /* end else */
375
376 done:
377 FUNC_LEAVE_NOAPI(ret_value)
378 } /* end H5HF_insert() */
379
380 /*-------------------------------------------------------------------------
381 * Function: H5HF_get_obj_len
382 *
383 * Purpose: Get the size of an entry in a fractal heap
384 *
385 * Return: SUCCEED/FAIL
386 *
387 * Programmer: Quincey Koziol
388 * May 9 2006
389 *
390 *-------------------------------------------------------------------------
391 */
392 herr_t
H5HF_get_obj_len(H5HF_t * fh,const void * _id,size_t * obj_len_p)393 H5HF_get_obj_len(H5HF_t *fh, const void *_id, size_t *obj_len_p)
394 {
395 const uint8_t *id = (const uint8_t *)_id; /* Object ID */
396 uint8_t id_flags; /* Heap ID flag bits */
397 herr_t ret_value = SUCCEED; /* Return value */
398
399 FUNC_ENTER_NOAPI(FAIL)
400
401 /*
402 * Check arguments.
403 */
404 HDassert(fh);
405 HDassert(id);
406 HDassert(obj_len_p);
407
408 /* Get the ID flags */
409 id_flags = *id;
410
411 /* Check for correct heap ID version */
412 if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
413 HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
414
415 /* Set the shared heap header's file context for this operation */
416 fh->hdr->f = fh->f;
417
418 /* Check type of object in heap */
419 if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
420 if (H5HF__man_get_obj_len(fh->hdr, id, obj_len_p) < 0)
421 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'managed' object's length")
422 } /* end if */
423 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
424 if (H5HF__huge_get_obj_len(fh->hdr, id, obj_len_p) < 0)
425 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'huge' object's length")
426 } /* end if */
427 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
428 if (H5HF__tiny_get_obj_len(fh->hdr, id, obj_len_p) < 0)
429 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'tiny' object's length")
430 } /* end if */
431 else {
432 HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
433 HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
434 } /* end else */
435
436 done:
437 FUNC_LEAVE_NOAPI(ret_value)
438 } /* end H5HF_get_obj_len() */
439
440 /*-------------------------------------------------------------------------
441 * Function: H5HF_get_obj_off
442 *
443 * Purpose: Get the offset of an entry in a fractal heap
444 *
445 * Return: SUCCEED/FAIL
446 *
447 * Programmer: Quincey Koziol
448 * Aug 20 2015
449 *
450 *-------------------------------------------------------------------------
451 */
452 herr_t
H5HF_get_obj_off(H5HF_t * fh,const void * _id,hsize_t * obj_off_p)453 H5HF_get_obj_off(H5HF_t *fh, const void *_id, hsize_t *obj_off_p)
454 {
455 const uint8_t *id = (const uint8_t *)_id; /* Object ID */
456 uint8_t id_flags; /* Heap ID flag bits */
457 herr_t ret_value = SUCCEED; /* Return value */
458
459 FUNC_ENTER_NOAPI(FAIL)
460
461 /*
462 * Check arguments.
463 */
464 HDassert(fh);
465 HDassert(id);
466 HDassert(obj_off_p);
467
468 /* Get the ID flags */
469 id_flags = *id;
470
471 /* Check for correct heap ID version */
472 if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
473 HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
474
475 /* Set the shared heap header's file context for this operation */
476 fh->hdr->f = fh->f;
477
478 /* Check type of object in heap */
479 if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
480 H5HF__man_get_obj_off(fh->hdr, id, obj_off_p);
481 } /* end if */
482 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
483 /* Huge objects are located directly in the file */
484 if (H5HF__huge_get_obj_off(fh->hdr, id, obj_off_p) < 0)
485 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get 'huge' object's offset")
486 } /* end if */
487 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
488 /* Tiny objects are not stored in the heap */
489 *obj_off_p = (hsize_t)0;
490 } /* end if */
491 else {
492 HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
493 HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
494 } /* end else */
495
496 done:
497 FUNC_LEAVE_NOAPI(ret_value)
498 } /* end H5HF_get_obj_off() */
499
500 /*-------------------------------------------------------------------------
501 * Function: H5HF_read
502 *
503 * Purpose: Read an object from a fractal heap into a buffer
504 *
505 * Return: SUCCEED/FAIL
506 *
507 * Programmer: Quincey Koziol
508 * Mar 18 2006
509 *
510 *-------------------------------------------------------------------------
511 */
512 herr_t
H5HF_read(H5HF_t * fh,const void * _id,void * obj)513 H5HF_read(H5HF_t *fh, const void *_id, void *obj /*out*/)
514 {
515 const uint8_t *id = (const uint8_t *)_id; /* Object ID */
516 uint8_t id_flags; /* Heap ID flag bits */
517 herr_t ret_value = SUCCEED; /* Return value */
518
519 FUNC_ENTER_NOAPI(FAIL)
520
521 /*
522 * Check arguments.
523 */
524 HDassert(fh);
525 HDassert(id);
526 HDassert(obj);
527
528 /* Get the ID flags */
529 id_flags = *id;
530
531 /* Check for correct heap ID version */
532 if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
533 HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
534
535 /* Set the shared heap header's file context for this operation */
536 fh->hdr->f = fh->f;
537
538 /* Check type of object in heap */
539 if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
540 /* Read object from managed heap blocks */
541 if (H5HF__man_read(fh->hdr, id, obj) < 0)
542 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read object from fractal heap")
543 } /* end if */
544 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
545 /* Read 'huge' object from file */
546 if (H5HF__huge_read(fh->hdr, id, obj) < 0)
547 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read 'huge' object from fractal heap")
548 } /* end if */
549 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
550 /* Read 'tiny' object from file */
551 if (H5HF__tiny_read(fh->hdr, id, obj) < 0)
552 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read 'tiny' object from fractal heap")
553 } /* end if */
554 else {
555 HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
556 HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
557 } /* end else */
558
559 done:
560 FUNC_LEAVE_NOAPI(ret_value)
561 } /* end H5HF_read() */
562
563 /*-------------------------------------------------------------------------
564 * Function: H5HF_write
565 *
566 * Purpose: Write an object from a buffer into a fractal heap
567 *
568 * Notes: Writing objects in "managed" heap blocks is only storage
569 * method currently supported. (Which could be expanded to
570 * 'huge' and 'tiny' objects, with some work)
571 *
572 * Also, assumes that the 'op' routine modifies the data, and
573 * marks data to be written back to disk, even if 'op' routine
574 * didn't actually change anything. (Which could be modified
575 * to pass "did_modify" flag to callback, if necessary)
576 *
577 * Also, assumes that object to write is same size as object in
578 * heap.
579 *
580 * Return: SUCCEED/FAIL
581 *
582 * Programmer: Quincey Koziol
583 * Dec 18 2006
584 *
585 *-------------------------------------------------------------------------
586 */
587 herr_t
H5HF_write(H5HF_t * fh,void * _id,hbool_t H5_ATTR_UNUSED * id_changed,const void * obj)588 H5HF_write(H5HF_t *fh, void *_id, hbool_t H5_ATTR_UNUSED *id_changed, const void *obj)
589 {
590 uint8_t *id = (uint8_t *)_id; /* Object ID */
591 uint8_t id_flags; /* Heap ID flag bits */
592 herr_t ret_value = SUCCEED; /* Return value */
593
594 FUNC_ENTER_NOAPI(FAIL)
595
596 /*
597 * Check arguments.
598 */
599 HDassert(fh);
600 HDassert(id);
601 HDassert(obj);
602
603 /* Get the ID flags */
604 id_flags = *id;
605
606 /* Check for correct heap ID version */
607 if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
608 HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
609
610 /* Set the shared heap header's file context for this operation */
611 fh->hdr->f = fh->f;
612
613 /* Check type of object in heap */
614 if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
615 /* Operate on object from managed heap blocks */
616 /* (ID can't change and modifying object is "easy" to manage) */
617 if (H5HF__man_write(fh->hdr, id, obj) < 0)
618 HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "can't write to 'managed' heap object")
619 } /* end if */
620 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
621 /* Operate on "huge" object */
622 if (H5HF__huge_write(fh->hdr, id, obj) < 0)
623 HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "can't write to 'huge' heap object")
624 } /* end if */
625 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
626 /* Check for writing a 'tiny' object */
627 /* (which isn't supported yet - ID will change) */
628 HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "modifying 'tiny' object not supported yet")
629 } /* end if */
630 else {
631 HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
632 HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
633 } /* end else */
634
635 done:
636 FUNC_LEAVE_NOAPI(ret_value)
637 } /* end H5HF_write() */
638
639 /*-------------------------------------------------------------------------
640 * Function: H5HF_op
641 *
642 * Purpose: Perform an operation directly on a heap object
643 *
644 * Note: The library routines currently assume that the 'op' callback
645 * won't modify the object. This can easily be changed later for
646 * "managed" heap objects, and, with some difficulty, for 'huge'
647 * and 'tiny' heap objects.
648 *
649 * Return: SUCCEED/FAIL
650 *
651 * Programmer: Quincey Koziol
652 * Sept 11 2006
653 *
654 *-------------------------------------------------------------------------
655 */
656 herr_t
H5HF_op(H5HF_t * fh,const void * _id,H5HF_operator_t op,void * op_data)657 H5HF_op(H5HF_t *fh, const void *_id, H5HF_operator_t op, void *op_data)
658 {
659 const uint8_t *id = (const uint8_t *)_id; /* Object ID */
660 uint8_t id_flags; /* Heap ID flag bits */
661 herr_t ret_value = SUCCEED; /* Return value */
662
663 FUNC_ENTER_NOAPI(FAIL)
664
665 /*
666 * Check arguments.
667 */
668 HDassert(fh);
669 HDassert(id);
670 HDassert(op);
671
672 /* Get the ID flags */
673 id_flags = *id;
674
675 /* Check for correct heap ID version */
676 if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
677 HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
678
679 /* Set the shared heap header's file context for this operation */
680 fh->hdr->f = fh->f;
681
682 /* Check type of object in heap */
683 if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
684 /* Operate on object from managed heap blocks */
685 if (H5HF__man_op(fh->hdr, id, op, op_data) < 0)
686 HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "can't operate on object from fractal heap")
687 } /* end if */
688 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
689 /* Operate on 'huge' object from file */
690 if (H5HF__huge_op(fh->hdr, id, op, op_data) < 0)
691 HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "can't operate on 'huge' object from fractal heap")
692 } /* end if */
693 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
694 /* Operate on 'tiny' object from file */
695 if (H5HF__tiny_op(fh->hdr, id, op, op_data) < 0)
696 HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "can't operate on 'tiny' object from fractal heap")
697 } /* end if */
698 else {
699 HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
700 HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
701 } /* end else */
702
703 done:
704 FUNC_LEAVE_NOAPI(ret_value)
705 } /* end H5HF_op() */
706
707 /*-------------------------------------------------------------------------
708 * Function: H5HF_remove
709 *
710 * Purpose: Remove an object from a fractal heap
711 *
712 * Return: SUCCEED/FAIL
713 *
714 * Programmer: Quincey Koziol
715 * May 15 2006
716 *
717 *-------------------------------------------------------------------------
718 */
719 herr_t
H5HF_remove(H5HF_t * fh,const void * _id)720 H5HF_remove(H5HF_t *fh, const void *_id)
721 {
722 const uint8_t *id = (const uint8_t *)_id; /* Object ID */
723 uint8_t id_flags; /* Heap ID flag bits */
724 herr_t ret_value = SUCCEED; /* Return value */
725
726 FUNC_ENTER_NOAPI(FAIL)
727
728 /*
729 * Check arguments.
730 */
731 HDassert(fh);
732 HDassert(fh->hdr);
733 HDassert(id);
734
735 /* Get the ID flags */
736 id_flags = *id;
737
738 /* Check for correct heap ID version */
739 if ((id_flags & H5HF_ID_VERS_MASK) != H5HF_ID_VERS_CURR)
740 HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "incorrect heap ID version")
741
742 /* Set the shared heap header's file context for this operation */
743 fh->hdr->f = fh->f;
744
745 /* Check type of object in heap */
746 if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_MAN) {
747 /* Remove object from managed heap blocks */
748 if (H5HF__man_remove(fh->hdr, id) < 0)
749 HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove object from fractal heap")
750 } /* end if */
751 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_HUGE) {
752 /* Remove 'huge' object from file & v2 B-tree tracker */
753 if (H5HF__huge_remove(fh->hdr, id) < 0)
754 HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove 'huge' object from fractal heap")
755 } /* end if */
756 else if ((id_flags & H5HF_ID_TYPE_MASK) == H5HF_ID_TYPE_TINY) {
757 /* Remove 'tiny' object from heap statistics */
758 if (H5HF__tiny_remove(fh->hdr, id) < 0)
759 HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove 'tiny' object from fractal heap")
760 } /* end if */
761 else {
762 HDfprintf(stderr, "%s: Heap ID type not supported yet!\n", FUNC);
763 HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "heap ID type not supported yet")
764 } /* end else */
765
766 done:
767 FUNC_LEAVE_NOAPI(ret_value)
768 } /* end H5HF_remove() */
769
770 /*-------------------------------------------------------------------------
771 * Function: H5HF_close
772 *
773 * Purpose: Close a fractal heap
774 *
775 * Return: SUCCEED/FAIL
776 *
777 * Programmer: Quincey Koziol
778 * Apr 17 2006
779 *
780 *-------------------------------------------------------------------------
781 */
782 herr_t
H5HF_close(H5HF_t * fh)783 H5HF_close(H5HF_t *fh)
784 {
785 hbool_t pending_delete = FALSE; /* Whether the heap is pending deletion */
786 haddr_t heap_addr = HADDR_UNDEF; /* Address of heap (for deletion) */
787 herr_t ret_value = SUCCEED; /* Return value */
788
789 FUNC_ENTER_NOAPI(FAIL)
790
791 /*
792 * Check arguments.
793 */
794 HDassert(fh);
795
796 /* Decrement file reference & check if this is the last open fractal heap using the shared heap header */
797 if (0 == H5HF__hdr_fuse_decr(fh->hdr)) {
798 /* Set the shared heap header's file context for this operation */
799 fh->hdr->f = fh->f;
800
801 /* Close the free space information */
802 /* (Can't put this in header "destroy" routine, because it has
803 * pointers to indirect blocks in the heap, which would create
804 * a reference loop and the objects couldn't be removed from
805 * the metadata cache - QAK)
806 */
807 if (H5HF__space_close(fh->hdr) < 0)
808 HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release free space info")
809
810 /* Reset the block iterator, if necessary */
811 /* (Can't put this in header "destroy" routine, because it has
812 * pointers to indirect blocks in the heap, which would create
813 * a reference loop and the objects couldn't be removed from
814 * the metadata cache - QAK)
815 */
816 if (H5HF__man_iter_ready(&fh->hdr->next_block))
817 if (H5HF__man_iter_reset(&fh->hdr->next_block) < 0)
818 HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reset block iterator")
819
820 /* Shut down the huge object information */
821 /* (Can't put this in header "destroy" routine, because it has
822 * has the address of an object in the file, which might be
823 * modified by the shutdown routine - QAK)
824 */
825 if (H5HF__huge_term(fh->hdr) < 0)
826 HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't release 'huge' object info")
827
828 /* Check for pending heap deletion */
829 if (fh->hdr->pending_delete) {
830 /* Set local info, so heap deletion can occur after decrementing the
831 * header's ref count
832 */
833 pending_delete = TRUE;
834 heap_addr = fh->hdr->heap_addr;
835 } /* end if */
836 } /* end if */
837
838 /* Decrement the reference count on the heap header */
839 /* (don't put in H5HF__hdr_fuse_decr() as the heap header may be evicted
840 * immediately -QAK)
841 */
842 if (H5HF__hdr_decr(fh->hdr) < 0)
843 HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header")
844
845 /* Check for pending heap deletion */
846 if (pending_delete) {
847 H5HF_hdr_t *hdr; /* Another pointer to fractal heap header */
848
849 /* Lock the heap header into memory */
850 if (NULL == (hdr = H5HF__hdr_protect(fh->f, heap_addr, H5AC__NO_FLAGS_SET)))
851 HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header")
852
853 /* Delete heap, starting with header (unprotects header) */
854 if (H5HF__hdr_delete(hdr) < 0)
855 HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "unable to delete fractal heap")
856 } /* end if */
857
858 done:
859 /* Release the fractal heap wrapper */
860 fh = H5FL_FREE(H5HF_t, fh);
861
862 FUNC_LEAVE_NOAPI(ret_value)
863 } /* end H5HF_close() */
864
865 /*-------------------------------------------------------------------------
866 * Function: H5HF_delete
867 *
868 * Purpose: Delete a fractal heap
869 *
870 * Return: SUCCEED/FAIL
871 *
872 * Programmer: Quincey Koziol
873 * Aug 4 2006
874 *
875 *-------------------------------------------------------------------------
876 */
877 herr_t
H5HF_delete(H5F_t * f,haddr_t fh_addr)878 H5HF_delete(H5F_t *f, haddr_t fh_addr)
879 {
880 H5HF_hdr_t *hdr = NULL; /* The fractal heap header information */
881 herr_t ret_value = SUCCEED; /* Return value */
882
883 FUNC_ENTER_NOAPI(FAIL)
884
885 /*
886 * Check arguments.
887 */
888 HDassert(f);
889 HDassert(H5F_addr_defined(fh_addr));
890
891 /* Lock the heap header into memory */
892 if (NULL == (hdr = H5HF__hdr_protect(f, fh_addr, H5AC__NO_FLAGS_SET)))
893 HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap header")
894
895 /* Check for files using shared heap header */
896 if (hdr->file_rc)
897 hdr->pending_delete = TRUE;
898 else {
899 /* Delete heap now, starting with header (unprotects header) */
900 if (H5HF__hdr_delete(hdr) < 0)
901 HGOTO_ERROR(H5E_HEAP, H5E_CANTDELETE, FAIL, "unable to delete fractal heap")
902 hdr = NULL;
903 } /* end if */
904
905 done:
906 /* Unprotect the header, if an error occurred */
907 if (hdr && H5AC_unprotect(f, H5AC_FHEAP_HDR, fh_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
908 HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap header")
909
910 FUNC_LEAVE_NOAPI(ret_value)
911 } /* end H5HF_delete() */
912