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