Line | Count | Source (jump to first uncovered line) |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the LICENSE file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | /*------------------------------------------------------------------------- |
14 | | * |
15 | | * Created: H5HL.c |
16 | | * |
17 | | * Purpose: Heap functions for the local heaps used by symbol |
18 | | * tables to store names (among other things). |
19 | | * |
20 | | *------------------------------------------------------------------------- |
21 | | */ |
22 | | |
23 | | /****************/ |
24 | | /* Module Setup */ |
25 | | /****************/ |
26 | | |
27 | | #include "H5HLmodule.h" /* This source code file is part of the H5HL module */ |
28 | | |
29 | | /***********/ |
30 | | /* Headers */ |
31 | | /***********/ |
32 | | #include "H5private.h" /* Generic Functions */ |
33 | | #include "H5ACprivate.h" /* Metadata Cache */ |
34 | | #include "H5Eprivate.h" /* Error Handling */ |
35 | | #include "H5Fprivate.h" /* Files */ |
36 | | #include "H5FLprivate.h" /* Free Lists */ |
37 | | #include "H5HLpkg.h" /* Local Heaps */ |
38 | | #include "H5MFprivate.h" /* File Memory Management */ |
39 | | #include "H5MMprivate.h" /* Memory Management */ |
40 | | |
41 | | /****************/ |
42 | | /* Local Macros */ |
43 | | /****************/ |
44 | | |
45 | 0 | #define H5HL_MIN_HEAP 128 /* Minimum size to reduce heap buffer to */ |
46 | | |
47 | | /******************/ |
48 | | /* Local Typedefs */ |
49 | | /******************/ |
50 | | |
51 | | /********************/ |
52 | | /* Package Typedefs */ |
53 | | /********************/ |
54 | | |
55 | | /********************/ |
56 | | /* Local Prototypes */ |
57 | | /********************/ |
58 | | |
59 | | static H5HL_free_t *H5HL__remove_free(H5HL_t *heap, H5HL_free_t *fl); |
60 | | static herr_t H5HL__minimize_heap_space(H5F_t *f, H5HL_t *heap); |
61 | | static herr_t H5HL__dirty(H5HL_t *heap); |
62 | | |
63 | | /*********************/ |
64 | | /* Package Variables */ |
65 | | /*********************/ |
66 | | |
67 | | /* Package initialization variable */ |
68 | | bool H5_PKG_INIT_VAR = false; |
69 | | |
70 | | /* Declare a free list to manage the H5HL_free_t struct */ |
71 | | H5FL_DEFINE(H5HL_free_t); |
72 | | |
73 | | /* Declare a PQ free list to manage the heap chunk information */ |
74 | | H5FL_BLK_DEFINE(lheap_chunk); |
75 | | |
76 | | /*****************************/ |
77 | | /* Library Private Variables */ |
78 | | /*****************************/ |
79 | | |
80 | | /*******************/ |
81 | | /* Local Variables */ |
82 | | /*******************/ |
83 | | |
84 | | /*------------------------------------------------------------------------- |
85 | | * Function: H5HL_create |
86 | | * |
87 | | * Purpose: Creates a new heap data structure on disk and caches it |
88 | | * in memory. SIZE_HINT is a hint for the initial size of the |
89 | | * data area of the heap. If size hint is invalid then a |
90 | | * reasonable (but probably not optimal) size will be chosen. |
91 | | * |
92 | | * Return: Success: SUCCEED. The file address of new heap is |
93 | | * returned through the ADDR argument. |
94 | | * Failure: FAIL. addr_p will be HADDR_UNDEF. |
95 | | * |
96 | | *------------------------------------------------------------------------- |
97 | | */ |
98 | | herr_t |
99 | | H5HL_create(H5F_t *f, size_t size_hint, haddr_t *addr_p /*out*/) |
100 | 0 | { |
101 | 0 | H5HL_t *heap = NULL; /* Heap created */ |
102 | 0 | H5HL_prfx_t *prfx = NULL; /* Heap prefix */ |
103 | 0 | hsize_t total_size = 0; /* Total heap size on disk */ |
104 | 0 | herr_t ret_value = SUCCEED; |
105 | |
|
106 | 0 | FUNC_ENTER_NOAPI(FAIL) |
107 | | |
108 | | /* check arguments */ |
109 | 0 | assert(f); |
110 | 0 | assert(addr_p); |
111 | | |
112 | | /* Adjust size hint as necessary */ |
113 | 0 | if (size_hint && size_hint < H5HL_SIZEOF_FREE(f)) |
114 | 0 | size_hint = H5HL_SIZEOF_FREE(f); |
115 | 0 | size_hint = H5HL_ALIGN(size_hint); |
116 | | |
117 | | /* Allocate new heap structure */ |
118 | 0 | if (NULL == (heap = H5HL__new(H5F_SIZEOF_SIZE(f), H5F_SIZEOF_ADDR(f), H5HL_SIZEOF_HDR(f)))) |
119 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate new heap struct"); |
120 | | |
121 | | /* Allocate file space */ |
122 | 0 | total_size = heap->prfx_size + size_hint; |
123 | 0 | if (HADDR_UNDEF == (heap->prfx_addr = H5MF_alloc(f, H5FD_MEM_LHEAP, total_size))) |
124 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "unable to allocate file memory"); |
125 | | |
126 | | /* Initialize info */ |
127 | 0 | heap->single_cache_obj = true; |
128 | 0 | heap->dblk_addr = heap->prfx_addr + (hsize_t)heap->prfx_size; |
129 | 0 | heap->dblk_size = size_hint; |
130 | 0 | if (size_hint) |
131 | 0 | if (NULL == (heap->dblk_image = H5FL_BLK_CALLOC(lheap_chunk, size_hint))) |
132 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
133 | | |
134 | | /* free list */ |
135 | 0 | if (size_hint) { |
136 | 0 | if (NULL == (heap->freelist = H5FL_MALLOC(H5HL_free_t))) |
137 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
138 | 0 | heap->freelist->offset = 0; |
139 | 0 | heap->freelist->size = size_hint; |
140 | 0 | heap->freelist->prev = heap->freelist->next = NULL; |
141 | 0 | heap->free_block = 0; |
142 | 0 | } |
143 | 0 | else { |
144 | 0 | heap->freelist = NULL; |
145 | 0 | heap->free_block = H5HL_FREE_NULL; |
146 | 0 | } |
147 | | |
148 | | /* Allocate the heap prefix */ |
149 | 0 | if (NULL == (prfx = H5HL__prfx_new(heap))) |
150 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
151 | | |
152 | | /* Add to cache */ |
153 | 0 | if (FAIL == H5AC_insert_entry(f, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, H5AC__NO_FLAGS_SET)) |
154 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to cache local heap prefix"); |
155 | | |
156 | | /* Set address to return */ |
157 | 0 | *addr_p = heap->prfx_addr; |
158 | |
|
159 | 0 | done: |
160 | 0 | if (ret_value < 0) { |
161 | 0 | *addr_p = HADDR_UNDEF; |
162 | 0 | if (prfx) { |
163 | 0 | if (FAIL == H5HL__prfx_dest(prfx)) |
164 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy local heap prefix"); |
165 | 0 | } |
166 | 0 | else { |
167 | 0 | if (heap) { |
168 | 0 | if (H5_addr_defined(heap->prfx_addr)) |
169 | 0 | if (FAIL == H5MF_xfree(f, H5FD_MEM_LHEAP, heap->prfx_addr, total_size)) |
170 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "can't release heap data?"); |
171 | 0 | if (FAIL == H5HL__dest(heap)) |
172 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy local heap"); |
173 | 0 | } |
174 | 0 | } |
175 | 0 | } |
176 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
177 | 0 | } /* end H5HL_create() */ |
178 | | |
179 | | /*------------------------------------------------------------------------- |
180 | | * Function: H5HL__minimize_heap_space |
181 | | * |
182 | | * Purpose: Go through the heap's freelist and determine if we can |
183 | | * eliminate the free blocks at the tail of the buffer. |
184 | | * |
185 | | * Return: SUCCEED/FAIL |
186 | | * |
187 | | *------------------------------------------------------------------------- |
188 | | */ |
189 | | static herr_t |
190 | | H5HL__minimize_heap_space(H5F_t *f, H5HL_t *heap) |
191 | 0 | { |
192 | 0 | size_t new_heap_size = heap->dblk_size; /* New size of heap */ |
193 | 0 | herr_t ret_value = SUCCEED; |
194 | |
|
195 | 0 | FUNC_ENTER_PACKAGE |
196 | | |
197 | | /* Check args */ |
198 | 0 | assert(f); |
199 | 0 | assert(heap); |
200 | | |
201 | | /* Check to see if we can reduce the size of the heap in memory by |
202 | | * eliminating free blocks at the tail of the buffer before flushing the |
203 | | * buffer out. |
204 | | */ |
205 | 0 | if (heap->freelist) { |
206 | 0 | H5HL_free_t *tmp_fl; |
207 | 0 | H5HL_free_t *last_fl = NULL; |
208 | | |
209 | | /* Search for a free block at the end of the buffer */ |
210 | 0 | for (tmp_fl = heap->freelist; tmp_fl; tmp_fl = tmp_fl->next) |
211 | | /* Check if the end of this free block is at the end of the buffer */ |
212 | 0 | if (tmp_fl->offset + tmp_fl->size == heap->dblk_size) { |
213 | 0 | last_fl = tmp_fl; |
214 | 0 | break; |
215 | 0 | } |
216 | | |
217 | | /* Found free block at the end of the buffer, decide what to do |
218 | | * about it |
219 | | */ |
220 | 0 | if (last_fl) { |
221 | | /* If the last free block's size is more than half the memory |
222 | | * buffer size (and the memory buffer is larger than the |
223 | | * minimum size), reduce or eliminate it. |
224 | | */ |
225 | 0 | if (last_fl->size >= (heap->dblk_size / 2) && heap->dblk_size > H5HL_MIN_HEAP) { |
226 | | /* Reduce size of buffer until it's too small or would |
227 | | * eliminate the free block |
228 | | */ |
229 | 0 | while (new_heap_size > H5HL_MIN_HEAP && |
230 | 0 | new_heap_size >= (last_fl->offset + H5HL_SIZEOF_FREE(f))) |
231 | 0 | new_heap_size /= 2; |
232 | | |
233 | | /* Check if reducing the memory buffer size would |
234 | | * eliminate the free block |
235 | | */ |
236 | 0 | if (new_heap_size < (last_fl->offset + H5HL_SIZEOF_FREE(f))) { |
237 | | /* Check if this is the only block on the free list */ |
238 | 0 | if (last_fl->prev == NULL && last_fl->next == NULL) { |
239 | | /* Double the new memory size */ |
240 | 0 | new_heap_size *= 2; |
241 | | |
242 | | /* Truncate the free block */ |
243 | 0 | last_fl->size = H5HL_ALIGN(new_heap_size - last_fl->offset); |
244 | 0 | new_heap_size = last_fl->offset + last_fl->size; |
245 | 0 | assert(last_fl->size >= H5HL_SIZEOF_FREE(f)); |
246 | 0 | } |
247 | 0 | else { |
248 | | /* Set the size of the memory buffer to the start |
249 | | * of the free list |
250 | | */ |
251 | 0 | new_heap_size = last_fl->offset; |
252 | | |
253 | | /* Eliminate the free block from the list */ |
254 | 0 | last_fl = H5HL__remove_free(heap, last_fl); |
255 | 0 | } |
256 | 0 | } |
257 | 0 | else { |
258 | | /* Truncate the free block */ |
259 | 0 | last_fl->size = H5HL_ALIGN(new_heap_size - last_fl->offset); |
260 | 0 | new_heap_size = last_fl->offset + last_fl->size; |
261 | 0 | assert(last_fl->size >= H5HL_SIZEOF_FREE(f)); |
262 | 0 | assert(last_fl->size == H5HL_ALIGN(last_fl->size)); |
263 | 0 | } |
264 | 0 | } |
265 | 0 | } |
266 | 0 | } |
267 | | |
268 | | /* If the heap grew smaller than disk storage then move the |
269 | | * data segment of the heap to another contiguous block of disk |
270 | | * storage. |
271 | | */ |
272 | 0 | if (new_heap_size != heap->dblk_size) { |
273 | 0 | assert(new_heap_size < heap->dblk_size); |
274 | | |
275 | | /* Resize the memory buffer */ |
276 | 0 | if (NULL == (heap->dblk_image = H5FL_BLK_REALLOC(lheap_chunk, heap->dblk_image, new_heap_size))) |
277 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
278 | | |
279 | | /* Reallocate data block in file */ |
280 | 0 | if (FAIL == H5HL__dblk_realloc(f, heap, new_heap_size)) |
281 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "reallocating data block failed"); |
282 | 0 | } |
283 | | |
284 | 0 | done: |
285 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
286 | 0 | } /* H5HL__minimize_heap_space() */ |
287 | | |
288 | | /*------------------------------------------------------------------------- |
289 | | * Function: H5HL_protect |
290 | | * |
291 | | * Purpose: This function is a wrapper for the H5AC_protect call. |
292 | | * |
293 | | * Return: Success: Non-NULL pointer to the local heap prefix. |
294 | | * Failure: NULL |
295 | | * |
296 | | *------------------------------------------------------------------------- |
297 | | */ |
298 | | H5HL_t * |
299 | | H5HL_protect(H5F_t *f, haddr_t addr, unsigned flags) |
300 | 1.70k | { |
301 | 1.70k | H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */ |
302 | 1.70k | H5HL_prfx_t *prfx = NULL; /* Local heap prefix */ |
303 | 1.70k | H5HL_dblk_t *dblk = NULL; /* Local heap data block */ |
304 | 1.70k | H5HL_t *heap = NULL; /* Heap data structure */ |
305 | 1.70k | H5HL_t *ret_value = NULL; |
306 | | |
307 | 1.70k | FUNC_ENTER_NOAPI(NULL) |
308 | | |
309 | | /* Check arguments */ |
310 | 1.70k | assert(f); |
311 | 1.70k | assert(H5_addr_defined(addr)); |
312 | | |
313 | | /* Only the H5AC__READ_ONLY_FLAG may appear in flags */ |
314 | 1.70k | assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); |
315 | | |
316 | | /* Construct the user data for protect callback */ |
317 | 1.70k | prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); |
318 | 1.70k | prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); |
319 | 1.70k | prfx_udata.prfx_addr = addr; |
320 | 1.70k | prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); |
321 | | |
322 | | /* Protect the local heap prefix */ |
323 | 1.70k | if (NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, H5AC_LHEAP_PRFX, addr, &prfx_udata, flags))) |
324 | 148 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to load heap prefix"); |
325 | | |
326 | | /* Get the pointer to the heap */ |
327 | 1.55k | heap = prfx->heap; |
328 | | |
329 | | /* Check if the heap is already pinned in memory */ |
330 | | /* (for re-entrant situation) */ |
331 | 1.55k | if (heap->prots == 0) { |
332 | 1.55k | void *pin_obj; /* Pointer to local heap object to pin */ |
333 | | |
334 | | /* Check if heap has separate data block */ |
335 | 1.55k | if (heap->single_cache_obj) |
336 | | /* Pin prefix */ |
337 | 77 | pin_obj = prfx; |
338 | 1.48k | else { |
339 | | /* Protect the local heap data block */ |
340 | 1.48k | if (NULL == |
341 | 1.48k | (dblk = (H5HL_dblk_t *)H5AC_protect(f, H5AC_LHEAP_DBLK, heap->dblk_addr, heap, flags))) |
342 | 206 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to load heap data block"); |
343 | | |
344 | | /* Pin data block */ |
345 | 1.27k | pin_obj = dblk; |
346 | 1.27k | } |
347 | | |
348 | | /* Pin local heap object */ |
349 | 1.35k | if (H5AC_pin_protected_entry(pin_obj) < 0) |
350 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPIN, NULL, "unable to pin local heap object"); |
351 | 1.35k | } |
352 | | |
353 | | /* Increment # of times heap is protected */ |
354 | 1.35k | heap->prots++; |
355 | | |
356 | | /* Set return value */ |
357 | 1.35k | ret_value = heap; |
358 | | |
359 | 1.70k | done: |
360 | | /* Release the prefix from the cache, now pinned */ |
361 | 1.70k | if (prfx && heap && H5AC_unprotect(f, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, H5AC__NO_FLAGS_SET) < 0) |
362 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release local heap prefix"); |
363 | | |
364 | | /* Release the data block from the cache, now pinned */ |
365 | 1.70k | if (dblk && heap && H5AC_unprotect(f, H5AC_LHEAP_DBLK, heap->dblk_addr, dblk, H5AC__NO_FLAGS_SET) < 0) |
366 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, NULL, "unable to release local heap data block"); |
367 | | |
368 | 1.70k | FUNC_LEAVE_NOAPI(ret_value) |
369 | 1.70k | } /* end H5HL_protect() */ |
370 | | |
371 | | /*------------------------------------------------------------------------- |
372 | | * Function: H5HL_offset_into |
373 | | * |
374 | | * Purpose: Called directly after the call to H5HL_protect so that |
375 | | * a pointer to the object in the heap can be obtained. |
376 | | * |
377 | | * Return: Success: Valid pointer |
378 | | * Failure: NULL |
379 | | * |
380 | | *------------------------------------------------------------------------- |
381 | | */ |
382 | | void * |
383 | | H5HL_offset_into(const H5HL_t *heap, size_t offset) |
384 | 3.93k | { |
385 | 3.93k | void *ret_value = NULL; |
386 | | |
387 | 3.93k | FUNC_ENTER_NOAPI(NULL) |
388 | | |
389 | | /* Sanity check */ |
390 | 3.93k | assert(heap); |
391 | 3.93k | if (offset >= heap->dblk_size) |
392 | 757 | HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, NULL, "unable to offset into local heap data block"); |
393 | | |
394 | 3.17k | ret_value = heap->dblk_image + offset; |
395 | | |
396 | 3.93k | done: |
397 | 3.93k | FUNC_LEAVE_NOAPI(ret_value) |
398 | 3.93k | } /* end H5HL_offset_into() */ |
399 | | |
400 | | /*------------------------------------------------------------------------- |
401 | | * Function: H5HL_unprotect |
402 | | * |
403 | | * Purpose: Unprotect the data retrieved by the H5HL_protect call. |
404 | | * |
405 | | * Return: SUCCEED/FAIL |
406 | | * |
407 | | *------------------------------------------------------------------------- |
408 | | */ |
409 | | herr_t |
410 | | H5HL_unprotect(H5HL_t *heap) |
411 | 1.35k | { |
412 | 1.35k | herr_t ret_value = SUCCEED; |
413 | | |
414 | 1.35k | FUNC_ENTER_NOAPI(FAIL) |
415 | | |
416 | | /* Check arguments */ |
417 | 1.35k | assert(heap); |
418 | | |
419 | | /* Decrement # of times heap is protected */ |
420 | 1.35k | heap->prots--; |
421 | | |
422 | | /* Check for last unprotection of heap */ |
423 | 1.35k | if (heap->prots == 0) { |
424 | | /* Check for separate heap data block */ |
425 | 1.35k | if (heap->single_cache_obj) { |
426 | | /* Mark local heap prefix as evictable again */ |
427 | 77 | if (FAIL == H5AC_unpin_entry(heap->prfx)) |
428 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin local heap data block"); |
429 | 77 | } |
430 | 1.27k | else { |
431 | | /* Sanity check */ |
432 | 1.27k | assert(heap->dblk); |
433 | | |
434 | | /* Mark local heap data block as evictable again */ |
435 | | /* (data block still pins prefix) */ |
436 | 1.27k | if (FAIL == H5AC_unpin_entry(heap->dblk)) |
437 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin local heap data block"); |
438 | 1.27k | } |
439 | 1.35k | } |
440 | | |
441 | 1.35k | done: |
442 | 1.35k | FUNC_LEAVE_NOAPI(ret_value) |
443 | 1.35k | } /* end H5HL_unprotect() */ |
444 | | |
445 | | /*------------------------------------------------------------------------- |
446 | | * Function: H5HL__remove_free |
447 | | * |
448 | | * Purpose: Removes free list element FL from the specified heap and |
449 | | * frees it. |
450 | | * |
451 | | * Return: NULL |
452 | | * |
453 | | *------------------------------------------------------------------------- |
454 | | */ |
455 | | static H5HL_free_t * |
456 | | H5HL__remove_free(H5HL_t *heap, H5HL_free_t *fl) |
457 | 0 | { |
458 | 0 | H5HL_free_t *ret_value = NULL; |
459 | |
|
460 | 0 | FUNC_ENTER_PACKAGE_NOERR |
461 | |
|
462 | 0 | if (fl->prev) |
463 | 0 | fl->prev->next = fl->next; |
464 | 0 | if (fl->next) |
465 | 0 | fl->next->prev = fl->prev; |
466 | |
|
467 | 0 | if (!fl->prev) |
468 | 0 | heap->freelist = fl->next; |
469 | | |
470 | | /* H5FL_FREE always returns NULL so we can't check for errors */ |
471 | 0 | ret_value = (H5HL_free_t *)H5FL_FREE(H5HL_free_t, fl); |
472 | |
|
473 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
474 | 0 | } /* end H5HL__remove_free() */ |
475 | | |
476 | | /*------------------------------------------------------------------------- |
477 | | * Function: H5HL__dirty |
478 | | * |
479 | | * Purpose: Mark heap as dirty |
480 | | * |
481 | | * Return: SUCCEED/FAIL |
482 | | * |
483 | | *------------------------------------------------------------------------- |
484 | | */ |
485 | | static herr_t |
486 | | H5HL__dirty(H5HL_t *heap) |
487 | 0 | { |
488 | 0 | herr_t ret_value = SUCCEED; |
489 | |
|
490 | 0 | FUNC_ENTER_PACKAGE |
491 | | |
492 | | /* Check arguments */ |
493 | 0 | assert(heap); |
494 | 0 | assert(heap->prfx); |
495 | | |
496 | | /* Mark heap data block as dirty, if there is one */ |
497 | 0 | if (!heap->single_cache_obj) { |
498 | | /* Sanity check */ |
499 | 0 | assert(heap->dblk); |
500 | |
|
501 | 0 | if (FAIL == H5AC_mark_entry_dirty(heap->dblk)) |
502 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark heap data block as dirty"); |
503 | 0 | } |
504 | | |
505 | | /* Mark heap prefix as dirty */ |
506 | 0 | if (FAIL == H5AC_mark_entry_dirty(heap->prfx)) |
507 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark heap prefix as dirty"); |
508 | | |
509 | 0 | done: |
510 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
511 | 0 | } /* end H5HL__dirty() */ |
512 | | |
513 | | /*------------------------------------------------------------------------- |
514 | | * Function: H5HL_insert |
515 | | * |
516 | | * Purpose: Inserts a new item into the heap. |
517 | | * |
518 | | * Return: Success: SUCCEED |
519 | | * Offset set to location of new item within heap |
520 | | * |
521 | | * Failure: FAIL |
522 | | * Offset set to SIZE_MAX |
523 | | * |
524 | | *------------------------------------------------------------------------- |
525 | | */ |
526 | | herr_t |
527 | | H5HL_insert(H5F_t *f, H5HL_t *heap, size_t buf_size, const void *buf, size_t *offset_out) |
528 | 0 | { |
529 | 0 | H5HL_free_t *fl = NULL, *last_fl = NULL; |
530 | 0 | size_t need_size; |
531 | 0 | size_t offset = 0; |
532 | 0 | bool found; |
533 | 0 | herr_t ret_value = SUCCEED; |
534 | |
|
535 | 0 | FUNC_ENTER_NOAPI(FAIL) |
536 | | |
537 | | /* Check arguments */ |
538 | 0 | assert(f); |
539 | 0 | assert(heap); |
540 | 0 | assert(buf_size > 0); |
541 | 0 | assert(buf); |
542 | 0 | assert(offset_out); |
543 | | |
544 | | /* Mark heap as dirty in cache */ |
545 | | /* (A bit early in the process, but it's difficult to determine in the |
546 | | * code below where to mark the heap as dirty, especially in error cases, |
547 | | * so we just accept that an extra flush of the heap info could occur |
548 | | * if an error occurs -QAK) |
549 | | */ |
550 | 0 | if (FAIL == H5HL__dirty(heap)) |
551 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark heap as dirty"); |
552 | | |
553 | | /* In order to keep the free list descriptors aligned on word boundaries, |
554 | | * whatever that might mean, we round the size up to the next multiple of |
555 | | * a word. |
556 | | */ |
557 | 0 | need_size = H5HL_ALIGN(buf_size); |
558 | | |
559 | | /* Look for a free slot large enough for this object and which would |
560 | | * leave zero or at least H5G_SIZEOF_FREE bytes left over. |
561 | | */ |
562 | 0 | for (fl = heap->freelist, found = false; fl; fl = fl->next) { |
563 | 0 | if (fl->size > need_size && fl->size - need_size >= H5HL_SIZEOF_FREE(f)) { |
564 | | /* A big enough free block was found */ |
565 | 0 | offset = fl->offset; |
566 | 0 | fl->offset += need_size; |
567 | 0 | fl->size -= need_size; |
568 | 0 | assert(fl->offset == H5HL_ALIGN(fl->offset)); |
569 | 0 | assert(fl->size == H5HL_ALIGN(fl->size)); |
570 | 0 | found = true; |
571 | 0 | break; |
572 | 0 | } |
573 | 0 | else if (fl->size == need_size) { |
574 | | /* Free block of exact size found */ |
575 | 0 | offset = fl->offset; |
576 | 0 | fl = H5HL__remove_free(heap, fl); |
577 | 0 | found = true; |
578 | 0 | break; |
579 | 0 | } |
580 | 0 | else if (!last_fl || last_fl->offset < fl->offset) { |
581 | | /* Track free space that's closest to end of heap */ |
582 | 0 | last_fl = fl; |
583 | 0 | } |
584 | 0 | } |
585 | | |
586 | | /* If no free chunk was large enough, then allocate more space and |
587 | | * add it to the free list. If the heap ends with a free chunk, we |
588 | | * can extend that free chunk. Otherwise we'll have to make another |
589 | | * free chunk. If the heap must expand, we double its size. |
590 | | */ |
591 | 0 | if (found == false) { |
592 | 0 | size_t need_more; /* How much more space we need */ |
593 | 0 | size_t new_dblk_size; /* Final size of space allocated for heap data block */ |
594 | 0 | size_t old_dblk_size; /* Previous size of space allocated for heap data block */ |
595 | 0 | htri_t was_extended; /* Whether the local heap's data segment on disk was extended */ |
596 | | |
597 | | /* At least double the heap's size, making certain there's enough room |
598 | | * for the new object |
599 | | */ |
600 | 0 | need_more = MAX(need_size, heap->dblk_size); |
601 | | |
602 | | /* If there is no last free block or it's not at the end of the heap, |
603 | | * and the amount of space to allocate is not big enough to include at |
604 | | * least the new object and a free-list info, trim down the amount of |
605 | | * space requested to just the amount of space needed. (Generally |
606 | | * speaking, this only occurs when the heap is small -QAK) |
607 | | */ |
608 | 0 | if (!(last_fl && last_fl->offset + last_fl->size == heap->dblk_size) && |
609 | 0 | (need_more < (need_size + H5HL_SIZEOF_FREE(f)))) |
610 | 0 | need_more = need_size; |
611 | |
|
612 | 0 | new_dblk_size = heap->dblk_size + need_more; |
613 | 0 | assert(heap->dblk_size < new_dblk_size); |
614 | 0 | old_dblk_size = heap->dblk_size; |
615 | 0 | H5_CHECK_OVERFLOW(heap->dblk_size, size_t, hsize_t); |
616 | 0 | H5_CHECK_OVERFLOW(new_dblk_size, size_t, hsize_t); |
617 | | |
618 | | /* Extend current heap if possible */ |
619 | 0 | was_extended = H5MF_try_extend(f, H5FD_MEM_LHEAP, heap->dblk_addr, (hsize_t)(heap->dblk_size), |
620 | 0 | (hsize_t)need_more); |
621 | 0 | if (FAIL == was_extended) |
622 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "error trying to extend heap"); |
623 | | |
624 | | /* Check if we extended the heap data block in file */ |
625 | 0 | if (was_extended == true) { |
626 | | /* Check for prefix & data block contiguous */ |
627 | 0 | if (heap->single_cache_obj) { |
628 | | /* Resize prefix+data block */ |
629 | 0 | if (FAIL == H5AC_resize_entry(heap->prfx, (size_t)(heap->prfx_size + new_dblk_size))) |
630 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize heap prefix in cache"); |
631 | 0 | } |
632 | 0 | else { |
633 | | /* Resize 'standalone' data block */ |
634 | 0 | if (FAIL == H5AC_resize_entry(heap->dblk, (size_t)new_dblk_size)) |
635 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "unable to resize heap data block in cache"); |
636 | 0 | } |
637 | | |
638 | | /* Note new size */ |
639 | 0 | heap->dblk_size = new_dblk_size; |
640 | 0 | } |
641 | 0 | else { /* ...if we can't, allocate a new chunk & release the old */ |
642 | | /* Reallocate data block in file */ |
643 | 0 | if (FAIL == H5HL__dblk_realloc(f, heap, new_dblk_size)) |
644 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, "reallocating data block failed"); |
645 | 0 | } |
646 | | |
647 | | /* If the last free list in the heap is at the end of the heap, extend it */ |
648 | 0 | if (last_fl && last_fl->offset + last_fl->size == old_dblk_size) { |
649 | | /* |
650 | | * Increase the size of the last free block. |
651 | | */ |
652 | 0 | offset = last_fl->offset; |
653 | 0 | last_fl->offset += need_size; |
654 | 0 | last_fl->size += need_more - need_size; |
655 | 0 | assert(last_fl->offset == H5HL_ALIGN(last_fl->offset)); |
656 | 0 | assert(last_fl->size == H5HL_ALIGN(last_fl->size)); |
657 | |
|
658 | 0 | if (last_fl->size < H5HL_SIZEOF_FREE(f)) |
659 | 0 | last_fl = H5HL__remove_free(heap, last_fl); |
660 | 0 | } |
661 | 0 | else { |
662 | | /* Create a new free list element large enough that we can |
663 | | * take some space out of it right away. |
664 | | */ |
665 | 0 | offset = old_dblk_size; |
666 | 0 | if (need_more - need_size >= H5HL_SIZEOF_FREE(f)) { |
667 | 0 | if (NULL == (fl = H5FL_MALLOC(H5HL_free_t))) |
668 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
669 | 0 | fl->offset = old_dblk_size + need_size; |
670 | 0 | fl->size = need_more - need_size; |
671 | 0 | assert(fl->offset == H5HL_ALIGN(fl->offset)); |
672 | 0 | assert(fl->size == H5HL_ALIGN(fl->size)); |
673 | 0 | fl->prev = NULL; |
674 | 0 | fl->next = heap->freelist; |
675 | 0 | if (heap->freelist) |
676 | 0 | heap->freelist->prev = fl; |
677 | 0 | heap->freelist = fl; |
678 | 0 | } |
679 | 0 | } |
680 | | |
681 | 0 | if (NULL == (heap->dblk_image = H5FL_BLK_REALLOC(lheap_chunk, heap->dblk_image, heap->dblk_size))) |
682 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
683 | | |
684 | | /* Clear new section so junk doesn't appear in the file */ |
685 | | /* (Avoid clearing section which will be overwritten with newly inserted data) */ |
686 | 0 | memset(heap->dblk_image + offset + buf_size, 0, (new_dblk_size - (offset + buf_size))); |
687 | 0 | } |
688 | | |
689 | | /* Copy the data into the heap */ |
690 | 0 | H5MM_memcpy(heap->dblk_image + offset, buf, buf_size); |
691 | |
|
692 | 0 | *offset_out = offset; |
693 | |
|
694 | 0 | done: |
695 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
696 | 0 | } /* H5HL_insert() */ |
697 | | |
698 | | /*------------------------------------------------------------------------- |
699 | | * Function: H5HL_remove |
700 | | * |
701 | | * Purpose: Removes an object or part of an object from the heap at |
702 | | * address ADDR of file F. The object (or part) to remove |
703 | | * begins at byte OFFSET from the beginning of the heap and |
704 | | * continues for SIZE bytes. |
705 | | * |
706 | | * Once part of an object is removed, one must not attempt |
707 | | * to access that part. Removing the beginning of an object |
708 | | * results in the object OFFSET increasing by the amount |
709 | | * truncated. Removing the end of an object results in |
710 | | * object truncation. Removing the middle of an object results |
711 | | * in two separate objects, one at the original offset and |
712 | | * one at the first offset past the removed portion. |
713 | | * |
714 | | * Return: SUCCEED/FAIL |
715 | | * |
716 | | *------------------------------------------------------------------------- |
717 | | */ |
718 | | herr_t |
719 | | H5HL_remove(H5F_t *f, H5HL_t *heap, size_t offset, size_t size) |
720 | 0 | { |
721 | 0 | H5HL_free_t *fl = NULL; |
722 | 0 | herr_t ret_value = SUCCEED; |
723 | |
|
724 | 0 | FUNC_ENTER_NOAPI(FAIL) |
725 | | |
726 | | /* Check arguments */ |
727 | 0 | assert(f); |
728 | 0 | assert(heap); |
729 | 0 | assert(size > 0); |
730 | 0 | assert(offset == H5HL_ALIGN(offset)); |
731 | |
|
732 | 0 | size = H5HL_ALIGN(size); |
733 | |
|
734 | 0 | assert(offset < heap->dblk_size); |
735 | 0 | assert(offset + size <= heap->dblk_size); |
736 | | |
737 | | /* Mark heap as dirty in cache |
738 | | * |
739 | | * (A bit early in the process, but it's difficult to determine in the |
740 | | * code below where to mark the heap as dirty, especially in error cases, |
741 | | * so we just accept that an extra flush of the heap info could occur |
742 | | * if an error occurs -QAK) |
743 | | */ |
744 | 0 | if (FAIL == H5HL__dirty(heap)) |
745 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTMARKDIRTY, FAIL, "unable to mark heap as dirty"); |
746 | | |
747 | | /* Check if this chunk can be prepended or appended to an already |
748 | | * free chunk. It might also fall between two chunks in such a way |
749 | | * that all three chunks can be combined into one. |
750 | | */ |
751 | 0 | fl = heap->freelist; |
752 | 0 | while (fl) { |
753 | 0 | H5HL_free_t *fl2 = NULL; |
754 | |
|
755 | 0 | if ((offset + size) == fl->offset) { |
756 | 0 | fl->offset = offset; |
757 | 0 | fl->size += size; |
758 | 0 | assert(fl->offset == H5HL_ALIGN(fl->offset)); |
759 | 0 | assert(fl->size == H5HL_ALIGN(fl->size)); |
760 | 0 | fl2 = fl->next; |
761 | 0 | while (fl2) { |
762 | 0 | if ((fl2->offset + fl2->size) == fl->offset) { |
763 | 0 | fl->offset = fl2->offset; |
764 | 0 | fl->size += fl2->size; |
765 | 0 | assert(fl->offset == H5HL_ALIGN(fl->offset)); |
766 | 0 | assert(fl->size == H5HL_ALIGN(fl->size)); |
767 | 0 | fl2 = H5HL__remove_free(heap, fl2); |
768 | 0 | if (((fl->offset + fl->size) == heap->dblk_size) && ((2 * fl->size) > heap->dblk_size)) { |
769 | 0 | if (FAIL == H5HL__minimize_heap_space(f, heap)) |
770 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "heap size minimization failed"); |
771 | 0 | } |
772 | 0 | HGOTO_DONE(SUCCEED); |
773 | 0 | } |
774 | 0 | fl2 = fl2->next; |
775 | 0 | } |
776 | 0 | if (((fl->offset + fl->size) == heap->dblk_size) && ((2 * fl->size) > heap->dblk_size)) { |
777 | 0 | if (FAIL == H5HL__minimize_heap_space(f, heap)) |
778 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "heap size minimization failed"); |
779 | 0 | } |
780 | 0 | HGOTO_DONE(SUCCEED); |
781 | 0 | } |
782 | 0 | else if (fl->offset + fl->size == offset) { |
783 | 0 | fl->size += size; |
784 | 0 | fl2 = fl->next; |
785 | 0 | assert(fl->size == H5HL_ALIGN(fl->size)); |
786 | 0 | while (fl2) { |
787 | 0 | if (fl->offset + fl->size == fl2->offset) { |
788 | 0 | fl->size += fl2->size; |
789 | 0 | assert(fl->size == H5HL_ALIGN(fl->size)); |
790 | 0 | fl2 = H5HL__remove_free(heap, fl2); |
791 | 0 | if (((fl->offset + fl->size) == heap->dblk_size) && ((2 * fl->size) > heap->dblk_size)) { |
792 | 0 | if (FAIL == H5HL__minimize_heap_space(f, heap)) |
793 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "heap size minimization failed"); |
794 | 0 | } |
795 | 0 | HGOTO_DONE(SUCCEED); |
796 | 0 | } |
797 | 0 | fl2 = fl2->next; |
798 | 0 | } |
799 | 0 | if (((fl->offset + fl->size) == heap->dblk_size) && ((2 * fl->size) > heap->dblk_size)) { |
800 | 0 | if (FAIL == H5HL__minimize_heap_space(f, heap)) |
801 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "heap size minimization failed"); |
802 | 0 | } |
803 | 0 | HGOTO_DONE(SUCCEED); |
804 | 0 | } |
805 | 0 | fl = fl->next; |
806 | 0 | } |
807 | | |
808 | | /* |
809 | | * The amount which is being removed must be large enough to |
810 | | * hold the free list data. If not, the freed chunk is forever |
811 | | * lost. |
812 | | */ |
813 | 0 | if (size < H5HL_SIZEOF_FREE(f)) |
814 | 0 | HGOTO_DONE(SUCCEED); |
815 | | |
816 | | /* Add an entry to the free list */ |
817 | 0 | if (NULL == (fl = H5FL_MALLOC(H5HL_free_t))) |
818 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
819 | 0 | fl->offset = offset; |
820 | 0 | fl->size = size; |
821 | 0 | assert(fl->offset == H5HL_ALIGN(fl->offset)); |
822 | 0 | assert(fl->size == H5HL_ALIGN(fl->size)); |
823 | 0 | fl->prev = NULL; |
824 | 0 | fl->next = heap->freelist; |
825 | 0 | if (heap->freelist) |
826 | 0 | heap->freelist->prev = fl; |
827 | 0 | heap->freelist = fl; |
828 | |
|
829 | 0 | if (((fl->offset + fl->size) == heap->dblk_size) && ((2 * fl->size) > heap->dblk_size)) |
830 | 0 | if (FAIL == H5HL__minimize_heap_space(f, heap)) |
831 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "heap size minimization failed"); |
832 | | |
833 | 0 | done: |
834 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
835 | 0 | } /* end H5HL_remove() */ |
836 | | |
837 | | /*------------------------------------------------------------------------- |
838 | | * Function: H5HL_delete |
839 | | * |
840 | | * Purpose: Deletes a local heap from disk, freeing disk space used. |
841 | | * |
842 | | * Return: SUCCEED/FAIL |
843 | | * |
844 | | *------------------------------------------------------------------------- |
845 | | */ |
846 | | herr_t |
847 | | H5HL_delete(H5F_t *f, haddr_t addr) |
848 | 0 | { |
849 | 0 | H5HL_t *heap = NULL; /* Local heap to delete */ |
850 | 0 | H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */ |
851 | 0 | H5HL_prfx_t *prfx = NULL; /* Local heap prefix */ |
852 | 0 | H5HL_dblk_t *dblk = NULL; /* Local heap data block */ |
853 | 0 | unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting heap */ |
854 | 0 | herr_t ret_value = SUCCEED; |
855 | |
|
856 | 0 | FUNC_ENTER_NOAPI(FAIL) |
857 | | |
858 | | /* Check arguments */ |
859 | 0 | assert(f); |
860 | 0 | assert(H5_addr_defined(addr)); |
861 | | |
862 | | /* Construct the user data for protect callback */ |
863 | 0 | prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); |
864 | 0 | prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); |
865 | 0 | prfx_udata.prfx_addr = addr; |
866 | 0 | prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); |
867 | | |
868 | | /* Protect the local heap prefix */ |
869 | 0 | if (NULL == |
870 | 0 | (prfx = (H5HL_prfx_t *)H5AC_protect(f, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__NO_FLAGS_SET))) |
871 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load heap prefix"); |
872 | | |
873 | | /* Get the pointer to the heap */ |
874 | 0 | heap = prfx->heap; |
875 | | |
876 | | /* Check if heap has separate data block */ |
877 | 0 | if (!heap->single_cache_obj) |
878 | | /* Protect the local heap data block */ |
879 | 0 | if (NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, H5AC_LHEAP_DBLK, heap->dblk_addr, heap, |
880 | 0 | H5AC__NO_FLAGS_SET))) |
881 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load heap data block"); |
882 | | |
883 | | /* Set the flags for releasing the prefix and data block */ |
884 | 0 | cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; |
885 | |
|
886 | 0 | done: |
887 | | /* Release the data block from the cache, now deleted */ |
888 | 0 | if (dblk && heap && H5AC_unprotect(f, H5AC_LHEAP_DBLK, heap->dblk_addr, dblk, cache_flags) < 0) |
889 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release local heap data block"); |
890 | | |
891 | | /* Release the prefix from the cache, now deleted */ |
892 | 0 | if (prfx && heap && H5AC_unprotect(f, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, cache_flags) < 0) |
893 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release local heap prefix"); |
894 | |
|
895 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
896 | 0 | } /* end H5HL_delete() */ |
897 | | |
898 | | /*------------------------------------------------------------------------- |
899 | | * Function: H5HL_heap_get_size |
900 | | * |
901 | | * Purpose: Retrieves the current size of a heap's block |
902 | | * |
903 | | * Return: SUCCEED/FAIL |
904 | | * |
905 | | *------------------------------------------------------------------------- |
906 | | */ |
907 | | size_t |
908 | | H5HL_heap_get_size(const H5HL_t *heap) |
909 | 1.28k | { |
910 | 1.28k | FUNC_ENTER_NOAPI_NOINIT_NOERR |
911 | | |
912 | | /* Check arguments */ |
913 | 1.28k | assert(heap); |
914 | | |
915 | 1.28k | FUNC_LEAVE_NOAPI(heap->dblk_size) |
916 | 1.28k | } /* end H5HL_heap_get_size() */ |
917 | | |
918 | | /*------------------------------------------------------------------------- |
919 | | * Function: H5HL_get_size |
920 | | * |
921 | | * Purpose: Retrieves the current size of a heap |
922 | | * |
923 | | * Return: SUCCEED/FAIL |
924 | | * |
925 | | *------------------------------------------------------------------------- |
926 | | */ |
927 | | herr_t |
928 | | H5HL_get_size(H5F_t *f, haddr_t addr, size_t *size) |
929 | 0 | { |
930 | 0 | H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */ |
931 | 0 | H5HL_prfx_t *prfx = NULL; /* Local heap prefix */ |
932 | 0 | H5HL_t *heap = NULL; /* Heap data structure */ |
933 | 0 | herr_t ret_value = SUCCEED; |
934 | |
|
935 | 0 | FUNC_ENTER_NOAPI(FAIL) |
936 | | |
937 | | /* Check arguments */ |
938 | 0 | assert(f); |
939 | 0 | assert(H5_addr_defined(addr)); |
940 | 0 | assert(size); |
941 | | |
942 | | /* Construct the user data for protect callback */ |
943 | 0 | prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); |
944 | 0 | prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); |
945 | 0 | prfx_udata.prfx_addr = addr; |
946 | 0 | prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); |
947 | | |
948 | | /* Protect the local heap prefix */ |
949 | 0 | if (NULL == |
950 | 0 | (prfx = (H5HL_prfx_t *)H5AC_protect(f, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__READ_ONLY_FLAG))) |
951 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load heap prefix"); |
952 | | |
953 | | /* Get the pointer to the heap */ |
954 | 0 | heap = prfx->heap; |
955 | | |
956 | | /* Set the size to return */ |
957 | 0 | *size = heap->dblk_size; |
958 | |
|
959 | 0 | done: |
960 | 0 | if (prfx && FAIL == H5AC_unprotect(f, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, H5AC__NO_FLAGS_SET)) |
961 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release local heap prefix"); |
962 | |
|
963 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
964 | 0 | } /* end H5HL_get_size() */ |
965 | | |
966 | | /*------------------------------------------------------------------------- |
967 | | * Function: H5HL_heapsize |
968 | | * |
969 | | * Purpose: Compute the size in bytes of the specified instance of |
970 | | * H5HL_t via H5HL_size() |
971 | | * |
972 | | * Return: SUCCEED/FAIL |
973 | | * |
974 | | *------------------------------------------------------------------------- |
975 | | */ |
976 | | herr_t |
977 | | H5HL_heapsize(H5F_t *f, haddr_t addr, hsize_t *heap_size) |
978 | 0 | { |
979 | 0 | H5HL_cache_prfx_ud_t prfx_udata; /* User data for protecting local heap prefix */ |
980 | 0 | H5HL_prfx_t *prfx = NULL; /* Local heap prefix */ |
981 | 0 | H5HL_t *heap = NULL; /* Heap data structure */ |
982 | 0 | herr_t ret_value = SUCCEED; |
983 | |
|
984 | 0 | FUNC_ENTER_NOAPI(FAIL) |
985 | | |
986 | | /* Check arguments */ |
987 | 0 | assert(f); |
988 | 0 | assert(H5_addr_defined(addr)); |
989 | 0 | assert(heap_size); |
990 | | |
991 | | /* Construct the user data for protect callback */ |
992 | 0 | prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); |
993 | 0 | prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); |
994 | 0 | prfx_udata.prfx_addr = addr; |
995 | 0 | prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); |
996 | | |
997 | | /* Protect the local heap prefix */ |
998 | 0 | if (NULL == |
999 | 0 | (prfx = (H5HL_prfx_t *)H5AC_protect(f, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__READ_ONLY_FLAG))) |
1000 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to load heap prefix"); |
1001 | | |
1002 | | /* Get the pointer to the heap */ |
1003 | 0 | heap = prfx->heap; |
1004 | | |
1005 | | /* Accumulate the size of the local heap */ |
1006 | 0 | *heap_size += (hsize_t)(heap->prfx_size + heap->dblk_size); |
1007 | |
|
1008 | 0 | done: |
1009 | 0 | if (prfx && FAIL == H5AC_unprotect(f, H5AC_LHEAP_PRFX, heap->prfx_addr, prfx, H5AC__NO_FLAGS_SET)) |
1010 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release local heap prefix"); |
1011 | |
|
1012 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1013 | 0 | } /* end H5HL_heapsize() */ |