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