/src/hdf5/src/H5B2cache.c
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: H5B2cache.c |
16 | | * |
17 | | * Purpose: Implement v2 B-tree metadata cache methods |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | /****************/ |
23 | | /* Module Setup */ |
24 | | /****************/ |
25 | | |
26 | | #include "H5B2module.h" /* This source code file is part of the H5B2 module */ |
27 | | |
28 | | /***********/ |
29 | | /* Headers */ |
30 | | /***********/ |
31 | | #include "H5private.h" /* Generic Functions */ |
32 | | #include "H5ACprivate.h" /* Metadata Cache */ |
33 | | #include "H5B2pkg.h" /* B-Trees (Version 2) */ |
34 | | #include "H5Eprivate.h" /* Error Handling */ |
35 | | #include "H5Fprivate.h" /* Files */ |
36 | | #include "H5FLprivate.h" /* Free Lists */ |
37 | | #include "H5MMprivate.h" /* Memory Management */ |
38 | | |
39 | | /****************/ |
40 | | /* Local Macros */ |
41 | | /****************/ |
42 | | |
43 | | /* B-tree format version #'s */ |
44 | 0 | #define H5B2_HDR_VERSION 0 /* Header */ |
45 | 0 | #define H5B2_INT_VERSION 0 /* Internal node */ |
46 | 0 | #define H5B2_LEAF_VERSION 0 /* Leaf node */ |
47 | | |
48 | | /******************/ |
49 | | /* Local Typedefs */ |
50 | | /******************/ |
51 | | |
52 | | /********************/ |
53 | | /* Package Typedefs */ |
54 | | /********************/ |
55 | | |
56 | | /********************/ |
57 | | /* Local Prototypes */ |
58 | | /********************/ |
59 | | |
60 | | /* Metadata cache callbacks */ |
61 | | static herr_t H5B2__cache_hdr_get_initial_load_size(void *udata, size_t *image_len); |
62 | | static htri_t H5B2__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata); |
63 | | static void *H5B2__cache_hdr_deserialize(const void *image, size_t len, void *udata, bool *dirty); |
64 | | static herr_t H5B2__cache_hdr_image_len(const void *thing, size_t *image_len); |
65 | | static herr_t H5B2__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, void *thing); |
66 | | static herr_t H5B2__cache_hdr_notify(H5AC_notify_action_t action, void *thing); |
67 | | static herr_t H5B2__cache_hdr_free_icr(void *thing); |
68 | | |
69 | | static herr_t H5B2__cache_int_get_initial_load_size(void *udata, size_t *image_len); |
70 | | static htri_t H5B2__cache_int_verify_chksum(const void *image_ptr, size_t len, void *udata); |
71 | | static void *H5B2__cache_int_deserialize(const void *image, size_t len, void *udata, bool *dirty); |
72 | | static herr_t H5B2__cache_int_image_len(const void *thing, size_t *image_len); |
73 | | static herr_t H5B2__cache_int_serialize(const H5F_t *f, void *image, size_t len, void *thing); |
74 | | static herr_t H5B2__cache_int_notify(H5AC_notify_action_t action, void *thing); |
75 | | static herr_t H5B2__cache_int_free_icr(void *thing); |
76 | | |
77 | | static herr_t H5B2__cache_leaf_get_initial_load_size(void *udata, size_t *image_len); |
78 | | static htri_t H5B2__cache_leaf_verify_chksum(const void *image_ptr, size_t len, void *udata); |
79 | | static void *H5B2__cache_leaf_deserialize(const void *image, size_t len, void *udata, bool *dirty); |
80 | | static herr_t H5B2__cache_leaf_image_len(const void *thing, size_t *image_len); |
81 | | static herr_t H5B2__cache_leaf_serialize(const H5F_t *f, void *image, size_t len, void *thing); |
82 | | static herr_t H5B2__cache_leaf_notify(H5AC_notify_action_t action, void *thing); |
83 | | static herr_t H5B2__cache_leaf_free_icr(void *thing); |
84 | | |
85 | | /*********************/ |
86 | | /* Package Variables */ |
87 | | /*********************/ |
88 | | |
89 | | /* H5B2 inherits cache-like properties from H5AC */ |
90 | | const H5AC_class_t H5AC_BT2_HDR[1] = {{ |
91 | | H5AC_BT2_HDR_ID, /* Metadata client ID */ |
92 | | "v2 B-tree header", /* Metadata client name (for debugging) */ |
93 | | H5FD_MEM_BTREE, /* File space memory type for client */ |
94 | | H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ |
95 | | H5B2__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */ |
96 | | NULL, /* 'get_final_load_size' callback */ |
97 | | H5B2__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ |
98 | | H5B2__cache_hdr_deserialize, /* 'deserialize' callback */ |
99 | | H5B2__cache_hdr_image_len, /* 'image_len' callback */ |
100 | | NULL, /* 'pre_serialize' callback */ |
101 | | H5B2__cache_hdr_serialize, /* 'serialize' callback */ |
102 | | H5B2__cache_hdr_notify, /* 'notify' callback */ |
103 | | H5B2__cache_hdr_free_icr, /* 'free_icr' callback */ |
104 | | NULL, /* 'fsf_size' callback */ |
105 | | }}; |
106 | | |
107 | | /* H5B2 inherits cache-like properties from H5AC */ |
108 | | const H5AC_class_t H5AC_BT2_INT[1] = {{ |
109 | | H5AC_BT2_INT_ID, /* Metadata client ID */ |
110 | | "v2 B-tree internal node", /* Metadata client name (for debugging) */ |
111 | | H5FD_MEM_BTREE, /* File space memory type for client */ |
112 | | H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ |
113 | | H5B2__cache_int_get_initial_load_size, /* 'get_initial_load_size' callback */ |
114 | | NULL, /* 'get_final_load_size' callback */ |
115 | | H5B2__cache_int_verify_chksum, /* 'verify_chksum' callback */ |
116 | | H5B2__cache_int_deserialize, /* 'deserialize' callback */ |
117 | | H5B2__cache_int_image_len, /* 'image_len' callback */ |
118 | | NULL, /* 'pre_serialize' callback */ |
119 | | H5B2__cache_int_serialize, /* 'serialize' callback */ |
120 | | H5B2__cache_int_notify, /* 'notify' callback */ |
121 | | H5B2__cache_int_free_icr, /* 'free_icr' callback */ |
122 | | NULL, /* 'fsf_size' callback */ |
123 | | }}; |
124 | | |
125 | | /* H5B2 inherits cache-like properties from H5AC */ |
126 | | const H5AC_class_t H5AC_BT2_LEAF[1] = {{ |
127 | | H5AC_BT2_LEAF_ID, /* Metadata client ID */ |
128 | | "v2 B-tree leaf node", /* Metadata client name (for debugging) */ |
129 | | H5FD_MEM_BTREE, /* File space memory type for client */ |
130 | | H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ |
131 | | H5B2__cache_leaf_get_initial_load_size, /* 'get_initial_load_size' callback */ |
132 | | NULL, /* 'get_final_load_size' callback */ |
133 | | H5B2__cache_leaf_verify_chksum, /* 'verify_chksum' callback */ |
134 | | H5B2__cache_leaf_deserialize, /* 'deserialize' callback */ |
135 | | H5B2__cache_leaf_image_len, /* 'image_len' callback */ |
136 | | NULL, /* 'pre_serialize' callback */ |
137 | | H5B2__cache_leaf_serialize, /* 'serialize' callback */ |
138 | | H5B2__cache_leaf_notify, /* 'notify' callback */ |
139 | | H5B2__cache_leaf_free_icr, /* 'free_icr' callback */ |
140 | | NULL, /* 'fsf_size' callback */ |
141 | | }}; |
142 | | |
143 | | /*****************************/ |
144 | | /* Library Private Variables */ |
145 | | /*****************************/ |
146 | | |
147 | | /*******************/ |
148 | | /* Local Variables */ |
149 | | /*******************/ |
150 | | |
151 | | /*------------------------------------------------------------------------- |
152 | | * Function: H5B2__cache_hdr_get_initial_load_size |
153 | | * |
154 | | * Purpose: Compute the size of the data structure on disk. |
155 | | * |
156 | | * Return: Non-negative on success/Negative on failure |
157 | | * |
158 | | *------------------------------------------------------------------------- |
159 | | */ |
160 | | static herr_t |
161 | | H5B2__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len) |
162 | 0 | { |
163 | 0 | H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata; /* User data for callback */ |
164 | |
|
165 | 0 | FUNC_ENTER_PACKAGE_NOERR |
166 | | |
167 | | /* Check arguments */ |
168 | 0 | assert(udata); |
169 | 0 | assert(udata->f); |
170 | 0 | assert(image_len); |
171 | | |
172 | | /* Set the image length size */ |
173 | 0 | *image_len = H5B2_HEADER_SIZE_FILE(udata->f); |
174 | |
|
175 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
176 | 0 | } /* end H5B2__cache_hdr_get_initial_load_size() */ |
177 | | |
178 | | /*------------------------------------------------------------------------- |
179 | | * Function: H5B2__cache_hdr_verify_chksum |
180 | | * |
181 | | * Purpose: Verify the computed checksum of the data structure is the |
182 | | * same as the stored chksum. |
183 | | * |
184 | | * Return: Success: true/false |
185 | | * Failure: Negative |
186 | | * |
187 | | *------------------------------------------------------------------------- |
188 | | */ |
189 | | static htri_t |
190 | | H5B2__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) |
191 | 0 | { |
192 | 0 | const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ |
193 | 0 | uint32_t stored_chksum; /* Stored metadata checksum value */ |
194 | 0 | uint32_t computed_chksum; /* Computed metadata checksum value */ |
195 | 0 | htri_t ret_value = true; /* Return value */ |
196 | |
|
197 | 0 | FUNC_ENTER_PACKAGE |
198 | | |
199 | | /* Check arguments */ |
200 | 0 | assert(image); |
201 | | |
202 | | /* Get stored and computed checksums */ |
203 | 0 | if (H5F_get_checksums(image, len, &stored_chksum, &computed_chksum) < 0) |
204 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't get checksums"); |
205 | | |
206 | 0 | if (stored_chksum != computed_chksum) |
207 | 0 | ret_value = false; |
208 | |
|
209 | 0 | done: |
210 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
211 | 0 | } /* end H5B2__cache_hdr_verify_chksum() */ |
212 | | |
213 | | /*------------------------------------------------------------------------- |
214 | | * Function: H5B2__cache_hdr_deserialize |
215 | | * |
216 | | * Purpose: Loads a B-tree header from the disk. |
217 | | * |
218 | | * Return: Success: Pointer to a new B-tree. |
219 | | * Failure: NULL |
220 | | * |
221 | | *------------------------------------------------------------------------- |
222 | | */ |
223 | | static void * |
224 | | H5B2__cache_hdr_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata, |
225 | | bool H5_ATTR_UNUSED *dirty) |
226 | 0 | { |
227 | 0 | H5B2_hdr_t *hdr = NULL; /* B-tree header */ |
228 | 0 | H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata; |
229 | 0 | H5B2_create_t cparam; /* B-tree creation parameters */ |
230 | 0 | H5B2_subid_t id; /* ID of B-tree class, as found in file */ |
231 | 0 | uint16_t depth; /* Depth of B-tree */ |
232 | 0 | uint32_t stored_chksum; /* Stored metadata checksum value */ |
233 | 0 | const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ |
234 | 0 | H5B2_hdr_t *ret_value = NULL; /* Return value */ |
235 | |
|
236 | 0 | FUNC_ENTER_PACKAGE |
237 | | |
238 | | /* Check arguments */ |
239 | 0 | assert(image); |
240 | 0 | assert(udata); |
241 | | |
242 | | /* Allocate new B-tree header and reset cache info */ |
243 | 0 | if (NULL == (hdr = H5B2__hdr_alloc(udata->f))) |
244 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "allocation failed for B-tree header"); |
245 | | |
246 | | /* Magic number */ |
247 | 0 | if (memcmp(image, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC) != 0) |
248 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree header signature"); |
249 | 0 | image += H5_SIZEOF_MAGIC; |
250 | | |
251 | | /* Version */ |
252 | 0 | if (*image++ != H5B2_HDR_VERSION) |
253 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADRANGE, NULL, "wrong B-tree header version"); |
254 | | |
255 | | /* B-tree class */ |
256 | 0 | id = (H5B2_subid_t)*image++; |
257 | 0 | if (id >= H5B2_NUM_BTREE_ID) |
258 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type"); |
259 | | |
260 | | /* Node size (in bytes) */ |
261 | 0 | UINT32DECODE(image, cparam.node_size); |
262 | | |
263 | | /* Raw key size (in bytes) */ |
264 | 0 | UINT16DECODE(image, cparam.rrec_size); |
265 | | |
266 | | /* Depth of tree */ |
267 | 0 | UINT16DECODE(image, depth); |
268 | | |
269 | | /* Split & merge %s */ |
270 | 0 | cparam.split_percent = *image++; |
271 | 0 | cparam.merge_percent = *image++; |
272 | | |
273 | | /* Root node pointer */ |
274 | 0 | H5F_addr_decode(udata->f, (const uint8_t **)&image, &(hdr->root.addr)); |
275 | 0 | UINT16DECODE(image, hdr->root.node_nrec); |
276 | 0 | H5F_DECODE_LENGTH(udata->f, image, hdr->root.all_nrec); |
277 | | |
278 | | /* checksum verification already done in verify_chksum cb */ |
279 | | |
280 | | /* Metadata checksum */ |
281 | 0 | UINT32DECODE(image, stored_chksum); |
282 | | |
283 | | /* Sanity check */ |
284 | 0 | assert((size_t)(image - (const uint8_t *)_image) == hdr->hdr_size); |
285 | | |
286 | | /* Initialize B-tree header info */ |
287 | 0 | cparam.cls = H5B2_client_class_g[id]; |
288 | 0 | if (H5B2__hdr_init(hdr, &cparam, udata->ctx_udata, depth) < 0) |
289 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, NULL, "can't initialize B-tree header info"); |
290 | | |
291 | | /* Set the B-tree header's address */ |
292 | 0 | hdr->addr = udata->addr; |
293 | | |
294 | | /* Sanity check */ |
295 | 0 | assert((size_t)(image - (const uint8_t *)_image) <= len); |
296 | | |
297 | | /* Set return value */ |
298 | 0 | ret_value = hdr; |
299 | |
|
300 | 0 | done: |
301 | 0 | if (!ret_value && hdr) |
302 | 0 | if (H5B2__hdr_free(hdr) < 0) |
303 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, NULL, "can't release v2 B-tree header"); |
304 | |
|
305 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
306 | 0 | } /* end H5B2__cache_hdr_deserialize() */ |
307 | | |
308 | | /*------------------------------------------------------------------------- |
309 | | * Function: H5B2__cache_hdr_image_len |
310 | | * |
311 | | * Purpose: Compute the size of the data structure on disk. |
312 | | * |
313 | | * Return: Non-negative on success/Negative on failure |
314 | | * |
315 | | *------------------------------------------------------------------------- |
316 | | */ |
317 | | static herr_t |
318 | | H5B2__cache_hdr_image_len(const void *_thing, size_t *image_len) |
319 | 0 | { |
320 | 0 | const H5B2_hdr_t *hdr = (const H5B2_hdr_t *)_thing; /* Pointer to the B-tree header */ |
321 | |
|
322 | 0 | FUNC_ENTER_PACKAGE_NOERR |
323 | | |
324 | | /* Check arguments */ |
325 | 0 | assert(hdr); |
326 | 0 | assert(image_len); |
327 | | |
328 | | /* Set the image length size */ |
329 | 0 | *image_len = hdr->hdr_size; |
330 | |
|
331 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
332 | 0 | } /* end H5B2__cache_hdr_image_len() */ |
333 | | |
334 | | /*------------------------------------------------------------------------- |
335 | | * Function: H5B2__cache_hdr_serialize |
336 | | * |
337 | | * Purpose: Flushes a dirty B-tree header to disk. |
338 | | * |
339 | | * Return: Non-negative on success/Negative on failure |
340 | | * |
341 | | *------------------------------------------------------------------------- |
342 | | */ |
343 | | static herr_t |
344 | | H5B2__cache_hdr_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, void *_thing) |
345 | 0 | { |
346 | 0 | H5B2_hdr_t *hdr = (H5B2_hdr_t *)_thing; /* Pointer to the B-tree header */ |
347 | 0 | uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ |
348 | 0 | uint32_t metadata_chksum; /* Computed metadata checksum value */ |
349 | |
|
350 | 0 | FUNC_ENTER_PACKAGE_NOERR |
351 | | |
352 | | /* check arguments */ |
353 | 0 | assert(f); |
354 | 0 | assert(image); |
355 | 0 | assert(hdr); |
356 | | |
357 | | /* Magic number */ |
358 | 0 | H5MM_memcpy(image, H5B2_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC); |
359 | 0 | image += H5_SIZEOF_MAGIC; |
360 | | |
361 | | /* Version # */ |
362 | 0 | *image++ = H5B2_HDR_VERSION; |
363 | | |
364 | | /* B-tree type */ |
365 | 0 | assert(hdr->cls->id <= 255); |
366 | 0 | *image++ = (uint8_t)hdr->cls->id; |
367 | | |
368 | | /* Node size (in bytes) */ |
369 | 0 | UINT32ENCODE(image, hdr->node_size); |
370 | | |
371 | | /* Raw key size (in bytes) */ |
372 | 0 | UINT16ENCODE(image, hdr->rrec_size); |
373 | | |
374 | | /* Depth of tree */ |
375 | 0 | UINT16ENCODE(image, hdr->depth); |
376 | | |
377 | | /* Split & merge %s */ |
378 | 0 | H5_CHECK_OVERFLOW(hdr->split_percent, /* From: */ unsigned, /* To: */ uint8_t); |
379 | 0 | *image++ = (uint8_t)hdr->split_percent; |
380 | 0 | H5_CHECK_OVERFLOW(hdr->merge_percent, /* From: */ unsigned, /* To: */ uint8_t); |
381 | 0 | *image++ = (uint8_t)hdr->merge_percent; |
382 | | |
383 | | /* Root node pointer */ |
384 | 0 | H5F_addr_encode(f, &image, hdr->root.addr); |
385 | 0 | UINT16ENCODE(image, hdr->root.node_nrec); |
386 | 0 | H5F_ENCODE_LENGTH(f, image, hdr->root.all_nrec); |
387 | | |
388 | | /* Compute metadata checksum */ |
389 | 0 | metadata_chksum = H5_checksum_metadata(_image, (hdr->hdr_size - H5B2_SIZEOF_CHKSUM), 0); |
390 | | |
391 | | /* Metadata checksum */ |
392 | 0 | UINT32ENCODE(image, metadata_chksum); |
393 | | |
394 | | /* Sanity check */ |
395 | 0 | assert((size_t)(image - (uint8_t *)_image) == len); |
396 | |
|
397 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
398 | 0 | } /* H5B2__cache_hdr_serialize() */ |
399 | | |
400 | | /*------------------------------------------------------------------------- |
401 | | * Function: H5B2__cache_hdr_notify |
402 | | * |
403 | | * Purpose: Handle cache action notifications |
404 | | * |
405 | | * Return: Non-negative on success/Negative on failure |
406 | | * |
407 | | *------------------------------------------------------------------------- |
408 | | */ |
409 | | static herr_t |
410 | | H5B2__cache_hdr_notify(H5AC_notify_action_t action, void *_thing) |
411 | 0 | { |
412 | 0 | H5B2_hdr_t *hdr = (H5B2_hdr_t *)_thing; |
413 | 0 | herr_t ret_value = SUCCEED; |
414 | |
|
415 | 0 | FUNC_ENTER_PACKAGE |
416 | | |
417 | | /* |
418 | | * Check arguments. |
419 | | */ |
420 | 0 | assert(hdr); |
421 | | |
422 | | /* Check if the file was opened with SWMR-write access */ |
423 | 0 | if (hdr->swmr_write) { |
424 | 0 | switch (action) { |
425 | 0 | case H5AC_NOTIFY_ACTION_AFTER_INSERT: |
426 | 0 | case H5AC_NOTIFY_ACTION_AFTER_LOAD: |
427 | | /* do nothing */ |
428 | 0 | break; |
429 | | |
430 | 0 | case H5AC_NOTIFY_ACTION_AFTER_FLUSH: |
431 | | /* Increment the shadow epoch, forcing new modifications to |
432 | | * internal and leaf nodes to create new shadow copies */ |
433 | 0 | hdr->shadow_epoch++; |
434 | 0 | break; |
435 | | |
436 | 0 | case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED: |
437 | 0 | case H5AC_NOTIFY_ACTION_ENTRY_CLEANED: |
438 | 0 | case H5AC_NOTIFY_ACTION_CHILD_DIRTIED: |
439 | 0 | case H5AC_NOTIFY_ACTION_CHILD_CLEANED: |
440 | 0 | case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED: |
441 | 0 | case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED: |
442 | | /* do nothing */ |
443 | 0 | break; |
444 | | |
445 | 0 | case H5AC_NOTIFY_ACTION_BEFORE_EVICT: |
446 | | /* If hdr->parent != NULL, hdr->parent is used to destroy |
447 | | * the flush dependency before the header is evicted. |
448 | | */ |
449 | 0 | if (hdr->parent) { |
450 | | /* Sanity check */ |
451 | 0 | assert(hdr->top_proxy); |
452 | | |
453 | | /* Destroy flush dependency on object header proxy */ |
454 | 0 | if (H5AC_proxy_entry_remove_child((H5AC_proxy_entry_t *)hdr->parent, |
455 | 0 | (void *)hdr->top_proxy) < 0) |
456 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, |
457 | 0 | "unable to destroy flush dependency between v2 B-tree and proxy"); |
458 | 0 | hdr->parent = NULL; |
459 | 0 | } /* end if */ |
460 | | |
461 | | /* Detach from 'top' proxy for extensible array */ |
462 | 0 | if (hdr->top_proxy) { |
463 | 0 | if (H5AC_proxy_entry_remove_child(hdr->top_proxy, hdr) < 0) |
464 | 0 | HGOTO_ERROR( |
465 | 0 | H5E_BTREE, H5E_CANTUNDEPEND, FAIL, |
466 | 0 | "unable to destroy flush dependency between header and v2 B-tree 'top' proxy"); |
467 | | /* Don't reset hdr->top_proxy here, it's destroyed when the header is freed -QAK */ |
468 | 0 | } /* end if */ |
469 | 0 | break; |
470 | | |
471 | 0 | default: |
472 | 0 | #ifdef NDEBUG |
473 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache"); |
474 | | #else /* NDEBUG */ |
475 | | assert(0 && "Unknown action?!?"); |
476 | | #endif /* NDEBUG */ |
477 | 0 | } /* end switch */ |
478 | 0 | } /* end if */ |
479 | 0 | else |
480 | 0 | assert(NULL == hdr->parent); |
481 | | |
482 | 0 | done: |
483 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
484 | 0 | } /* end H5B2__cache_hdr_notify() */ |
485 | | |
486 | | /*------------------------------------------------------------------------- |
487 | | * Function: H5B2__cache_hdr_free_icr |
488 | | * |
489 | | * Purpose: Destroy/release an "in core representation" of a data |
490 | | * structure |
491 | | * |
492 | | * Return: Non-negative on success/Negative on failure |
493 | | * |
494 | | *------------------------------------------------------------------------- |
495 | | */ |
496 | | static herr_t |
497 | | H5B2__cache_hdr_free_icr(void *thing) |
498 | 0 | { |
499 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
500 | |
|
501 | 0 | FUNC_ENTER_PACKAGE |
502 | | |
503 | | /* Check arguments */ |
504 | 0 | assert(thing); |
505 | | |
506 | | /* Destroy v2 B-tree header */ |
507 | 0 | if (H5B2__hdr_free((H5B2_hdr_t *)thing) < 0) |
508 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free v2 B-tree header"); |
509 | | |
510 | 0 | done: |
511 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
512 | 0 | } /* H5B2__cache_hdr_free_icr() */ |
513 | | |
514 | | /*------------------------------------------------------------------------- |
515 | | * Function: H5B2__cache_int_get_initial_load_size |
516 | | * |
517 | | * Purpose: Compute the size of the data structure on disk. |
518 | | * |
519 | | * Return: Non-negative on success/Negative on failure |
520 | | * |
521 | | *------------------------------------------------------------------------- |
522 | | */ |
523 | | static herr_t |
524 | | H5B2__cache_int_get_initial_load_size(void *_udata, size_t *image_len) |
525 | 0 | { |
526 | 0 | H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* User data for callback */ |
527 | |
|
528 | 0 | FUNC_ENTER_PACKAGE_NOERR |
529 | | |
530 | | /* Check arguments */ |
531 | 0 | assert(udata); |
532 | 0 | assert(udata->hdr); |
533 | 0 | assert(image_len); |
534 | | |
535 | | /* Set the image length size */ |
536 | 0 | *image_len = udata->hdr->node_size; |
537 | |
|
538 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
539 | 0 | } /* end H5B2__cache_int_get_initial_load_size() */ |
540 | | |
541 | | /*------------------------------------------------------------------------- |
542 | | * Function: H5B2__cache_int_verify_chksum |
543 | | * |
544 | | * Purpose: Verify the computed checksum of the data structure is the |
545 | | * same as the stored chksum. |
546 | | * |
547 | | * Return: Success: true/false |
548 | | * Failure: Negative |
549 | | * |
550 | | *------------------------------------------------------------------------- |
551 | | */ |
552 | | static htri_t |
553 | | H5B2__cache_int_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata) |
554 | 0 | { |
555 | 0 | const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ |
556 | 0 | H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */ |
557 | 0 | size_t chk_size; /* Exact size of the node with checksum at the end */ |
558 | 0 | uint32_t stored_chksum; /* Stored metadata checksum value */ |
559 | 0 | uint32_t computed_chksum; /* Computed metadata checksum value */ |
560 | 0 | htri_t ret_value = true; /* Return value */ |
561 | |
|
562 | 0 | FUNC_ENTER_PACKAGE |
563 | | |
564 | | /* Check arguments */ |
565 | 0 | assert(image); |
566 | 0 | assert(udata); |
567 | | |
568 | | /* Internal node prefix header + records + child pointer triplets: size with checksum at the end */ |
569 | 0 | chk_size = H5B2_INT_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size) + |
570 | 0 | ((size_t)(udata->nrec + 1) * H5B2_INT_POINTER_SIZE(udata->hdr, udata->depth)); |
571 | | |
572 | | /* Get stored and computed checksums */ |
573 | 0 | if (H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum) < 0) |
574 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't get checksums"); |
575 | | |
576 | 0 | if (stored_chksum != computed_chksum) |
577 | 0 | ret_value = false; |
578 | |
|
579 | 0 | done: |
580 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
581 | 0 | } /* end H5B2__cache_int_verify_chksum() */ |
582 | | |
583 | | /*------------------------------------------------------------------------- |
584 | | * Function: H5B2__cache_int_deserialize |
585 | | * |
586 | | * Purpose: Deserialize a B-tree internal node from the disk. |
587 | | * |
588 | | * Return: Success: Pointer to a new B-tree internal node. |
589 | | * Failure: NULL |
590 | | * |
591 | | *------------------------------------------------------------------------- |
592 | | */ |
593 | | static void * |
594 | | H5B2__cache_int_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata, |
595 | | bool H5_ATTR_UNUSED *dirty) |
596 | 0 | { |
597 | 0 | H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */ |
598 | 0 | H5B2_internal_t *internal = NULL; /* Internal node read */ |
599 | 0 | const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ |
600 | 0 | uint8_t *native; /* Pointer to native record info */ |
601 | 0 | H5B2_node_ptr_t *int_node_ptr; /* Pointer to node pointer info */ |
602 | 0 | uint32_t stored_chksum; /* Stored metadata checksum value */ |
603 | 0 | unsigned u; /* Local index variable */ |
604 | 0 | H5B2_internal_t *ret_value = NULL; /* Return value */ |
605 | 0 | int node_nrec = 0; |
606 | |
|
607 | 0 | FUNC_ENTER_PACKAGE |
608 | | |
609 | | /* Check arguments */ |
610 | 0 | assert(image); |
611 | 0 | assert(udata); |
612 | | |
613 | | /* Allocate new internal node and reset cache info */ |
614 | 0 | if (NULL == (internal = H5FL_CALLOC(H5B2_internal_t))) |
615 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); |
616 | | |
617 | | /* Increment ref. count on B-tree header */ |
618 | 0 | if (H5B2__hdr_incr(udata->hdr) < 0) |
619 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment ref. count on B-tree header"); |
620 | | |
621 | | /* Share B-tree information */ |
622 | 0 | internal->hdr = udata->hdr; |
623 | 0 | internal->parent = udata->parent; |
624 | 0 | internal->shadow_epoch = udata->hdr->shadow_epoch; |
625 | | |
626 | | /* Magic number */ |
627 | 0 | if (memcmp(image, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC) != 0) |
628 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree internal node signature"); |
629 | 0 | image += H5_SIZEOF_MAGIC; |
630 | | |
631 | | /* Version */ |
632 | 0 | if (*image++ != H5B2_INT_VERSION) |
633 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree internal node version"); |
634 | | |
635 | | /* B-tree type */ |
636 | 0 | if (*image++ != (uint8_t)udata->hdr->cls->id) |
637 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type"); |
638 | | |
639 | | /* Allocate space for the native keys in memory */ |
640 | 0 | if (NULL == |
641 | 0 | (internal->int_native = (uint8_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[udata->depth].nat_rec_fac))) |
642 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, |
643 | 0 | "memory allocation failed for B-tree internal native keys"); |
644 | | |
645 | | /* Allocate space for the node pointers in memory */ |
646 | 0 | if (NULL == (internal->node_ptrs = |
647 | 0 | (H5B2_node_ptr_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[udata->depth].node_ptr_fac))) |
648 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, |
649 | 0 | "memory allocation failed for B-tree internal node pointers"); |
650 | | |
651 | | /* Set the number of records in the leaf & it's depth */ |
652 | 0 | internal->nrec = udata->nrec; |
653 | 0 | internal->depth = udata->depth; |
654 | | |
655 | | /* Deserialize records for internal node */ |
656 | 0 | native = internal->int_native; |
657 | 0 | for (u = 0; u < internal->nrec; u++) { |
658 | | /* Decode record */ |
659 | 0 | if ((udata->hdr->cls->decode)(image, native, udata->hdr->cb_ctx) < 0) |
660 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTDECODE, NULL, "unable to decode B-tree record"); |
661 | | |
662 | | /* Move to next record */ |
663 | 0 | image += udata->hdr->rrec_size; |
664 | 0 | native += udata->hdr->cls->nrec_size; |
665 | 0 | } /* end for */ |
666 | | |
667 | | /* Deserialize node pointers for internal node */ |
668 | 0 | int_node_ptr = internal->node_ptrs; |
669 | 0 | for (u = 0; u < (unsigned)(internal->nrec + 1); u++) { |
670 | | /* Decode node pointer */ |
671 | 0 | H5F_addr_decode(udata->f, (const uint8_t **)&image, &(int_node_ptr->addr)); |
672 | 0 | UINT64DECODE_VAR(image, node_nrec, udata->hdr->max_nrec_size); |
673 | 0 | H5_CHECKED_ASSIGN(int_node_ptr->node_nrec, uint16_t, node_nrec, int); |
674 | 0 | if (udata->depth > 1) |
675 | 0 | UINT64DECODE_VAR(image, int_node_ptr->all_nrec, |
676 | 0 | udata->hdr->node_info[udata->depth - 1].cum_max_nrec_size); |
677 | 0 | else |
678 | 0 | int_node_ptr->all_nrec = int_node_ptr->node_nrec; |
679 | | |
680 | | /* Move to next node pointer */ |
681 | 0 | int_node_ptr++; |
682 | 0 | } /* end for */ |
683 | | |
684 | | /* checksum verification already done in verify_chksum cb */ |
685 | | |
686 | | /* Metadata checksum */ |
687 | 0 | UINT32DECODE(image, stored_chksum); |
688 | | |
689 | | /* Sanity check parsing */ |
690 | 0 | assert((size_t)(image - (const uint8_t *)_image) <= len); |
691 | | |
692 | | /* Set return value */ |
693 | 0 | ret_value = internal; |
694 | |
|
695 | 0 | done: |
696 | 0 | if (!ret_value && internal) |
697 | 0 | if (H5B2__internal_free(internal) < 0) |
698 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree internal node"); |
699 | |
|
700 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
701 | 0 | } /* H5B2__cache_int_deserialize() */ |
702 | | |
703 | | /*------------------------------------------------------------------------- |
704 | | * Function: H5B2__cache_int_image_len |
705 | | * |
706 | | * Purpose: Compute the size of the data structure on disk. |
707 | | * |
708 | | * Return: Non-negative on success/Negative on failure |
709 | | * |
710 | | *------------------------------------------------------------------------- |
711 | | */ |
712 | | static herr_t |
713 | | H5B2__cache_int_image_len(const void *_thing, size_t *image_len) |
714 | 0 | { |
715 | 0 | const H5B2_internal_t *internal = |
716 | 0 | (const H5B2_internal_t *)_thing; /* Pointer to the B-tree internal node */ |
717 | |
|
718 | 0 | FUNC_ENTER_PACKAGE_NOERR |
719 | | |
720 | | /* Check arguments */ |
721 | 0 | assert(internal); |
722 | 0 | assert(internal->hdr); |
723 | 0 | assert(image_len); |
724 | | |
725 | | /* Set the image length size */ |
726 | 0 | *image_len = internal->hdr->node_size; |
727 | |
|
728 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
729 | 0 | } /* end H5B2__cache_int_image_len() */ |
730 | | |
731 | | /*------------------------------------------------------------------------- |
732 | | * Function: H5B2__cache_int_serialize |
733 | | * |
734 | | * Purpose: Serializes a B-tree internal node for writing to disk. |
735 | | * |
736 | | * Return: Non-negative on success/Negative on failure |
737 | | * |
738 | | *------------------------------------------------------------------------- |
739 | | */ |
740 | | static herr_t |
741 | | H5B2__cache_int_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, void *_thing) |
742 | 0 | { |
743 | 0 | H5B2_internal_t *internal = (H5B2_internal_t *)_thing; /* Pointer to the B-tree internal node */ |
744 | 0 | uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ |
745 | 0 | uint8_t *native; /* Pointer to native record info */ |
746 | 0 | H5B2_node_ptr_t *int_node_ptr; /* Pointer to node pointer info */ |
747 | 0 | uint32_t metadata_chksum; /* Computed metadata checksum value */ |
748 | 0 | unsigned u; /* Local index variable */ |
749 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
750 | |
|
751 | 0 | FUNC_ENTER_PACKAGE |
752 | | |
753 | | /* check arguments */ |
754 | 0 | assert(f); |
755 | 0 | assert(image); |
756 | 0 | assert(internal); |
757 | 0 | assert(internal->hdr); |
758 | | |
759 | | /* Magic number */ |
760 | 0 | H5MM_memcpy(image, H5B2_INT_MAGIC, (size_t)H5_SIZEOF_MAGIC); |
761 | 0 | image += H5_SIZEOF_MAGIC; |
762 | | |
763 | | /* Version # */ |
764 | 0 | *image++ = H5B2_INT_VERSION; |
765 | | |
766 | | /* B-tree type */ |
767 | 0 | assert(internal->hdr->cls->id <= 255); |
768 | 0 | *image++ = (uint8_t)internal->hdr->cls->id; |
769 | 0 | assert((size_t)(image - (uint8_t *)_image) == (H5B2_INT_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM)); |
770 | | |
771 | | /* Serialize records for internal node */ |
772 | 0 | native = internal->int_native; |
773 | 0 | for (u = 0; u < internal->nrec; u++) { |
774 | | /* Encode record */ |
775 | 0 | if ((internal->hdr->cls->encode)(image, native, internal->hdr->cb_ctx) < 0) |
776 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record"); |
777 | | |
778 | | /* Move to next record */ |
779 | 0 | image += internal->hdr->rrec_size; |
780 | 0 | native += internal->hdr->cls->nrec_size; |
781 | 0 | } /* end for */ |
782 | | |
783 | | /* Serialize node pointers for internal node */ |
784 | 0 | int_node_ptr = internal->node_ptrs; |
785 | 0 | for (u = 0; u < (unsigned)(internal->nrec + 1); u++) { |
786 | | /* Encode node pointer */ |
787 | 0 | H5F_addr_encode(f, &image, int_node_ptr->addr); |
788 | 0 | UINT64ENCODE_VAR(image, int_node_ptr->node_nrec, internal->hdr->max_nrec_size); |
789 | 0 | if (internal->depth > 1) |
790 | 0 | UINT64ENCODE_VAR(image, int_node_ptr->all_nrec, |
791 | 0 | internal->hdr->node_info[internal->depth - 1].cum_max_nrec_size); |
792 | | |
793 | | /* Move to next node pointer */ |
794 | 0 | int_node_ptr++; |
795 | 0 | } /* end for */ |
796 | | |
797 | | /* Compute metadata checksum */ |
798 | 0 | metadata_chksum = H5_checksum_metadata(_image, (size_t)(image - (uint8_t *)_image), 0); |
799 | | |
800 | | /* Metadata checksum */ |
801 | 0 | UINT32ENCODE(image, metadata_chksum); |
802 | | |
803 | | /* Sanity check */ |
804 | 0 | assert((size_t)(image - (uint8_t *)_image) <= len); |
805 | | |
806 | | /* Clear rest of internal node */ |
807 | 0 | memset(image, 0, len - (size_t)(image - (uint8_t *)_image)); |
808 | |
|
809 | 0 | done: |
810 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
811 | 0 | } /* H5B2__cache_int_serialize() */ |
812 | | |
813 | | /*------------------------------------------------------------------------- |
814 | | * Function: H5B2__cache_int_notify |
815 | | * |
816 | | * Purpose: Handle cache action notifications |
817 | | * |
818 | | * Return: Non-negative on success/Negative on failure |
819 | | * |
820 | | *------------------------------------------------------------------------- |
821 | | */ |
822 | | static herr_t |
823 | | H5B2__cache_int_notify(H5AC_notify_action_t action, void *_thing) |
824 | 0 | { |
825 | 0 | H5B2_internal_t *internal = (H5B2_internal_t *)_thing; |
826 | 0 | herr_t ret_value = SUCCEED; |
827 | |
|
828 | 0 | FUNC_ENTER_PACKAGE |
829 | | |
830 | | /* |
831 | | * Check arguments. |
832 | | */ |
833 | 0 | assert(internal); |
834 | 0 | assert(internal->hdr); |
835 | | |
836 | | /* Check if the file was opened with SWMR-write access */ |
837 | 0 | if (internal->hdr->swmr_write) { |
838 | 0 | switch (action) { |
839 | 0 | case H5AC_NOTIFY_ACTION_AFTER_INSERT: |
840 | 0 | case H5AC_NOTIFY_ACTION_AFTER_LOAD: |
841 | | /* Create flush dependency on parent */ |
842 | 0 | if (H5B2__create_flush_depend((H5AC_info_t *)internal->parent, (H5AC_info_t *)internal) < 0) |
843 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency"); |
844 | 0 | break; |
845 | | |
846 | 0 | case H5AC_NOTIFY_ACTION_AFTER_FLUSH: |
847 | 0 | case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED: |
848 | 0 | case H5AC_NOTIFY_ACTION_ENTRY_CLEANED: |
849 | 0 | case H5AC_NOTIFY_ACTION_CHILD_DIRTIED: |
850 | 0 | case H5AC_NOTIFY_ACTION_CHILD_CLEANED: |
851 | 0 | case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED: |
852 | 0 | case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED: |
853 | | /* do nothing */ |
854 | 0 | break; |
855 | | |
856 | 0 | case H5AC_NOTIFY_ACTION_BEFORE_EVICT: |
857 | | /* Destroy flush dependency on parent */ |
858 | 0 | if (H5B2__destroy_flush_depend((H5AC_info_t *)internal->parent, (H5AC_info_t *)internal) < 0) |
859 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency"); |
860 | | |
861 | | /* Detach from 'top' proxy for v2 B-tree */ |
862 | 0 | if (internal->top_proxy) { |
863 | 0 | if (H5AC_proxy_entry_remove_child(internal->top_proxy, internal) < 0) |
864 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, |
865 | 0 | "unable to destroy flush dependency between internal node and v2 B-tree " |
866 | 0 | "'top' proxy"); |
867 | 0 | internal->top_proxy = NULL; |
868 | 0 | } /* end if */ |
869 | 0 | break; |
870 | | |
871 | 0 | default: |
872 | 0 | #ifdef NDEBUG |
873 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache"); |
874 | | #else /* NDEBUG */ |
875 | | assert(0 && "Unknown action?!?"); |
876 | | #endif /* NDEBUG */ |
877 | 0 | } /* end switch */ |
878 | 0 | } /* end if */ |
879 | 0 | else |
880 | 0 | assert(NULL == internal->top_proxy); |
881 | | |
882 | 0 | done: |
883 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
884 | 0 | } /* end H5B2__cache_int_notify() */ |
885 | | |
886 | | /*------------------------------------------------------------------------- |
887 | | * Function: H5B2__cache_int_free_icr |
888 | | * |
889 | | * Purpose: Destroy/release an "in core representation" of a data |
890 | | * structure |
891 | | * |
892 | | * Return: Non-negative on success/Negative on failure |
893 | | * |
894 | | *------------------------------------------------------------------------- |
895 | | */ |
896 | | static herr_t |
897 | | H5B2__cache_int_free_icr(void *_thing) |
898 | 0 | { |
899 | 0 | H5B2_internal_t *internal = (H5B2_internal_t *)_thing; |
900 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
901 | |
|
902 | 0 | FUNC_ENTER_PACKAGE |
903 | | |
904 | | /* Check arguments */ |
905 | 0 | assert(internal); |
906 | | |
907 | | /* Release v2 B-tree internal node */ |
908 | 0 | if (H5B2__internal_free(internal) < 0) |
909 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release v2 B-tree internal node"); |
910 | | |
911 | 0 | done: |
912 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
913 | 0 | } /* H5B2__cache_int_free_icr() */ |
914 | | |
915 | | /*------------------------------------------------------------------------- |
916 | | * Function: H5B2__cache_leaf_get_initial_load_size |
917 | | * |
918 | | * Purpose: Compute the size of the data structure on disk. |
919 | | * |
920 | | * Return: Non-negative on success/Negative on failure |
921 | | * |
922 | | *------------------------------------------------------------------------- |
923 | | */ |
924 | | static herr_t |
925 | | H5B2__cache_leaf_get_initial_load_size(void *_udata, size_t *image_len) |
926 | 0 | { |
927 | 0 | H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata; /* User data for callback */ |
928 | |
|
929 | 0 | FUNC_ENTER_PACKAGE_NOERR |
930 | | |
931 | | /* Check arguments */ |
932 | 0 | assert(udata); |
933 | 0 | assert(udata->hdr); |
934 | 0 | assert(image_len); |
935 | | |
936 | | /* Set the image length size */ |
937 | 0 | *image_len = udata->hdr->node_size; |
938 | |
|
939 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
940 | 0 | } /* end H5B2__cache_leaf_get_initial_load_size() */ |
941 | | |
942 | | /*------------------------------------------------------------------------- |
943 | | * Function: H5B2__cache_leaf_verify_chksum |
944 | | * |
945 | | * Purpose: Verify the computed checksum of the data structure is the |
946 | | * same as the stored chksum. |
947 | | * |
948 | | * Return: Success: true/false |
949 | | * Failure: Negative |
950 | | * |
951 | | *------------------------------------------------------------------------- |
952 | | */ |
953 | | static htri_t |
954 | | H5B2__cache_leaf_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata) |
955 | 0 | { |
956 | 0 | const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ |
957 | 0 | H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */ |
958 | 0 | size_t chk_size; /* Exact size of the node with checksum at the end */ |
959 | 0 | uint32_t stored_chksum; /* Stored metadata checksum value */ |
960 | 0 | uint32_t computed_chksum; /* Computed metadata checksum value */ |
961 | 0 | htri_t ret_value = true; /* Return value */ |
962 | |
|
963 | 0 | FUNC_ENTER_PACKAGE |
964 | | |
965 | | /* Check arguments */ |
966 | 0 | assert(image); |
967 | 0 | assert(udata); |
968 | | |
969 | | /* Leaf node prefix header + records: size with checksum at the end */ |
970 | 0 | chk_size = H5B2_LEAF_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size); |
971 | | |
972 | | /* Get stored and computed checksums */ |
973 | 0 | if (H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum) < 0) |
974 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't get checksums"); |
975 | | |
976 | 0 | if (stored_chksum != computed_chksum) |
977 | 0 | ret_value = false; |
978 | |
|
979 | 0 | done: |
980 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
981 | 0 | } /* end H5B2__cache_leaf_verify_chksum() */ |
982 | | |
983 | | /*------------------------------------------------------------------------- |
984 | | * Function: H5B2__cache_leaf_deserialize |
985 | | * |
986 | | * Purpose: Deserialize a B-tree leaf from the disk. |
987 | | * |
988 | | * Return: Success: Pointer to a new B-tree leaf node. |
989 | | * Failure: NULL |
990 | | * |
991 | | *------------------------------------------------------------------------- |
992 | | */ |
993 | | static void * |
994 | | H5B2__cache_leaf_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata, |
995 | | bool H5_ATTR_UNUSED *dirty) |
996 | 0 | { |
997 | 0 | H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata; |
998 | 0 | H5B2_leaf_t *leaf = NULL; /* Pointer to lead node loaded */ |
999 | 0 | const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ |
1000 | 0 | uint8_t *native; /* Pointer to native keys */ |
1001 | 0 | uint32_t stored_chksum; /* Stored metadata checksum value */ |
1002 | 0 | unsigned u; /* Local index variable */ |
1003 | 0 | H5B2_leaf_t *ret_value = NULL; /* Return value */ |
1004 | |
|
1005 | 0 | FUNC_ENTER_PACKAGE |
1006 | | |
1007 | | /* Check arguments */ |
1008 | 0 | assert(image); |
1009 | 0 | assert(udata); |
1010 | | |
1011 | | /* Allocate new leaf node and reset cache info */ |
1012 | 0 | if (NULL == (leaf = H5FL_CALLOC(H5B2_leaf_t))) |
1013 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed"); |
1014 | | |
1015 | | /* Increment ref. count on B-tree header */ |
1016 | 0 | if (H5B2__hdr_incr(udata->hdr) < 0) |
1017 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, NULL, "can't increment ref. count on B-tree header"); |
1018 | | |
1019 | | /* Share B-tree header information */ |
1020 | 0 | leaf->hdr = udata->hdr; |
1021 | 0 | leaf->parent = udata->parent; |
1022 | 0 | leaf->shadow_epoch = udata->hdr->shadow_epoch; |
1023 | | |
1024 | | /* Magic number */ |
1025 | 0 | if (memcmp(image, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC) != 0) |
1026 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "wrong B-tree leaf node signature"); |
1027 | 0 | image += H5_SIZEOF_MAGIC; |
1028 | | |
1029 | | /* Version */ |
1030 | 0 | if (*image++ != H5B2_LEAF_VERSION) |
1031 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADRANGE, NULL, "wrong B-tree leaf node version"); |
1032 | | |
1033 | | /* B-tree type */ |
1034 | 0 | if (*image++ != (uint8_t)udata->hdr->cls->id) |
1035 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADTYPE, NULL, "incorrect B-tree type"); |
1036 | | |
1037 | | /* Allocate space for the native keys in memory */ |
1038 | 0 | if (NULL == (leaf->leaf_native = (uint8_t *)H5FL_FAC_MALLOC(udata->hdr->node_info[0].nat_rec_fac))) |
1039 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree leaf native keys"); |
1040 | | |
1041 | | /* Set the number of records in the leaf */ |
1042 | 0 | leaf->nrec = udata->nrec; |
1043 | | |
1044 | | /* Deserialize records for leaf node */ |
1045 | 0 | native = leaf->leaf_native; |
1046 | 0 | for (u = 0; u < leaf->nrec; u++) { |
1047 | | /* Decode record */ |
1048 | 0 | if ((udata->hdr->cls->decode)(image, native, udata->hdr->cb_ctx) < 0) |
1049 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, NULL, "unable to decode B-tree record"); |
1050 | | |
1051 | | /* Move to next record */ |
1052 | 0 | image += udata->hdr->rrec_size; |
1053 | 0 | native += udata->hdr->cls->nrec_size; |
1054 | 0 | } /* end for */ |
1055 | | |
1056 | | /* checksum verification already done in verify_chksum cb */ |
1057 | | |
1058 | | /* Metadata checksum */ |
1059 | 0 | UINT32DECODE(image, stored_chksum); |
1060 | | |
1061 | | /* Sanity check parsing */ |
1062 | 0 | assert((size_t)(image - (const uint8_t *)_image) <= udata->hdr->node_size); |
1063 | | |
1064 | | /* Sanity check */ |
1065 | 0 | assert((size_t)(image - (const uint8_t *)_image) <= len); |
1066 | | |
1067 | | /* Set return value */ |
1068 | 0 | ret_value = leaf; |
1069 | |
|
1070 | 0 | done: |
1071 | 0 | if (!ret_value && leaf) |
1072 | 0 | if (H5B2__leaf_free(leaf) < 0) |
1073 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree leaf node"); |
1074 | |
|
1075 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1076 | 0 | } /* H5B2__cache_leaf_deserialize() */ |
1077 | | |
1078 | | /*------------------------------------------------------------------------- |
1079 | | * Function: H5B2__cache_leaf_image_len |
1080 | | * |
1081 | | * Purpose: Compute the size of the data structure on disk. |
1082 | | * |
1083 | | * Return: Non-negative on success/Negative on failure |
1084 | | * |
1085 | | *------------------------------------------------------------------------- |
1086 | | */ |
1087 | | static herr_t |
1088 | | H5B2__cache_leaf_image_len(const void *_thing, size_t *image_len) |
1089 | 0 | { |
1090 | 0 | const H5B2_leaf_t *leaf = (const H5B2_leaf_t *)_thing; /* Pointer to the B-tree leaf node */ |
1091 | |
|
1092 | 0 | FUNC_ENTER_PACKAGE_NOERR |
1093 | | |
1094 | | /* Check arguments */ |
1095 | 0 | assert(leaf); |
1096 | 0 | assert(leaf->hdr); |
1097 | 0 | assert(image_len); |
1098 | | |
1099 | | /* Set the image length size */ |
1100 | 0 | *image_len = leaf->hdr->node_size; |
1101 | |
|
1102 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
1103 | 0 | } /* end H5B2__cache_leaf_image_len() */ |
1104 | | |
1105 | | /*------------------------------------------------------------------------- |
1106 | | * Function: H5B2__cache_leaf_serialize |
1107 | | * |
1108 | | * Purpose: Serializes a B-tree leaf node for writing to disk. |
1109 | | * |
1110 | | * Return: Non-negative on success/Negative on failure |
1111 | | * |
1112 | | *------------------------------------------------------------------------- |
1113 | | */ |
1114 | | static herr_t |
1115 | | H5B2__cache_leaf_serialize(const H5F_t H5_ATTR_UNUSED *f, void *_image, size_t H5_ATTR_UNUSED len, |
1116 | | void *_thing) |
1117 | 0 | { |
1118 | 0 | H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing; /* Pointer to the B-tree leaf node */ |
1119 | 0 | uint8_t *image = (uint8_t *)_image; /* Pointer into raw data buffer */ |
1120 | 0 | uint8_t *native; /* Pointer to native keys */ |
1121 | 0 | uint32_t metadata_chksum; /* Computed metadata checksum value */ |
1122 | 0 | unsigned u; /* Local index variable */ |
1123 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1124 | |
|
1125 | 0 | FUNC_ENTER_PACKAGE |
1126 | | |
1127 | | /* check arguments */ |
1128 | 0 | assert(f); |
1129 | 0 | assert(image); |
1130 | 0 | assert(leaf); |
1131 | 0 | assert(leaf->hdr); |
1132 | | |
1133 | | /* magic number */ |
1134 | 0 | H5MM_memcpy(image, H5B2_LEAF_MAGIC, (size_t)H5_SIZEOF_MAGIC); |
1135 | 0 | image += H5_SIZEOF_MAGIC; |
1136 | | |
1137 | | /* version # */ |
1138 | 0 | *image++ = H5B2_LEAF_VERSION; |
1139 | | |
1140 | | /* B-tree type */ |
1141 | 0 | assert(leaf->hdr->cls->id <= 255); |
1142 | 0 | *image++ = (uint8_t)leaf->hdr->cls->id; |
1143 | 0 | assert((size_t)(image - (uint8_t *)_image) == (H5B2_LEAF_PREFIX_SIZE - H5B2_SIZEOF_CHKSUM)); |
1144 | | |
1145 | | /* Serialize records for leaf node */ |
1146 | 0 | native = leaf->leaf_native; |
1147 | 0 | for (u = 0; u < leaf->nrec; u++) { |
1148 | | /* Encode record */ |
1149 | 0 | if ((leaf->hdr->cls->encode)(image, native, leaf->hdr->cb_ctx) < 0) |
1150 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTENCODE, FAIL, "unable to encode B-tree record"); |
1151 | | |
1152 | | /* Move to next record */ |
1153 | 0 | image += leaf->hdr->rrec_size; |
1154 | 0 | native += leaf->hdr->cls->nrec_size; |
1155 | 0 | } /* end for */ |
1156 | | |
1157 | | /* Compute metadata checksum */ |
1158 | 0 | metadata_chksum = |
1159 | 0 | H5_checksum_metadata(_image, (size_t)((const uint8_t *)image - (const uint8_t *)_image), 0); |
1160 | | |
1161 | | /* Metadata checksum */ |
1162 | 0 | UINT32ENCODE(image, metadata_chksum); |
1163 | | |
1164 | | /* Sanity check */ |
1165 | 0 | assert((size_t)(image - (uint8_t *)_image) <= len); |
1166 | | |
1167 | | /* Clear rest of leaf node */ |
1168 | 0 | memset(image, 0, len - (size_t)(image - (uint8_t *)_image)); |
1169 | |
|
1170 | 0 | done: |
1171 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1172 | 0 | } /* H5B2__cache_leaf_serialize() */ |
1173 | | |
1174 | | /*------------------------------------------------------------------------- |
1175 | | * Function: H5B2__cache_leaf_notify |
1176 | | * |
1177 | | * Purpose: Handle cache action notifications |
1178 | | * |
1179 | | * Return: Non-negative on success/Negative on failure |
1180 | | * |
1181 | | *------------------------------------------------------------------------- |
1182 | | */ |
1183 | | static herr_t |
1184 | | H5B2__cache_leaf_notify(H5AC_notify_action_t action, void *_thing) |
1185 | 0 | { |
1186 | 0 | H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing; |
1187 | 0 | herr_t ret_value = SUCCEED; |
1188 | |
|
1189 | 0 | FUNC_ENTER_PACKAGE |
1190 | | |
1191 | | /* |
1192 | | * Check arguments. |
1193 | | */ |
1194 | 0 | assert(leaf); |
1195 | 0 | assert(leaf->hdr); |
1196 | | |
1197 | | /* Check if the file was opened with SWMR-write access */ |
1198 | 0 | if (leaf->hdr->swmr_write) { |
1199 | 0 | switch (action) { |
1200 | 0 | case H5AC_NOTIFY_ACTION_AFTER_INSERT: |
1201 | 0 | case H5AC_NOTIFY_ACTION_AFTER_LOAD: |
1202 | | /* Create flush dependency on parent */ |
1203 | 0 | if (H5B2__create_flush_depend((H5AC_info_t *)leaf->parent, (H5AC_info_t *)leaf) < 0) |
1204 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTDEPEND, FAIL, "unable to create flush dependency"); |
1205 | 0 | break; |
1206 | | |
1207 | 0 | case H5AC_NOTIFY_ACTION_AFTER_FLUSH: |
1208 | 0 | case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED: |
1209 | 0 | case H5AC_NOTIFY_ACTION_ENTRY_CLEANED: |
1210 | 0 | case H5AC_NOTIFY_ACTION_CHILD_DIRTIED: |
1211 | 0 | case H5AC_NOTIFY_ACTION_CHILD_CLEANED: |
1212 | 0 | case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED: |
1213 | 0 | case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED: |
1214 | | /* do nothing */ |
1215 | 0 | break; |
1216 | | |
1217 | 0 | case H5AC_NOTIFY_ACTION_BEFORE_EVICT: |
1218 | | /* Destroy flush dependency on parent */ |
1219 | 0 | if (H5B2__destroy_flush_depend((H5AC_info_t *)leaf->parent, (H5AC_info_t *)leaf) < 0) |
1220 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency"); |
1221 | | |
1222 | | /* Detach from 'top' proxy for v2 B-tree */ |
1223 | 0 | if (leaf->top_proxy) { |
1224 | 0 | if (H5AC_proxy_entry_remove_child(leaf->top_proxy, leaf) < 0) |
1225 | 0 | HGOTO_ERROR( |
1226 | 0 | H5E_BTREE, H5E_CANTUNDEPEND, FAIL, |
1227 | 0 | "unable to destroy flush dependency between leaf node and v2 B-tree 'top' proxy"); |
1228 | 0 | leaf->top_proxy = NULL; |
1229 | 0 | } /* end if */ |
1230 | 0 | break; |
1231 | | |
1232 | 0 | default: |
1233 | 0 | #ifdef NDEBUG |
1234 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "unknown action from metadata cache"); |
1235 | | #else /* NDEBUG */ |
1236 | | assert(0 && "Unknown action?!?"); |
1237 | | #endif /* NDEBUG */ |
1238 | 0 | } /* end switch */ |
1239 | 0 | } /* end if */ |
1240 | 0 | else |
1241 | 0 | assert(NULL == leaf->top_proxy); |
1242 | | |
1243 | 0 | done: |
1244 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1245 | 0 | } /* end H5B2__cache_leaf_notify() */ |
1246 | | |
1247 | | /*------------------------------------------------------------------------- |
1248 | | * Function: H5B2__cache_leaf_free_icr |
1249 | | * |
1250 | | * Purpose: Destroy/release an "in core representation" of a data |
1251 | | * structure |
1252 | | * |
1253 | | * Return: Non-negative on success/Negative on failure |
1254 | | * |
1255 | | *------------------------------------------------------------------------- |
1256 | | */ |
1257 | | static herr_t |
1258 | | H5B2__cache_leaf_free_icr(void *_thing) |
1259 | 0 | { |
1260 | 0 | H5B2_leaf_t *leaf = (H5B2_leaf_t *)_thing; |
1261 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1262 | |
|
1263 | 0 | FUNC_ENTER_PACKAGE |
1264 | | |
1265 | | /* Check arguments */ |
1266 | 0 | assert(leaf); |
1267 | | |
1268 | | /* Destroy v2 B-tree leaf node */ |
1269 | 0 | if (H5B2__leaf_free(leaf) < 0) |
1270 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree leaf node"); |
1271 | | |
1272 | 0 | done: |
1273 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1274 | 0 | } /* H5B2__cache_leaf_free_icr() */ |