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