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  * Programmer:  Robb Matzke <matzke@llnl.gov>
16  *              Friday, March 27, 1998
17  *
18  * Purpose:	Operations on the global heap.  The global heap is the set of
19  *		all collections and each collection contains one or more
20  *		global heap objects.  An object belongs to exactly one
21  *		collection.  A collection is treated as an atomic entity for
22  *		the purposes of I/O and caching.
23  *
24  *		Each file has a small cache of global heap collections called
25  *		the CWFS list and recently accessed collections with free
26  *		space appear on this list.  As collections are accessed the
27  *		collection is moved toward the front of the list.  New
28  *		collections are added to the front of the list while old
29  *		collections are added to the end of the list.
30  *
31  *		The collection model reduces the overhead which would be
32  *		incurred if the global heap were a single object, and the
33  *		CWFS list allows the library to cheaply choose a collection
34  *		for a new object based on object size, amount of free space
35  *		in the collection, and temporal locality.
36  */
37 
38 /****************/
39 /* Module Setup */
40 /****************/
41 
42 #include "H5HGmodule.h"         /* This source code file is part of the H5HG module */
43 
44 
45 /***********/
46 /* Headers */
47 /***********/
48 #include "H5private.h"		/* Generic Functions			*/
49 #include "H5Eprivate.h"		/* Error handling		  	*/
50 #include "H5Fprivate.h"         /* File access				*/
51 #include "H5HGpkg.h"		/* Global heaps				*/
52 #include "H5MFprivate.h"	/* File memory management		*/
53 #include "H5MMprivate.h"	/* Memory management			*/
54 
55 
56 /****************/
57 /* Local Macros */
58 /****************/
59 
60 /*
61  * The maximum number of links allowed to a global heap object.
62  */
63 #define H5HG_MAXLINK	65535
64 
65 /*
66  * The maximum number of indices allowed in a global heap object.
67  */
68 #define H5HG_MAXIDX	65535
69 
70 
71 /******************/
72 /* Local Typedefs */
73 /******************/
74 
75 
76 /********************/
77 /* Package Typedefs */
78 /********************/
79 
80 
81 /********************/
82 /* Local Prototypes */
83 /********************/
84 
85 static haddr_t H5HG__create(H5F_t *f, size_t size);
86 
87 
88 /*********************/
89 /* Package Variables */
90 /*********************/
91 
92 /* Package initialization variable */
93 hbool_t H5_PKG_INIT_VAR = FALSE;
94 
95 /* Declare a free list to manage the H5HG_heap_t struct */
96 H5FL_DEFINE(H5HG_heap_t);
97 
98 /* Declare a free list to manage sequences of H5HG_obj_t's */
99 H5FL_SEQ_DEFINE(H5HG_obj_t);
100 
101 /* Declare a PQ free list to manage heap chunks */
102 H5FL_BLK_DEFINE(gheap_chunk);
103 
104 
105 /*****************************/
106 /* Library Private Variables */
107 /*****************************/
108 
109 
110 /*******************/
111 /* Local Variables */
112 /*******************/
113 
114 
115 
116 /*-------------------------------------------------------------------------
117  * Function:	H5HG__create
118  *
119  * Purpose:	Creates a global heap collection of the specified size.  If
120  *		SIZE is less than some minimum it will be readjusted.  The
121  *		new collection is allocated in the file and added to the
122  *		beginning of the CWFS list.
123  *
124  * Return:	Success:	Ptr to a cached heap.  The pointer is valid
125  *				only until some other hdf5 library function
126  *				is called.
127  *
128  *		Failure:	NULL
129  *
130  * Programmer:	Robb Matzke
131  *              Friday, March 27, 1998
132  *
133  *-------------------------------------------------------------------------
134  */
135 static haddr_t
H5HG__create(H5F_t * f,size_t size)136 H5HG__create(H5F_t *f, size_t size)
137 {
138     H5HG_heap_t	*heap = NULL;
139     uint8_t	*p = NULL;
140     haddr_t	addr = HADDR_UNDEF;
141     size_t	n;
142     haddr_t	ret_value = HADDR_UNDEF;        /* Return value */
143 
144     FUNC_ENTER_STATIC_TAG(H5AC__GLOBALHEAP_TAG)
145 
146     /* Check args */
147     HDassert(f);
148     if(size < H5HG_MINSIZE)
149         size = H5HG_MINSIZE;
150     size = H5HG_ALIGN(size);
151 
152     /* Create it */
153     H5_CHECK_OVERFLOW(size, size_t, hsize_t);
154     if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_GHEAP, (hsize_t)size)))
155         HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "unable to allocate file space for global heap")
156     if(NULL == (heap = H5FL_CALLOC(H5HG_heap_t)))
157         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "memory allocation failed")
158     heap->addr = addr;
159     heap->size = size;
160     heap->shared = H5F_SHARED(f);
161 
162     if(NULL == (heap->chunk = H5FL_BLK_MALLOC(gheap_chunk, size)))
163         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "memory allocation failed")
164     HDmemset(heap->chunk, 0, size);
165     heap->nalloc = H5HG_NOBJS(f, size);
166     heap->nused = 1; /* account for index 0, which is used for the free object */
167     if(NULL == (heap->obj = H5FL_SEQ_MALLOC(H5HG_obj_t, heap->nalloc)))
168         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "memory allocation failed")
169 
170     /* Initialize the header */
171     HDmemcpy(heap->chunk, H5HG_MAGIC, (size_t)H5_SIZEOF_MAGIC);
172     p = heap->chunk + H5_SIZEOF_MAGIC;
173     *p++ = H5HG_VERSION;
174     *p++ = 0; /*reserved*/
175     *p++ = 0; /*reserved*/
176     *p++ = 0; /*reserved*/
177     H5F_ENCODE_LENGTH(f, p, size);
178 
179     /*
180      * Padding so free space object is aligned. If malloc returned memory
181      * which was always at least H5HG_ALIGNMENT aligned then we could just
182      * align the pointer, but this might not be the case.
183      */
184     n = (size_t)H5HG_ALIGN(p - heap->chunk) - (size_t)(p - heap->chunk);
185 #ifdef OLD_WAY
186 /* Don't bother zeroing out the rest of the info in the heap -QAK */
187     HDmemset(p, 0, n);
188 #endif /* OLD_WAY */
189     p += n;
190 
191     /* The freespace object */
192     heap->obj[0].size = size - H5HG_SIZEOF_HDR(f);
193     HDassert(H5HG_ISALIGNED(heap->obj[0].size));
194     heap->obj[0].nrefs = 0;
195     heap->obj[0].begin = p;
196     UINT16ENCODE(p, 0);	/*object ID*/
197     UINT16ENCODE(p, 0);	/*reference count*/
198     UINT32ENCODE(p, 0); /*reserved*/
199     H5F_ENCODE_LENGTH(f, p, heap->obj[0].size);
200 #ifdef OLD_WAY
201 /* Don't bother zeroing out the rest of the info in the heap -QAK */
202     HDmemset (p, 0, (size_t)((heap->chunk+heap->size) - p));
203 #endif /* OLD_WAY */
204 
205     /* Add this heap to the beginning of the CWFS list */
206     if(H5F_cwfs_add(f, heap) < 0)
207 	HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "unable to add global heap collection to file's CWFS")
208 
209     /* Add the heap to the cache */
210     if(H5AC_insert_entry(f, H5AC_GHEAP, addr, heap, H5AC__NO_FLAGS_SET) < 0)
211 	HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, HADDR_UNDEF, "unable to cache global heap collection")
212 
213     ret_value = addr;
214 
215 done:
216     /* Cleanup on error */
217     if(!H5F_addr_defined(ret_value)) {
218         if(H5F_addr_defined(addr)) {
219             /* Release the space on disk */
220             if(H5MF_xfree(f, H5FD_MEM_GHEAP, addr, (hsize_t)size) < 0)
221                 HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, HADDR_UNDEF, "unable to free global heap")
222 
223             /* Check if the heap object was allocated */
224             if(heap)
225                 /* Destroy the heap object */
226                 if(H5HG_free(heap) < 0)
227                     HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, HADDR_UNDEF, "unable to destroy global heap collection")
228         } /* end if */
229     } /* end if */
230 
231     FUNC_LEAVE_NOAPI_TAG(ret_value);
232 } /* H5HG__create() */
233 
234 
235 /*-------------------------------------------------------------------------
236  * Function:	H5HG__protect
237  *
238  * Purpose:	Convenience wrapper around H5AC_protect on an indirect block
239  *
240  * Return:	Pointer to indirect block on success, NULL on failure
241  *
242  * Programmer:	Quincey Koziol
243  *              Wednesday, May  5, 2010
244  *
245  *-------------------------------------------------------------------------
246  */
247 H5HG_heap_t *
H5HG__protect(H5F_t * f,haddr_t addr,unsigned flags)248 H5HG__protect(H5F_t *f, haddr_t addr, unsigned flags)
249 {
250     H5HG_heap_t *heap;          /* Global heap */
251     H5HG_heap_t *ret_value = NULL;      /* Return value */
252 
253     FUNC_ENTER_PACKAGE
254 
255     /* Check arguments */
256     HDassert(f);
257     HDassert(H5F_addr_defined(addr));
258 
259     /* only H5AC__READ_ONLY_FLAG may appear in flags */
260     HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
261 
262     /* Lock the heap into memory */
263     if(NULL == (heap = (H5HG_heap_t *)H5AC_protect(f, H5AC_GHEAP, addr, f, flags)))
264         HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect global heap")
265 
266     /* Set the heap's address */
267     heap->addr = addr;
268 
269     /* Set the return value */
270     ret_value = heap;
271 
272 done:
273     FUNC_LEAVE_NOAPI(ret_value)
274 } /* H5HG__protect() */
275 
276 
277 /*-------------------------------------------------------------------------
278  * Function:	H5HG_alloc
279  *
280  * Purpose:	Given a heap with enough free space, this function will split
281  *		the free space to make a new empty heap object and initialize
282  *		the header.  SIZE is the exact size of the object data to be
283  *		stored. It will be increased to make room for the object
284  *		header and then rounded up for alignment.
285  *
286  * Return:	Success:	The heap object ID of the new object.
287  *
288  *		Failure:	0
289  *
290  * Programmer:	Robb Matzke
291  *              Friday, March 27, 1998
292  *
293  *-------------------------------------------------------------------------
294  */
295 static size_t
H5HG_alloc(H5F_t * f,H5HG_heap_t * heap,size_t size,unsigned * heap_flags_ptr)296 H5HG_alloc(H5F_t *f, H5HG_heap_t *heap, size_t size, unsigned *heap_flags_ptr)
297 {
298     size_t      idx;
299     uint8_t     *p;
300     size_t      need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(size);
301     size_t      ret_value = 0;          /* Return value */
302 
303     FUNC_ENTER_NOAPI_NOINIT
304 
305     /* Check args */
306     HDassert(heap);
307     HDassert(heap->obj[0].size>=need);
308     HDassert(heap_flags_ptr);
309 
310     /*
311      * Find an ID for the new object. ID zero is reserved for the free space
312      * object.
313      */
314     if(heap->nused <= H5HG_MAXIDX)
315         idx = heap->nused++;
316     else {
317         for(idx = 1; idx < heap->nused; idx++)
318             if(NULL == heap->obj[idx].begin)
319                 break;
320     } /* end else */
321 
322     HDassert(idx < heap->nused);
323 
324     /* Check if we need more room to store heap objects */
325     if(idx >= heap->nalloc) {
326         size_t new_alloc;       /* New allocation number */
327         H5HG_obj_t *new_obj;	/* New array of object descriptions */
328 
329         /* Determine the new number of objects to index */
330         /* nalloc is *not* guaranteed to be a power of 2! - NAF 10/26/09 */
331         new_alloc = MIN(MAX(heap->nalloc * 2, (idx + 1)), (H5HG_MAXIDX + 1));
332         HDassert(idx < new_alloc);
333 
334         /* Reallocate array of objects */
335         if(NULL == (new_obj = H5FL_SEQ_REALLOC(H5HG_obj_t, heap->obj, new_alloc)))
336             HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, 0, "memory allocation failed")
337 
338         /* Clear newly allocated space */
339         HDmemset(&new_obj[heap->nalloc], 0, (new_alloc - heap->nalloc) * sizeof(heap->obj[0]));
340 
341         /* Update heap information */
342         heap->nalloc = new_alloc;
343         heap->obj = new_obj;
344         HDassert(heap->nalloc > heap->nused);
345     } /* end if */
346 
347     /* Initialize the new object */
348     heap->obj[idx].nrefs = 0;
349     heap->obj[idx].size = size;
350     heap->obj[idx].begin = heap->obj[0].begin;
351     p = heap->obj[idx].begin;
352     UINT16ENCODE(p, idx);
353     UINT16ENCODE(p, 0); /*nrefs*/
354     UINT32ENCODE(p, 0); /*reserved*/
355     H5F_ENCODE_LENGTH (f, p, size);
356 
357     /* Fix the free space object */
358     if(need == heap->obj[0].size) {
359         /*
360          * All free space has been exhausted from this collection.
361          */
362         heap->obj[0].size = 0;
363         heap->obj[0].begin = NULL;
364     } /* end if */
365     else if(heap->obj[0].size-need >= H5HG_SIZEOF_OBJHDR (f)) {
366 	/*
367 	 * Some free space remains and it's larger than a heap object header,
368 	 * so write the new free heap object header to the heap.
369 	 */
370 	heap->obj[0].size -= need;
371 	heap->obj[0].begin += need;
372 	p = heap->obj[0].begin;
373 	UINT16ENCODE(p, 0);	/*id*/
374 	UINT16ENCODE(p, 0);	/*nrefs*/
375 	UINT32ENCODE(p, 0);	/*reserved*/
376 	H5F_ENCODE_LENGTH (f, p, heap->obj[0].size);
377 	HDassert(H5HG_ISALIGNED(heap->obj[0].size));
378     } /* end else-if */
379     else {
380 	/*
381 	 * Some free space remains but it's smaller than a heap object header,
382 	 * so we don't write the header.
383 	 */
384 	heap->obj[0].size -= need;
385 	heap->obj[0].begin += need;
386 	HDassert(H5HG_ISALIGNED(heap->obj[0].size));
387     }
388 
389     /* Mark the heap as dirty */
390     *heap_flags_ptr |= H5AC__DIRTIED_FLAG;
391 
392     /* Set the return value */
393     ret_value = idx;
394 
395 done:
396     FUNC_LEAVE_NOAPI(ret_value);
397 } /* end H5HG_alloc() */
398 
399 
400 /*-------------------------------------------------------------------------
401  * Function:	H5HG_extend
402  *
403  * Purpose:	Extend a heap to hold an object of SIZE bytes.
404  *		SIZE is the exact size of the object data to be
405  *		stored. It will be increased to make room for the object
406  *		header and then rounded up for alignment.
407  *
408  * Return:	Success:	Non-negative
409  *
410  *		Failure:	Negative
411  *
412  * Programmer:	Quincey Koziol
413  *              Saturday, June 12, 2004
414  *
415  *-------------------------------------------------------------------------
416  */
417 herr_t
H5HG_extend(H5F_t * f,haddr_t addr,size_t need)418 H5HG_extend(H5F_t *f, haddr_t addr, size_t need)
419 {
420     H5HG_heap_t *heap = NULL;       /* Pointer to heap to extend */
421     unsigned heap_flags = H5AC__NO_FLAGS_SET;   /* Flags to unprotecting heap */
422     size_t  old_size;               /* Previous size of the heap's chunk */
423     uint8_t *new_chunk;             /* Pointer to new chunk information */
424     uint8_t *p;                     /* Pointer to raw heap info */
425     unsigned u;                     /* Local index variable */
426     herr_t  ret_value = SUCCEED;    /* Return value */
427 
428     FUNC_ENTER_NOAPI_NOINIT
429 
430     /* Check args */
431     HDassert(f);
432     HDassert(H5F_addr_defined(addr));
433 
434     /* Protect the heap */
435     if(NULL == (heap = H5HG__protect(f, addr, H5AC__NO_FLAGS_SET)))
436         HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap")
437 
438     /* Re-allocate the heap information in memory */
439     if(NULL == (new_chunk = H5FL_BLK_REALLOC(gheap_chunk, heap->chunk, (heap->size + need))))
440         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "new heap allocation failed")
441     HDmemset(new_chunk + heap->size, 0, need);
442 
443     /* Adjust the size of the heap */
444     old_size = heap->size;
445     heap->size += need;
446 
447     /* Encode the new size of the heap */
448     p = new_chunk + H5_SIZEOF_MAGIC + 1 /* version */ + 3 /* reserved */;
449     H5F_ENCODE_LENGTH(f, p, heap->size);
450 
451     /* Move the pointers to the existing objects to their new locations */
452     for(u = 0; u < heap->nused; u++)
453         if(heap->obj[u].begin)
454             heap->obj[u].begin = new_chunk + (heap->obj[u].begin - heap->chunk);
455 
456     /* Update the heap chunk pointer now */
457     heap->chunk = new_chunk;
458 
459     /* Update the free space information for the heap  */
460     heap->obj[0].size += need;
461     if(heap->obj[0].begin == NULL)
462         heap->obj[0].begin = heap->chunk+old_size;
463     p = heap->obj[0].begin;
464     UINT16ENCODE(p, 0);	/*id*/
465     UINT16ENCODE(p, 0);	/*nrefs*/
466     UINT32ENCODE(p, 0);	/*reserved*/
467     H5F_ENCODE_LENGTH(f, p, heap->obj[0].size);
468     HDassert(H5HG_ISALIGNED(heap->obj[0].size));
469 
470     /* Resize the heap in the cache */
471     if(H5AC_resize_entry(heap, heap->size) < 0)
472         HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize global heap in cache")
473 
474     /* Mark the heap as dirty */
475     heap_flags |= H5AC__DIRTIED_FLAG;
476 
477 done:
478     if(heap && H5AC_unprotect(f, H5AC_GHEAP, heap->addr, heap, heap_flags) < 0)
479         HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to unprotect heap")
480 
481     FUNC_LEAVE_NOAPI(ret_value)
482 } /* end H5HG_extend() */
483 
484 
485 /*-------------------------------------------------------------------------
486  * Function:	H5HG_insert
487  *
488  * Purpose:	A new object is inserted into the global heap.  It will be
489  *		placed in the first collection on the CWFS list which has
490  *		enough free space and that collection will be advanced one
491  *		position in the list.  If no collection on the CWFS list has
492  *		enough space then  a new collection will be created.
493  *
494  *		It is legal to push a zero-byte object onto the heap to get
495  *		the reference count features of heap objects.
496  *
497  * Return:	Success:	Non-negative, and a heap object handle returned
498  *				through the HOBJ pointer.
499  *
500  *		Failure:	Negative
501  *
502  * Programmer:	Robb Matzke
503  *              Friday, March 27, 1998
504  *
505  *-------------------------------------------------------------------------
506  */
507 herr_t
H5HG_insert(H5F_t * f,size_t size,void * obj,H5HG_t * hobj)508 H5HG_insert(H5F_t *f, size_t size, void *obj, H5HG_t *hobj/*out*/)
509 {
510     size_t	need;		/*total space needed for object		*/
511     size_t	idx;
512     haddr_t	addr;           /* Address of heap to add object within */
513     H5HG_heap_t	*heap = NULL;
514     unsigned 	heap_flags = H5AC__NO_FLAGS_SET;
515     herr_t      ret_value = SUCCEED;    /* Return value */
516 
517     FUNC_ENTER_NOAPI_TAG(H5AC__GLOBALHEAP_TAG, FAIL)
518 
519     /* Check args */
520     HDassert(f);
521     HDassert(0 == size || obj);
522     HDassert(hobj);
523 
524     if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
525 	HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file")
526 
527     /* Find a large enough collection on the CWFS list */
528     need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(size);
529 
530     /* Look for a heap in the file's CWFS that has enough space for the object */
531     addr = HADDR_UNDEF;
532     if(H5F_cwfs_find_free_heap(f, need, &addr) < 0)
533         HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "error trying to locate heap")
534 
535     /*
536      * If we didn't find any collection with enough free space then allocate a
537      * new collection large enough for the message plus the collection header.
538      */
539     if(!H5F_addr_defined(addr)) {
540         addr = H5HG__create(f, need + H5HG_SIZEOF_HDR(f));
541 
542         if(!H5F_addr_defined(addr))
543 	    HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to allocate a global heap collection")
544     } /* end if */
545     HDassert(H5F_addr_defined(addr));
546 
547     if(NULL == (heap = H5HG__protect(f, addr, H5AC__NO_FLAGS_SET)))
548         HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap")
549 
550     /* Split the free space to make room for the new object */
551     if(0 == (idx = H5HG_alloc(f, heap, size, &heap_flags)))
552         HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "unable to allocate global heap object")
553 
554     /* Copy data into the heap */
555     if(size > 0) {
556         HDmemcpy(heap->obj[idx].begin + H5HG_SIZEOF_OBJHDR(f), obj, size);
557 #ifdef OLD_WAY
558 /* Don't bother zeroing out the rest of the info in the heap -QAK */
559         HDmemset(heap->obj[idx].begin + H5HG_SIZEOF_OBJHDR(f) + size, 0,
560                  need - (H5HG_SIZEOF_OBJHDR(f) + size));
561 #endif /* OLD_WAY */
562     } /* end if */
563     heap_flags |= H5AC__DIRTIED_FLAG;
564 
565     /* Return value */
566     hobj->addr = heap->addr;
567     hobj->idx = idx;
568 
569 done:
570     if(heap && H5AC_unprotect(f, H5AC_GHEAP, heap->addr, heap, heap_flags) < 0)
571         HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to unprotect heap.")
572 
573     FUNC_LEAVE_NOAPI_TAG(ret_value)
574 } /* H5HG_insert() */
575 
576 
577 /*-------------------------------------------------------------------------
578  * Function:	H5HG_read
579  *
580  * Purpose:	Reads the specified global heap object into the buffer OBJECT
581  *		supplied by the caller.  If the caller doesn't supply a
582  *		buffer then one will be allocated.  The buffer should be
583  *		large enough to hold the result.
584  *
585  * Return:	Success:	The buffer containing the result.
586  *
587  *		Failure:	NULL
588  *
589  * Programmer:	Robb Matzke
590  *              Monday, March 30, 1998
591  *
592  *-------------------------------------------------------------------------
593  */
594 void *
H5HG_read(H5F_t * f,H5HG_t * hobj,void * object,size_t * buf_size)595 H5HG_read(H5F_t *f, H5HG_t *hobj, void *object/*out*/, size_t *buf_size)
596 {
597     H5HG_heap_t	*heap = NULL;           /* Pointer to global heap object */
598     size_t	size;                   /* Size of the heap object */
599     uint8_t	*p;                     /* Pointer to object in heap buffer */
600     void        *orig_object = object;  /* Keep a copy of the original object pointer */
601     void	*ret_value = NULL;      /* Return value */
602 
603     FUNC_ENTER_NOAPI_TAG(H5AC__GLOBALHEAP_TAG, NULL)
604 
605     /* Check args */
606     HDassert(f);
607     HDassert(hobj);
608 
609     /* Load the heap */
610     if(NULL == (heap = H5HG__protect(f, hobj->addr, H5AC__READ_ONLY_FLAG)))
611 	HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect global heap")
612 
613     HDassert(hobj->idx < heap->nused);
614     HDassert(heap->obj[hobj->idx].begin);
615     size = heap->obj[hobj->idx].size;
616     p = heap->obj[hobj->idx].begin + H5HG_SIZEOF_OBJHDR(f);
617 
618     /* Allocate a buffer for the object read in, if the user didn't give one */
619     if(!object && NULL == (object = H5MM_malloc(size)))
620 	HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
621     HDmemcpy(object, p, size);
622 
623     /*
624      * Advance the heap in the CWFS list. We might have done this already
625      * with the H5AC_protect(), but it won't hurt to do it twice.
626      */
627     if(heap->obj[0].begin) {
628         if(H5F_cwfs_advance_heap(f, heap, FALSE) < 0)
629             HGOTO_ERROR(H5E_HEAP, H5E_CANTMODIFY, NULL, "can't adjust file's CWFS")
630     } /* end if */
631 
632     /* If the caller would like to know the heap object's size, set that */
633     if(buf_size)
634         *buf_size = size;
635 
636     /* Set return value */
637     ret_value = object;
638 
639 done:
640     if(heap && H5AC_unprotect(f, H5AC_GHEAP, hobj->addr, heap, H5AC__NO_FLAGS_SET) < 0)
641         HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release object header")
642 
643     if(NULL == ret_value && NULL == orig_object && object)
644         H5MM_free(object);
645 
646     FUNC_LEAVE_NOAPI_TAG(ret_value)
647 } /* end H5HG_read() */
648 
649 
650 /*-------------------------------------------------------------------------
651  * Function:	H5HG_link
652  *
653  * Purpose:	Adjusts the link count for a global heap object by adding
654  *		ADJUST to the current value.  This function will fail if the
655  *		new link count would overflow.  Nothing special happens when
656  *		the link count reaches zero; in order for a heap object to be
657  *		removed one must call H5HG_remove().
658  *
659  * Return:	Success:	Number of links present after the adjustment.
660  *
661  *		Failure:	Negative
662  *
663  * Programmer:	Robb Matzke
664  *              Monday, March 30, 1998
665  *
666  *-------------------------------------------------------------------------
667  */
668 int
H5HG_link(H5F_t * f,const H5HG_t * hobj,int adjust)669 H5HG_link(H5F_t *f, const H5HG_t *hobj, int adjust)
670 {
671     H5HG_heap_t *heap = NULL;
672     unsigned heap_flags = H5AC__NO_FLAGS_SET;
673     int ret_value = -1;         /* Return value */
674 
675     FUNC_ENTER_NOAPI_TAG(H5AC__GLOBALHEAP_TAG, FAIL)
676 
677     /* Check args */
678     HDassert(f);
679     HDassert(hobj);
680     if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
681 	HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file")
682 
683     /* Load the heap */
684     if(NULL == (heap = H5HG__protect(f, hobj->addr, H5AC__NO_FLAGS_SET)))
685         HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap")
686 
687     if(adjust != 0) {
688         HDassert(hobj->idx < heap->nused);
689         HDassert(heap->obj[hobj->idx].begin);
690         if((heap->obj[hobj->idx].nrefs + adjust) < 0)
691             HGOTO_ERROR(H5E_HEAP, H5E_BADRANGE, FAIL, "new link count would be out of range")
692         if((heap->obj[hobj->idx].nrefs + adjust) > H5HG_MAXLINK)
693             HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "new link count would be out of range")
694         heap->obj[hobj->idx].nrefs += adjust;
695         heap_flags |= H5AC__DIRTIED_FLAG;
696     } /* end if */
697 
698     /* Set return value */
699     ret_value = heap->obj[hobj->idx].nrefs;
700 
701 done:
702     if(heap && H5AC_unprotect(f, H5AC_GHEAP, hobj->addr, heap, heap_flags) < 0)
703         HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
704 
705     FUNC_LEAVE_NOAPI_TAG(ret_value)
706 } /* end H5HG_link() */
707 
708 
709 /*-------------------------------------------------------------------------
710  * Function:    H5HG_get_obj_size
711  *
712  * Purpose:     Returns the size of a global heap object.
713  * Return:      Success:        Non-negative
714  *
715  *              Failure:        Negative
716  *
717  * Programmer:  Neil Fortner
718  *              Thursday, February 12, 2015
719  *
720  *-------------------------------------------------------------------------
721  */
722 herr_t
H5HG_get_obj_size(H5F_t * f,H5HG_t * hobj,size_t * obj_size)723 H5HG_get_obj_size(H5F_t *f, H5HG_t *hobj, size_t *obj_size)
724 {
725     H5HG_heap_t *heap = NULL;           /* Pointer to global heap object */
726     herr_t      ret_value = SUCCEED;    /* Return value */
727 
728     FUNC_ENTER_NOAPI_TAG(H5AC__GLOBALHEAP_TAG, FAIL)
729 
730     /* Check args */
731     HDassert(f);
732     HDassert(hobj);
733     HDassert(obj_size);
734 
735     /* Load the heap */
736     if(NULL == (heap = H5HG__protect(f, hobj->addr, H5AC__READ_ONLY_FLAG)))
737         HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap")
738 
739     HDassert(hobj->idx < heap->nused);
740     HDassert(heap->obj[hobj->idx].begin);
741 
742     /* Set object size */
743     *obj_size = heap->obj[hobj->idx].size;
744 
745 done:
746     if(heap && H5AC_unprotect(f, H5AC_GHEAP, hobj->addr, heap, H5AC__NO_FLAGS_SET) < 0)
747         HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
748 
749     FUNC_LEAVE_NOAPI_TAG(ret_value)
750 } /* end H5HG_get_obj_size() */
751 
752 
753 /*-------------------------------------------------------------------------
754  * Function:	H5HG_remove
755  *
756  * Purpose:	Removes the specified object from the global heap.
757  *
758  * Return:	Non-negative on success/Negative on failure
759  *
760  * Programmer:	Robb Matzke
761  *              Monday, March 30, 1998
762  *
763  *-------------------------------------------------------------------------
764  */
765 herr_t
H5HG_remove(H5F_t * f,H5HG_t * hobj)766 H5HG_remove (H5F_t *f, H5HG_t *hobj)
767 {
768     H5HG_heap_t *heap = NULL;
769     uint8_t     *p = NULL, *obj_start = NULL;
770     size_t      need;
771     unsigned    u;
772     unsigned    flags = H5AC__NO_FLAGS_SET;/* Whether the heap gets deleted */
773     herr_t      ret_value = SUCCEED;       /* Return value */
774 
775     FUNC_ENTER_NOAPI_TAG(H5AC__GLOBALHEAP_TAG, FAIL)
776 
777     /* Check args */
778     HDassert(f);
779     HDassert(hobj);
780     if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
781         HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file")
782 
783     /* Load the heap */
784     if(NULL == (heap = H5HG__protect(f, hobj->addr, H5AC__NO_FLAGS_SET)))
785         HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect global heap")
786 
787     HDassert(hobj->idx < heap->nused);
788     HDassert(heap->obj[hobj->idx].begin);
789     obj_start = heap->obj[hobj->idx].begin;
790     /* Include object header size */
791     need = H5HG_ALIGN(heap->obj[hobj->idx].size) + H5HG_SIZEOF_OBJHDR(f);
792 
793     /* Move the new free space to the end of the heap */
794     for(u = 0; u < heap->nused; u++)
795         if(heap->obj[u].begin > heap->obj[hobj->idx].begin)
796             heap->obj[u].begin -= need;
797     if(NULL == heap->obj[0].begin) {
798         heap->obj[0].begin = heap->chunk + (heap->size - need);
799         heap->obj[0].size = need;
800         heap->obj[0].nrefs = 0;
801     } /* end if */
802     else
803         heap->obj[0].size += need;
804     HDmemmove(obj_start, obj_start + need,
805               heap->size - (size_t)((obj_start + need) - heap->chunk));
806     if(heap->obj[0].size >= H5HG_SIZEOF_OBJHDR(f)) {
807         p = heap->obj[0].begin;
808         UINT16ENCODE(p, 0); /*id*/
809         UINT16ENCODE(p, 0); /*nrefs*/
810         UINT32ENCODE(p, 0); /*reserved*/
811         H5F_ENCODE_LENGTH (f, p, heap->obj[0].size);
812     } /* end if */
813     HDmemset(heap->obj + hobj->idx, 0, sizeof(H5HG_obj_t));
814     flags |= H5AC__DIRTIED_FLAG;
815 
816     if((heap->obj[0].size + H5HG_SIZEOF_HDR(f)) == heap->size) {
817         /*
818          * The collection is empty. Remove it from the CWFS list and return it
819          * to the file free list.
820          */
821         flags |= H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; /* Indicate that the object was deleted, for the unprotect call */
822     } /* end if */
823     else {
824         /*
825          * If the heap is in the CWFS list then advance it one position.  The
826          * H5AC_protect() might have done that too, but that's okay.  If the
827          * heap isn't on the CWFS list then add it to the end.
828          */
829         if(H5F_cwfs_advance_heap(f, heap, TRUE) < 0)
830             HGOTO_ERROR(H5E_HEAP, H5E_CANTMODIFY, FAIL, "can't adjust file's CWFS")
831     } /* end else */
832 
833 done:
834     if(heap && H5AC_unprotect(f, H5AC_GHEAP, hobj->addr, heap, flags) < 0)
835         HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
836 
837     FUNC_LEAVE_NOAPI_TAG(ret_value);
838 } /* end H5HG_remove() */
839 
840 
841 /*-------------------------------------------------------------------------
842  * Function:	H5HG_free
843  *
844  * Purpose:	Destroys a global heap collection in memory
845  *
846  * Return:	Non-negative on success/Negative on failure
847  *
848  * Programmer:	Quincey Koziol
849  *              Wednesday, January 15, 2003
850  *
851  *-------------------------------------------------------------------------
852  */
853 herr_t
H5HG_free(H5HG_heap_t * heap)854 H5HG_free(H5HG_heap_t *heap)
855 {
856     herr_t ret_value = SUCCEED;         /* Return value */
857 
858     FUNC_ENTER_NOAPI(FAIL)
859 
860     /* Check arguments */
861     HDassert(heap);
862 
863     /* Remove the heap from the CWFS list */
864     if(H5F_cwfs_remove_heap(heap->shared, heap) < 0)
865         HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "can't remove heap from file's CWFS")
866 
867     if(heap->chunk)
868         heap->chunk = H5FL_BLK_FREE(gheap_chunk, heap->chunk);
869     if(heap->obj)
870         heap->obj = H5FL_SEQ_FREE(H5HG_obj_t, heap->obj);
871     heap = H5FL_FREE(H5HG_heap_t, heap);
872 
873 done:
874     FUNC_LEAVE_NOAPI(ret_value)
875 } /* H5HG_free() */
876 
877