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: H5B2leaf.c |
16 | | * |
17 | | * Purpose: Routines for managing v2 B-tree leaf nodes. |
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 "H5B2pkg.h" /* v2 B-trees */ |
33 | | #include "H5Eprivate.h" /* Error handling */ |
34 | | #include "H5FLprivate.h" /* Free Lists */ |
35 | | #include "H5MFprivate.h" /* File memory management */ |
36 | | #include "H5MMprivate.h" /* Memory management */ |
37 | | |
38 | | /****************/ |
39 | | /* Local Macros */ |
40 | | /****************/ |
41 | | |
42 | | /******************/ |
43 | | /* Local Typedefs */ |
44 | | /******************/ |
45 | | |
46 | | /********************/ |
47 | | /* Package Typedefs */ |
48 | | /********************/ |
49 | | |
50 | | /********************/ |
51 | | /* Local Prototypes */ |
52 | | /********************/ |
53 | | static herr_t H5B2__shadow_leaf(H5B2_leaf_t *leaf, H5B2_node_ptr_t *curr_node_ptr); |
54 | | |
55 | | /*********************/ |
56 | | /* Package Variables */ |
57 | | /*********************/ |
58 | | |
59 | | /* Declare a free list to manage the H5B2_leaf_t struct */ |
60 | | H5FL_DEFINE(H5B2_leaf_t); |
61 | | |
62 | | /*****************************/ |
63 | | /* Library Private Variables */ |
64 | | /*****************************/ |
65 | | |
66 | | /*******************/ |
67 | | /* Local Variables */ |
68 | | /*******************/ |
69 | | |
70 | | /*------------------------------------------------------------------------- |
71 | | * Function: H5B2__create_leaf |
72 | | * |
73 | | * Purpose: Creates empty leaf node of a B-tree and update node pointer |
74 | | * to point to it. |
75 | | * |
76 | | * Return: Non-negative on success/Negative on failure |
77 | | * |
78 | | *------------------------------------------------------------------------- |
79 | | */ |
80 | | herr_t |
81 | | H5B2__create_leaf(H5B2_hdr_t *hdr, void *parent, H5B2_node_ptr_t *node_ptr) |
82 | 0 | { |
83 | 0 | H5B2_leaf_t *leaf = NULL; /* Pointer to new leaf node created */ |
84 | 0 | bool inserted = false; /* Whether the leaf node was inserted into cache */ |
85 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
86 | |
|
87 | 0 | FUNC_ENTER_PACKAGE |
88 | | |
89 | | /* Check arguments. */ |
90 | 0 | assert(hdr); |
91 | 0 | assert(node_ptr); |
92 | | |
93 | | /* Allocate memory for leaf information */ |
94 | 0 | if (NULL == (leaf = H5FL_CALLOC(H5B2_leaf_t))) |
95 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree leaf info"); |
96 | | |
97 | | /* Increment ref. count on B-tree header */ |
98 | 0 | if (H5B2__hdr_incr(hdr) < 0) |
99 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTINC, FAIL, "can't increment ref. count on B-tree header"); |
100 | | |
101 | | /* Share B-tree header information */ |
102 | 0 | leaf->hdr = hdr; |
103 | | |
104 | | /* Allocate space for the native keys in memory */ |
105 | 0 | if (NULL == (leaf->leaf_native = (uint8_t *)H5FL_FAC_MALLOC(hdr->node_info[0].nat_rec_fac))) |
106 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for B-tree leaf native keys"); |
107 | 0 | memset(leaf->leaf_native, 0, hdr->cls->nrec_size * hdr->node_info[0].max_nrec); |
108 | | |
109 | | /* Set parent */ |
110 | 0 | leaf->parent = parent; |
111 | | |
112 | | /* Set shadowed epoch to header's epoch */ |
113 | 0 | leaf->shadow_epoch = hdr->shadow_epoch; |
114 | | |
115 | | /* Allocate space on disk for the leaf */ |
116 | 0 | if (HADDR_UNDEF == (node_ptr->addr = H5MF_alloc(hdr->f, H5FD_MEM_BTREE, (hsize_t)hdr->node_size))) |
117 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for B-tree leaf node"); |
118 | | |
119 | | /* Cache the new B-tree node */ |
120 | 0 | if (H5AC_insert_entry(hdr->f, H5AC_BT2_LEAF, node_ptr->addr, leaf, H5AC__NO_FLAGS_SET) < 0) |
121 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't add B-tree leaf to cache"); |
122 | 0 | inserted = true; |
123 | | |
124 | | /* Add leaf node as child of 'top' proxy */ |
125 | 0 | if (hdr->top_proxy) { |
126 | 0 | if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, leaf) < 0) |
127 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, FAIL, "unable to add v2 B-tree node as child of proxy"); |
128 | 0 | leaf->top_proxy = hdr->top_proxy; |
129 | 0 | } /* end if */ |
130 | | |
131 | 0 | done: |
132 | 0 | if (ret_value < 0) { |
133 | 0 | if (leaf) { |
134 | | /* Remove from cache, if inserted */ |
135 | 0 | if (inserted) |
136 | 0 | if (H5AC_remove_entry(leaf) < 0) |
137 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTREMOVE, FAIL, |
138 | 0 | "unable to remove v2 B-tree leaf node from cache"); |
139 | | |
140 | | /* Release leaf node's disk space */ |
141 | 0 | if (H5_addr_defined(node_ptr->addr) && |
142 | 0 | H5MF_xfree(hdr->f, H5FD_MEM_BTREE, node_ptr->addr, (hsize_t)hdr->node_size) < 0) |
143 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, |
144 | 0 | "unable to release file space for v2 B-tree leaf node"); |
145 | | |
146 | | /* Destroy leaf node */ |
147 | 0 | if (H5B2__leaf_free(leaf) < 0) |
148 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to release v2 B-tree leaf node"); |
149 | 0 | } /* end if */ |
150 | 0 | } /* end if */ |
151 | |
|
152 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
153 | 0 | } /* H5B2__create_leaf() */ |
154 | | |
155 | | /*------------------------------------------------------------------------- |
156 | | * Function: H5B2__protect_leaf |
157 | | * |
158 | | * Purpose: "Protect" an leaf node in the metadata cache |
159 | | * |
160 | | * Return: Pointer to leaf node on success/NULL on failure |
161 | | * |
162 | | *------------------------------------------------------------------------- |
163 | | */ |
164 | | H5B2_leaf_t * |
165 | | H5B2__protect_leaf(H5B2_hdr_t *hdr, void *parent, H5B2_node_ptr_t *node_ptr, bool shadow, unsigned flags) |
166 | 0 | { |
167 | 0 | H5B2_leaf_cache_ud_t udata; /* User-data for callback */ |
168 | 0 | H5B2_leaf_t *leaf; /* v2 B-tree leaf node */ |
169 | 0 | H5B2_leaf_t *ret_value = NULL; /* Return value */ |
170 | |
|
171 | 0 | FUNC_ENTER_PACKAGE |
172 | | |
173 | | /* Check arguments. */ |
174 | 0 | assert(hdr); |
175 | 0 | assert(node_ptr); |
176 | 0 | assert(H5_addr_defined(node_ptr->addr)); |
177 | | |
178 | | /* only H5AC__READ_ONLY_FLAG may appear in flags */ |
179 | 0 | assert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); |
180 | | |
181 | | /* Set up user data for callback */ |
182 | 0 | udata.f = hdr->f; |
183 | 0 | udata.hdr = hdr; |
184 | 0 | udata.parent = parent; |
185 | 0 | udata.nrec = node_ptr->node_nrec; |
186 | | |
187 | | /* Protect the leaf node */ |
188 | 0 | if (NULL == (leaf = (H5B2_leaf_t *)H5AC_protect(hdr->f, H5AC_BT2_LEAF, node_ptr->addr, &udata, flags))) |
189 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to protect B-tree leaf node"); |
190 | | |
191 | | /* Create top proxy, if it doesn't exist */ |
192 | 0 | if (hdr->top_proxy && NULL == leaf->top_proxy) { |
193 | | /* Add leaf node as child of 'top' proxy */ |
194 | 0 | if (H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, leaf) < 0) |
195 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, NULL, "unable to add v2 B-tree leaf node as child of proxy"); |
196 | 0 | leaf->top_proxy = hdr->top_proxy; |
197 | 0 | } /* end if */ |
198 | | |
199 | | /* Shadow the node, if requested */ |
200 | 0 | if (shadow) |
201 | 0 | if (H5B2__shadow_leaf(leaf, node_ptr) < 0) |
202 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, NULL, "unable to shadow leaf node"); |
203 | | |
204 | | /* Set return value */ |
205 | 0 | ret_value = leaf; |
206 | |
|
207 | 0 | done: |
208 | | /* Clean up on error */ |
209 | 0 | if (!ret_value) { |
210 | | /* Release the leaf node, if it was protected */ |
211 | 0 | if (leaf) { |
212 | | /* Remove from v2 B-tree's proxy, if added */ |
213 | 0 | if (leaf->top_proxy) { |
214 | 0 | if (H5AC_proxy_entry_remove_child(leaf->top_proxy, leaf) < 0) |
215 | 0 | HDONE_ERROR( |
216 | 0 | H5E_BTREE, H5E_CANTUNDEPEND, NULL, |
217 | 0 | "unable to destroy flush dependency between leaf node and v2 B-tree 'top' proxy"); |
218 | 0 | leaf->top_proxy = NULL; |
219 | 0 | } /* end if */ |
220 | | |
221 | | /* Unprotect leaf node */ |
222 | 0 | if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, node_ptr->addr, leaf, H5AC__NO_FLAGS_SET) < 0) |
223 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, NULL, |
224 | 0 | "unable to unprotect v2 B-tree leaf node, address = %llu", |
225 | 0 | (unsigned long long)node_ptr->addr); |
226 | 0 | } /* end if */ |
227 | 0 | } /* end if */ |
228 | |
|
229 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
230 | 0 | } /* H5B2__protect_leaf() */ |
231 | | |
232 | | /*------------------------------------------------------------------------- |
233 | | * Function: H5B2__neighbor_leaf |
234 | | * |
235 | | * Purpose: Locate a record relative to the specified information in a |
236 | | * B-tree leaf node and return that information by filling in |
237 | | * fields of the |
238 | | * caller-supplied UDATA pointer depending on the type of leaf node |
239 | | * requested. The UDATA can point to additional data passed |
240 | | * to the key comparison function. |
241 | | * |
242 | | * The 'OP' routine is called with the record found and the |
243 | | * OP_DATA pointer, to allow caller to return information about |
244 | | * the record. |
245 | | * |
246 | | * The RANGE indicates whether to search for records less than or |
247 | | * equal to, or greater than or equal to the information passed |
248 | | * in with UDATA. |
249 | | * |
250 | | * Return: Non-negative on success, negative on failure. |
251 | | * |
252 | | *------------------------------------------------------------------------- |
253 | | */ |
254 | | herr_t |
255 | | H5B2__neighbor_leaf(H5B2_hdr_t *hdr, H5B2_node_ptr_t *curr_node_ptr, void *neighbor_loc, H5B2_compare_t comp, |
256 | | void *parent, void *udata, H5B2_found_t op, void *op_data) |
257 | 0 | { |
258 | 0 | H5B2_leaf_t *leaf; /* Pointer to leaf node */ |
259 | 0 | unsigned idx = 0; /* Location of record which matches key */ |
260 | 0 | int cmp = 0; /* Comparison value of records */ |
261 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
262 | |
|
263 | 0 | FUNC_ENTER_PACKAGE |
264 | | |
265 | | /* Check arguments. */ |
266 | 0 | assert(hdr); |
267 | 0 | assert(curr_node_ptr); |
268 | 0 | assert(H5_addr_defined(curr_node_ptr->addr)); |
269 | 0 | assert(op); |
270 | | |
271 | | /* Lock current B-tree node */ |
272 | 0 | if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, curr_node_ptr, false, H5AC__READ_ONLY_FLAG))) |
273 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node"); |
274 | | |
275 | | /* Locate node pointer for child */ |
276 | 0 | if (H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0) |
277 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records"); |
278 | 0 | if (cmp > 0) |
279 | 0 | idx++; |
280 | 0 | else if (cmp == 0 && comp == H5B2_COMPARE_GREATER) |
281 | 0 | idx++; |
282 | | |
283 | | /* Set the neighbor location, if appropriate */ |
284 | 0 | if (comp == H5B2_COMPARE_LESS) { |
285 | 0 | if (idx > 0) |
286 | 0 | neighbor_loc = H5B2_LEAF_NREC(leaf, hdr, idx - 1); |
287 | 0 | } /* end if */ |
288 | 0 | else { |
289 | 0 | assert(comp == H5B2_COMPARE_GREATER); |
290 | |
|
291 | 0 | if (idx < leaf->nrec) |
292 | 0 | neighbor_loc = H5B2_LEAF_NREC(leaf, hdr, idx); |
293 | 0 | } /* end else */ |
294 | | |
295 | | /* Make callback if neighbor record has been found */ |
296 | 0 | if (neighbor_loc) { |
297 | | /* Make callback for current record */ |
298 | 0 | if ((op)(neighbor_loc, op_data) < 0) |
299 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, |
300 | 0 | "'found' callback failed for B-tree neighbor operation"); |
301 | 0 | } /* end if */ |
302 | 0 | else |
303 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to find neighbor record in B-tree"); |
304 | | |
305 | 0 | done: |
306 | | /* Release the B-tree leaf node */ |
307 | 0 | if (leaf && H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr->addr, leaf, H5AC__NO_FLAGS_SET) < 0) |
308 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree leaf node"); |
309 | |
|
310 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
311 | 0 | } /* H5B2__neighbor_leaf() */ |
312 | | |
313 | | /*------------------------------------------------------------------------- |
314 | | * Function: H5B2__insert_leaf |
315 | | * |
316 | | * Purpose: Adds a new record to a B-tree leaf node. |
317 | | * |
318 | | * Return: Non-negative on success/Negative on failure |
319 | | * |
320 | | *------------------------------------------------------------------------- |
321 | | */ |
322 | | herr_t |
323 | | H5B2__insert_leaf(H5B2_hdr_t *hdr, H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, void *parent, |
324 | | void *udata) |
325 | 0 | { |
326 | 0 | H5B2_leaf_t *leaf; /* Pointer to leaf node */ |
327 | 0 | unsigned leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting the leaf node */ |
328 | 0 | int cmp; /* Comparison value of records */ |
329 | 0 | unsigned idx = 0; /* Location of record which matches key */ |
330 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
331 | |
|
332 | 0 | FUNC_ENTER_PACKAGE |
333 | | |
334 | | /* Check arguments. */ |
335 | 0 | assert(hdr); |
336 | 0 | assert(curr_node_ptr); |
337 | 0 | assert(H5_addr_defined(curr_node_ptr->addr)); |
338 | | |
339 | | /* Lock current B-tree node */ |
340 | 0 | if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, curr_node_ptr, false, H5AC__NO_FLAGS_SET))) |
341 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node"); |
342 | | |
343 | | /* Must have a leaf node with enough space to insert a record now */ |
344 | 0 | assert(curr_node_ptr->node_nrec < hdr->node_info[0].max_nrec); |
345 | | |
346 | | /* Sanity check number of records */ |
347 | 0 | assert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec); |
348 | 0 | assert(leaf->nrec == curr_node_ptr->node_nrec); |
349 | | |
350 | | /* Check for inserting into empty leaf */ |
351 | 0 | if (leaf->nrec == 0) |
352 | 0 | idx = 0; |
353 | 0 | else { |
354 | | /* Find correct location to insert this record */ |
355 | 0 | if (H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0) |
356 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records"); |
357 | 0 | if (cmp == 0) |
358 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_EXISTS, FAIL, "record is already in B-tree"); |
359 | 0 | if (cmp > 0) |
360 | 0 | idx++; |
361 | | |
362 | | /* Make room for new record */ |
363 | 0 | if (idx < leaf->nrec) |
364 | 0 | memmove(H5B2_LEAF_NREC(leaf, hdr, idx + 1), H5B2_LEAF_NREC(leaf, hdr, idx), |
365 | 0 | hdr->cls->nrec_size * (leaf->nrec - idx)); |
366 | 0 | } /* end else */ |
367 | | |
368 | | /* Make callback to store record in native form */ |
369 | 0 | if ((hdr->cls->store)(H5B2_LEAF_NREC(leaf, hdr, idx), udata) < 0) |
370 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into leaf node"); |
371 | | |
372 | | /* Mark the node as dirty */ |
373 | 0 | leaf_flags |= H5AC__DIRTIED_FLAG; |
374 | | |
375 | | /* Update record count for node pointer to current node */ |
376 | 0 | curr_node_ptr->all_nrec++; |
377 | 0 | curr_node_ptr->node_nrec++; |
378 | | |
379 | | /* Update record count for current node */ |
380 | 0 | leaf->nrec++; |
381 | | |
382 | | /* Check for new record being the min or max for the tree */ |
383 | | /* (Don't use 'else' for the idx check, to allow for root leaf node) */ |
384 | 0 | if (H5B2_POS_MIDDLE != curr_pos) { |
385 | 0 | if (idx == 0) { |
386 | 0 | if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) { |
387 | 0 | if (hdr->min_native_rec == NULL) |
388 | 0 | if (NULL == (hdr->min_native_rec = H5MM_malloc(hdr->cls->nrec_size))) |
389 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, |
390 | 0 | "memory allocation failed for v2 B-tree min record info"); |
391 | 0 | H5MM_memcpy(hdr->min_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size); |
392 | 0 | } /* end if */ |
393 | 0 | } /* end if */ |
394 | 0 | if (idx == (unsigned)(leaf->nrec - 1)) { |
395 | 0 | if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) { |
396 | 0 | if (hdr->max_native_rec == NULL) |
397 | 0 | if (NULL == (hdr->max_native_rec = H5MM_malloc(hdr->cls->nrec_size))) |
398 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, |
399 | 0 | "memory allocation failed for v2 B-tree max record info"); |
400 | 0 | H5MM_memcpy(hdr->max_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size); |
401 | 0 | } /* end if */ |
402 | 0 | } /* end if */ |
403 | 0 | } /* end if */ |
404 | | |
405 | 0 | done: |
406 | | /* Release the B-tree leaf node (marked as dirty) */ |
407 | 0 | if (leaf) { |
408 | | /* Shadow the node if doing SWMR writes */ |
409 | 0 | if (hdr->swmr_write && (leaf_flags & H5AC__DIRTIED_FLAG)) |
410 | 0 | if (H5B2__shadow_leaf(leaf, curr_node_ptr) < 0) |
411 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf B-tree node"); |
412 | | |
413 | | /* Unprotect leaf node */ |
414 | 0 | if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr->addr, leaf, leaf_flags) < 0) |
415 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node"); |
416 | 0 | } /* end if */ |
417 | |
|
418 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
419 | 0 | } /* H5B2__insert_leaf() */ |
420 | | |
421 | | /*------------------------------------------------------------------------- |
422 | | * Function: H5B2__update_leaf |
423 | | * |
424 | | * Purpose: Insert or modify a record in a B-tree leaf node. |
425 | | * If the record exists already, it is modified as if H5B2_modify |
426 | | * was called). If it doesn't exist, it is inserted as if |
427 | | * H5B2_insert was called. |
428 | | * |
429 | | * Return: Non-negative on success/Negative on failure |
430 | | * |
431 | | *------------------------------------------------------------------------- |
432 | | */ |
433 | | herr_t |
434 | | H5B2__update_leaf(H5B2_hdr_t *hdr, H5B2_node_ptr_t *curr_node_ptr, H5B2_update_status_t *status, |
435 | | H5B2_nodepos_t curr_pos, void *parent, void *udata, H5B2_modify_t op, void *op_data) |
436 | 0 | { |
437 | 0 | H5B2_leaf_t *leaf; /* Pointer to leaf node */ |
438 | 0 | unsigned leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting the leaf node */ |
439 | 0 | int cmp = -1; /* Comparison value of records */ |
440 | 0 | unsigned idx = 0; /* Location of record which matches key */ |
441 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
442 | |
|
443 | 0 | FUNC_ENTER_PACKAGE |
444 | | |
445 | | /* Check arguments. */ |
446 | 0 | assert(hdr); |
447 | 0 | assert(curr_node_ptr); |
448 | 0 | assert(H5_addr_defined(curr_node_ptr->addr)); |
449 | | |
450 | | /* Lock current B-tree node */ |
451 | 0 | if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, curr_node_ptr, false, H5AC__NO_FLAGS_SET))) |
452 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node"); |
453 | | |
454 | | /* Sanity check number of records */ |
455 | 0 | assert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec); |
456 | 0 | assert(leaf->nrec == curr_node_ptr->node_nrec); |
457 | | |
458 | | /* Check for inserting into empty leaf */ |
459 | 0 | if (leaf->nrec == 0) |
460 | 0 | idx = 0; |
461 | 0 | else { |
462 | | /* Find correct location to insert this record */ |
463 | 0 | if (H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0) |
464 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records"); |
465 | | |
466 | | /* Check for inserting a record */ |
467 | 0 | if (0 != cmp) { |
468 | | /* Check if the leaf node is full */ |
469 | 0 | if (curr_node_ptr->node_nrec == hdr->node_info[0].split_nrec) { |
470 | | /* Indicate that the leaf is full, but we need to insert */ |
471 | 0 | *status = H5B2_UPDATE_INSERT_CHILD_FULL; |
472 | | |
473 | | /* Let calling routine handle insertion */ |
474 | 0 | HGOTO_DONE(SUCCEED); |
475 | 0 | } /* end if */ |
476 | | |
477 | | /* Adjust index to leave room for record to insert */ |
478 | 0 | if (cmp > 0) |
479 | 0 | idx++; |
480 | | |
481 | | /* Make room for new record */ |
482 | 0 | if (idx < leaf->nrec) |
483 | 0 | memmove(H5B2_LEAF_NREC(leaf, hdr, idx + 1), H5B2_LEAF_NREC(leaf, hdr, idx), |
484 | 0 | hdr->cls->nrec_size * (leaf->nrec - idx)); |
485 | 0 | } /* end if */ |
486 | 0 | } /* end else */ |
487 | | |
488 | | /* Check for modifying existing record */ |
489 | 0 | if (0 == cmp) { |
490 | 0 | bool changed = false; /* Whether the 'modify' callback changed the record */ |
491 | | |
492 | | /* Make callback for current record */ |
493 | 0 | if ((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data, &changed) < 0) { |
494 | | /* Make certain that the callback didn't modify the value if it failed */ |
495 | 0 | assert(changed == false); |
496 | |
|
497 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTMODIFY, FAIL, |
498 | 0 | "'modify' callback failed for B-tree update operation"); |
499 | 0 | } /* end if */ |
500 | | |
501 | | /* Mark the node as dirty if it changed */ |
502 | 0 | leaf_flags |= (changed ? H5AC__DIRTIED_FLAG : 0); |
503 | | |
504 | | /* Indicate that the record was modified */ |
505 | 0 | *status = H5B2_UPDATE_MODIFY_DONE; |
506 | 0 | } /* end if */ |
507 | 0 | else { |
508 | | /* Must have a leaf node with enough space to insert a record now */ |
509 | 0 | assert(curr_node_ptr->node_nrec < hdr->node_info[0].max_nrec); |
510 | | |
511 | | /* Make callback to store record in native form */ |
512 | 0 | if ((hdr->cls->store)(H5B2_LEAF_NREC(leaf, hdr, idx), udata) < 0) |
513 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert record into leaf node"); |
514 | | |
515 | | /* Mark the node as dirty */ |
516 | 0 | leaf_flags |= H5AC__DIRTIED_FLAG; |
517 | | |
518 | | /* Indicate that the record was inserted */ |
519 | 0 | *status = H5B2_UPDATE_INSERT_DONE; |
520 | | |
521 | | /* Update record count for node pointer to current node */ |
522 | 0 | curr_node_ptr->all_nrec++; |
523 | 0 | curr_node_ptr->node_nrec++; |
524 | | |
525 | | /* Update record count for current node */ |
526 | 0 | leaf->nrec++; |
527 | 0 | } /* end else */ |
528 | | |
529 | | /* Check for new record being the min or max for the tree */ |
530 | | /* (Don't use 'else' for the idx check, to allow for root leaf node) */ |
531 | 0 | if (H5B2_POS_MIDDLE != curr_pos) { |
532 | 0 | if (idx == 0) { |
533 | 0 | if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) { |
534 | 0 | if (hdr->min_native_rec == NULL) |
535 | 0 | if (NULL == (hdr->min_native_rec = H5MM_malloc(hdr->cls->nrec_size))) |
536 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, |
537 | 0 | "memory allocation failed for v2 B-tree min record info"); |
538 | 0 | H5MM_memcpy(hdr->min_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size); |
539 | 0 | } /* end if */ |
540 | 0 | } /* end if */ |
541 | 0 | if (idx == (unsigned)(leaf->nrec - 1)) { |
542 | 0 | if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) { |
543 | 0 | if (hdr->max_native_rec == NULL) |
544 | 0 | if (NULL == (hdr->max_native_rec = H5MM_malloc(hdr->cls->nrec_size))) |
545 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, |
546 | 0 | "memory allocation failed for v2 B-tree max record info"); |
547 | 0 | H5MM_memcpy(hdr->max_native_rec, H5B2_LEAF_NREC(leaf, hdr, idx), hdr->cls->nrec_size); |
548 | 0 | } /* end if */ |
549 | 0 | } /* end if */ |
550 | 0 | } /* end if */ |
551 | | |
552 | 0 | done: |
553 | | /* Release the B-tree leaf node */ |
554 | 0 | if (leaf) { |
555 | | /* Check if we should shadow this node */ |
556 | 0 | if (hdr->swmr_write && (leaf_flags & H5AC__DIRTIED_FLAG)) { |
557 | | /* Attempt to shadow the node if doing SWMR writes */ |
558 | 0 | if (H5B2__shadow_leaf(leaf, curr_node_ptr) < 0) |
559 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf B-tree node"); |
560 | | |
561 | | /* Change the state to "shadowed" if only modified currently */ |
562 | | /* (Triggers parent to be marked dirty) */ |
563 | 0 | if (*status == H5B2_UPDATE_MODIFY_DONE) |
564 | 0 | *status = H5B2_UPDATE_SHADOW_DONE; |
565 | 0 | } /* end if */ |
566 | | |
567 | | /* Unprotect leaf node */ |
568 | 0 | if (H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, curr_node_ptr->addr, leaf, leaf_flags) < 0) |
569 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node"); |
570 | 0 | } /* end if */ |
571 | |
|
572 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
573 | 0 | } /* H5B2__update_leaf() */ |
574 | | |
575 | | /*------------------------------------------------------------------------- |
576 | | * Function: H5B2__swap_leaf |
577 | | * |
578 | | * Purpose: Swap a record in a node with a record in a leaf node |
579 | | * |
580 | | * Return: Success: Non-negative |
581 | | * |
582 | | * Failure: Negative |
583 | | * |
584 | | *------------------------------------------------------------------------- |
585 | | */ |
586 | | herr_t |
587 | | H5B2__swap_leaf(H5B2_hdr_t *hdr, uint16_t depth, H5B2_internal_t *internal, unsigned *internal_flags_ptr, |
588 | | unsigned idx, void *swap_loc) |
589 | 0 | { |
590 | 0 | const H5AC_class_t *child_class; /* Pointer to child node's class info */ |
591 | 0 | haddr_t child_addr = HADDR_UNDEF; /* Address of child node */ |
592 | 0 | void *child = NULL; /* Pointer to child node */ |
593 | 0 | uint8_t *child_native; /* Pointer to child's native records */ |
594 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
595 | |
|
596 | 0 | FUNC_ENTER_PACKAGE |
597 | | |
598 | | /* Check arguments. */ |
599 | 0 | assert(hdr); |
600 | 0 | assert(internal); |
601 | 0 | assert(internal_flags_ptr); |
602 | 0 | assert(idx <= internal->nrec); |
603 | | |
604 | | /* Check for the kind of B-tree node to swap */ |
605 | 0 | if (depth > 1) { |
606 | 0 | H5B2_internal_t *child_internal; /* Pointer to internal node */ |
607 | | |
608 | | /* Setup information for unlocking child node */ |
609 | 0 | child_class = H5AC_BT2_INT; |
610 | | |
611 | | /* Lock B-tree child nodes */ |
612 | 0 | if (NULL == |
613 | 0 | (child_internal = H5B2__protect_internal(hdr, internal, &internal->node_ptrs[idx], |
614 | 0 | (uint16_t)(depth - 1), false, H5AC__NO_FLAGS_SET))) |
615 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree internal node"); |
616 | 0 | child_addr = internal->node_ptrs[idx].addr; |
617 | | |
618 | | /* More setup for accessing child node information */ |
619 | 0 | child = child_internal; |
620 | 0 | child_native = child_internal->int_native; |
621 | 0 | } /* end if */ |
622 | 0 | else { |
623 | 0 | H5B2_leaf_t *child_leaf; /* Pointer to leaf node */ |
624 | | |
625 | | /* Setup information for unlocking child nodes */ |
626 | 0 | child_class = H5AC_BT2_LEAF; |
627 | | |
628 | | /* Lock B-tree child node */ |
629 | 0 | if (NULL == (child_leaf = H5B2__protect_leaf(hdr, internal, &internal->node_ptrs[idx], false, |
630 | 0 | H5AC__NO_FLAGS_SET))) |
631 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node"); |
632 | 0 | child_addr = internal->node_ptrs[idx].addr; |
633 | | |
634 | | /* More setup for accessing child node information */ |
635 | 0 | child = child_leaf; |
636 | 0 | child_native = child_leaf->leaf_native; |
637 | 0 | } /* end else */ |
638 | | |
639 | | /* Swap records (use disk page as temporary buffer) */ |
640 | 0 | H5MM_memcpy(hdr->page, H5B2_NAT_NREC(child_native, hdr, 0), hdr->cls->nrec_size); |
641 | 0 | H5MM_memcpy(H5B2_NAT_NREC(child_native, hdr, 0), swap_loc, hdr->cls->nrec_size); |
642 | 0 | H5MM_memcpy(swap_loc, hdr->page, hdr->cls->nrec_size); |
643 | | |
644 | | /* Mark parent as dirty */ |
645 | 0 | *internal_flags_ptr |= H5AC__DIRTIED_FLAG; |
646 | |
|
647 | | #ifdef H5B2_DEBUG |
648 | | H5B2__assert_internal((hsize_t)0, hdr, internal); |
649 | | if (depth > 1) |
650 | | H5B2__assert_internal(internal->node_ptrs[idx].all_nrec, hdr, (H5B2_internal_t *)child); |
651 | | else |
652 | | H5B2__assert_leaf(hdr, (H5B2_leaf_t *)child); |
653 | | #endif /* H5B2_DEBUG */ |
654 | |
|
655 | 0 | done: |
656 | | /* Unlock child node */ |
657 | 0 | if (child && H5AC_unprotect(hdr->f, child_class, child_addr, child, H5AC__DIRTIED_FLAG) < 0) |
658 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree child node"); |
659 | |
|
660 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
661 | 0 | } /* end H5B2__swap_leaf() */ |
662 | | |
663 | | /*------------------------------------------------------------------------- |
664 | | * Function: H5B2__shadow_leaf |
665 | | * |
666 | | * Purpose: "Shadow" a leaf node - copy it to a new location, leaving |
667 | | * the data in the old location intact (for now). This is |
668 | | * done when writing in SWMR mode to ensure that readers do |
669 | | * not see nodes that are out of date with respect to each |
670 | | * other and thereby inconsistent. |
671 | | * |
672 | | * Return: Non-negative on success/Negative on failure |
673 | | * |
674 | | *------------------------------------------------------------------------- |
675 | | */ |
676 | | static herr_t |
677 | | H5B2__shadow_leaf(H5B2_leaf_t *leaf, H5B2_node_ptr_t *curr_node_ptr) |
678 | 0 | { |
679 | 0 | H5B2_hdr_t *hdr; /* B-tree header */ |
680 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
681 | |
|
682 | 0 | FUNC_ENTER_PACKAGE |
683 | | |
684 | | /* |
685 | | * Check arguments. |
686 | | */ |
687 | 0 | assert(leaf); |
688 | 0 | assert(curr_node_ptr); |
689 | 0 | assert(H5_addr_defined(curr_node_ptr->addr)); |
690 | 0 | hdr = leaf->hdr; |
691 | 0 | assert(hdr); |
692 | 0 | assert(hdr->swmr_write); |
693 | | |
694 | | /* We only need to shadow the node if it has not been shadowed since the |
695 | | * last time the header was flushed, as otherwise it will be unreachable by |
696 | | * the readers so there will be no need to shadow. To check if it has been |
697 | | * shadowed, compare the epoch of this node and the header. If this node's |
698 | | * epoch is <= to the header's, it hasn't been shadowed yet. */ |
699 | 0 | if (leaf->shadow_epoch <= hdr->shadow_epoch) { |
700 | 0 | haddr_t new_node_addr; /* Address to move node to */ |
701 | | |
702 | | /* |
703 | | * We must clone the old node so readers with an out-of-date version of |
704 | | * the parent can still see the correct number of children, via the |
705 | | * shadowed node. Remove it from cache but do not mark it free on disk. |
706 | | */ |
707 | | /* Allocate space for the cloned node */ |
708 | 0 | if (HADDR_UNDEF == (new_node_addr = H5MF_alloc(hdr->f, H5FD_MEM_BTREE, (hsize_t)hdr->node_size))) |
709 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "unable to allocate file space to move B-tree node"); |
710 | | |
711 | | /* Move the location of the old child on the disk */ |
712 | 0 | if (H5AC_move_entry(hdr->f, H5AC_BT2_LEAF, curr_node_ptr->addr, new_node_addr) < 0) |
713 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTMOVE, FAIL, "unable to move B-tree node"); |
714 | 0 | curr_node_ptr->addr = new_node_addr; |
715 | | |
716 | | /* Should free the space in the file, but this is not supported by |
717 | | * SWMR_WRITE code yet - QAK, 2016/12/01 |
718 | | */ |
719 | | |
720 | | /* Set shadow epoch for node ahead of header */ |
721 | 0 | leaf->shadow_epoch = hdr->shadow_epoch + 1; |
722 | 0 | } /* end if */ |
723 | | |
724 | 0 | done: |
725 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
726 | 0 | } /* end H5B2__shadow_leaf() */ |
727 | | |
728 | | /*------------------------------------------------------------------------- |
729 | | * Function: H5B2__remove_leaf |
730 | | * |
731 | | * Purpose: Removes a record from a B-tree leaf node. |
732 | | * |
733 | | * Return: Non-negative on success/Negative on failure |
734 | | * |
735 | | *------------------------------------------------------------------------- |
736 | | */ |
737 | | herr_t |
738 | | H5B2__remove_leaf(H5B2_hdr_t *hdr, H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, void *parent, |
739 | | void *udata, H5B2_remove_t op, void *op_data) |
740 | 0 | { |
741 | 0 | H5B2_leaf_t *leaf; /* Pointer to leaf node */ |
742 | 0 | haddr_t leaf_addr = HADDR_UNDEF; /* Leaf address on disk */ |
743 | 0 | unsigned leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting leaf node */ |
744 | 0 | unsigned idx = 0; /* Location of record which matches key */ |
745 | 0 | int cmp; /* Comparison value of records */ |
746 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
747 | |
|
748 | 0 | FUNC_ENTER_PACKAGE |
749 | | |
750 | | /* Check arguments. */ |
751 | 0 | assert(hdr); |
752 | 0 | assert(curr_node_ptr); |
753 | 0 | assert(H5_addr_defined(curr_node_ptr->addr)); |
754 | | |
755 | | /* Lock current B-tree node */ |
756 | 0 | if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, curr_node_ptr, false, H5AC__NO_FLAGS_SET))) |
757 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node"); |
758 | 0 | leaf_addr = curr_node_ptr->addr; |
759 | | |
760 | | /* Sanity check number of records */ |
761 | 0 | assert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec); |
762 | 0 | assert(leaf->nrec == curr_node_ptr->node_nrec); |
763 | | |
764 | | /* Find correct location to remove this record */ |
765 | 0 | if (H5B2__locate_record(hdr->cls, leaf->nrec, hdr->nat_off, leaf->leaf_native, udata, &idx, &cmp) < 0) |
766 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records"); |
767 | 0 | if (cmp != 0) |
768 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "record is not in B-tree"); |
769 | | |
770 | | /* Check for invalidating the min/max record for the tree */ |
771 | 0 | if (H5B2_POS_MIDDLE != curr_pos) { |
772 | | /* (Don't use 'else' for the idx check, to allow for root leaf node) */ |
773 | 0 | if (idx == 0) { |
774 | 0 | if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) { |
775 | 0 | if (hdr->min_native_rec) |
776 | 0 | hdr->min_native_rec = H5MM_xfree(hdr->min_native_rec); |
777 | 0 | } /* end if */ |
778 | 0 | } /* end if */ |
779 | 0 | if (idx == (unsigned)(leaf->nrec - 1)) { |
780 | 0 | if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) { |
781 | 0 | if (hdr->max_native_rec) |
782 | 0 | hdr->max_native_rec = H5MM_xfree(hdr->max_native_rec); |
783 | 0 | } /* end if */ |
784 | 0 | } /* end if */ |
785 | 0 | } /* end if */ |
786 | | |
787 | | /* Make 'remove' callback if there is one */ |
788 | 0 | if (op) |
789 | 0 | if ((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data) < 0) |
790 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record into leaf node"); |
791 | | |
792 | | /* Update number of records in node */ |
793 | 0 | leaf->nrec--; |
794 | |
|
795 | 0 | if (leaf->nrec > 0) { |
796 | | /* Shadow the node if doing SWMR writes */ |
797 | 0 | if (hdr->swmr_write) { |
798 | 0 | if (H5B2__shadow_leaf(leaf, curr_node_ptr) < 0) |
799 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf node"); |
800 | 0 | leaf_addr = curr_node_ptr->addr; |
801 | 0 | } /* end if */ |
802 | | |
803 | | /* Pack record out of leaf */ |
804 | 0 | if (idx < leaf->nrec) |
805 | 0 | memmove(H5B2_LEAF_NREC(leaf, hdr, idx), H5B2_LEAF_NREC(leaf, hdr, (idx + 1)), |
806 | 0 | hdr->cls->nrec_size * (leaf->nrec - idx)); |
807 | | |
808 | | /* Mark leaf node as dirty also */ |
809 | 0 | leaf_flags |= H5AC__DIRTIED_FLAG; |
810 | 0 | } /* end if */ |
811 | 0 | else { |
812 | | /* Let the cache know that the object is deleted */ |
813 | 0 | leaf_flags |= H5AC__DELETED_FLAG; |
814 | 0 | if (!hdr->swmr_write) |
815 | 0 | leaf_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; |
816 | | |
817 | | /* Reset address of parent node pointer */ |
818 | 0 | curr_node_ptr->addr = HADDR_UNDEF; |
819 | 0 | } /* end else */ |
820 | | |
821 | | /* Update record count for parent of leaf node */ |
822 | 0 | curr_node_ptr->node_nrec--; |
823 | |
|
824 | 0 | done: |
825 | | /* Release the B-tree leaf node */ |
826 | 0 | if (leaf && H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, leaf_addr, leaf, leaf_flags) < 0) |
827 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node"); |
828 | |
|
829 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
830 | 0 | } /* H5B2__remove_leaf() */ |
831 | | |
832 | | /*------------------------------------------------------------------------- |
833 | | * Function: H5B2__remove_leaf_by_idx |
834 | | * |
835 | | * Purpose: Removes a record from a B-tree leaf node, according to the |
836 | | * offset in the B-tree records. |
837 | | * |
838 | | * Return: Non-negative on success/Negative on failure |
839 | | * |
840 | | *------------------------------------------------------------------------- |
841 | | */ |
842 | | herr_t |
843 | | H5B2__remove_leaf_by_idx(H5B2_hdr_t *hdr, H5B2_node_ptr_t *curr_node_ptr, H5B2_nodepos_t curr_pos, |
844 | | void *parent, unsigned idx, H5B2_remove_t op, void *op_data) |
845 | 0 | { |
846 | 0 | H5B2_leaf_t *leaf; /* Pointer to leaf node */ |
847 | 0 | haddr_t leaf_addr = HADDR_UNDEF; /* Leaf address on disk */ |
848 | 0 | unsigned leaf_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting leaf node */ |
849 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
850 | |
|
851 | 0 | FUNC_ENTER_PACKAGE |
852 | | |
853 | | /* Check arguments. */ |
854 | 0 | assert(hdr); |
855 | 0 | assert(curr_node_ptr); |
856 | 0 | assert(H5_addr_defined(curr_node_ptr->addr)); |
857 | | |
858 | | /* Lock B-tree leaf node */ |
859 | 0 | if (NULL == (leaf = H5B2__protect_leaf(hdr, parent, curr_node_ptr, false, H5AC__NO_FLAGS_SET))) |
860 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree leaf node"); |
861 | 0 | leaf_addr = curr_node_ptr->addr; |
862 | | |
863 | | /* Sanity check number of records */ |
864 | 0 | assert(curr_node_ptr->all_nrec == curr_node_ptr->node_nrec); |
865 | 0 | assert(leaf->nrec == curr_node_ptr->node_nrec); |
866 | 0 | assert(idx < leaf->nrec); |
867 | | |
868 | | /* Check for invalidating the min/max record for the tree */ |
869 | 0 | if (H5B2_POS_MIDDLE != curr_pos) { |
870 | | /* (Don't use 'else' for the idx check, to allow for root leaf node) */ |
871 | 0 | if (idx == 0) { |
872 | 0 | if (H5B2_POS_LEFT == curr_pos || H5B2_POS_ROOT == curr_pos) { |
873 | 0 | if (hdr->min_native_rec) |
874 | 0 | hdr->min_native_rec = H5MM_xfree(hdr->min_native_rec); |
875 | 0 | } /* end if */ |
876 | 0 | } /* end if */ |
877 | 0 | if (idx == (unsigned)(leaf->nrec - 1)) { |
878 | 0 | if (H5B2_POS_RIGHT == curr_pos || H5B2_POS_ROOT == curr_pos) { |
879 | 0 | if (hdr->max_native_rec) |
880 | 0 | hdr->max_native_rec = H5MM_xfree(hdr->max_native_rec); |
881 | 0 | } /* end if */ |
882 | 0 | } /* end if */ |
883 | 0 | } /* end if */ |
884 | | |
885 | | /* Make 'remove' callback if there is one */ |
886 | 0 | if (op) |
887 | 0 | if ((op)(H5B2_LEAF_NREC(leaf, hdr, idx), op_data) < 0) |
888 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to remove record into leaf node"); |
889 | | |
890 | | /* Update number of records in node */ |
891 | 0 | leaf->nrec--; |
892 | |
|
893 | 0 | if (leaf->nrec > 0) { |
894 | | /* Shadow the node if doing SWMR writes */ |
895 | 0 | if (hdr->swmr_write) { |
896 | 0 | if (H5B2__shadow_leaf(leaf, curr_node_ptr) < 0) |
897 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTCOPY, FAIL, "unable to shadow leaf node"); |
898 | 0 | leaf_addr = curr_node_ptr->addr; |
899 | 0 | } /* end if */ |
900 | | |
901 | | /* Pack record out of leaf */ |
902 | 0 | if (idx < leaf->nrec) |
903 | 0 | memmove(H5B2_LEAF_NREC(leaf, hdr, idx), H5B2_LEAF_NREC(leaf, hdr, (idx + 1)), |
904 | 0 | hdr->cls->nrec_size * (leaf->nrec - idx)); |
905 | | |
906 | | /* Mark leaf node as dirty also */ |
907 | 0 | leaf_flags |= H5AC__DIRTIED_FLAG; |
908 | 0 | } /* end if */ |
909 | 0 | else { |
910 | | /* Let the cache know that the object is deleted */ |
911 | 0 | leaf_flags |= H5AC__DELETED_FLAG; |
912 | 0 | if (!hdr->swmr_write) |
913 | 0 | leaf_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; |
914 | | |
915 | | /* Reset address of parent node pointer */ |
916 | 0 | curr_node_ptr->addr = HADDR_UNDEF; |
917 | 0 | } /* end else */ |
918 | | |
919 | | /* Update record count for parent of leaf node */ |
920 | 0 | curr_node_ptr->node_nrec--; |
921 | |
|
922 | 0 | done: |
923 | | /* Release the B-tree leaf node */ |
924 | 0 | if (leaf && H5AC_unprotect(hdr->f, H5AC_BT2_LEAF, leaf_addr, leaf, leaf_flags) < 0) |
925 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release leaf B-tree node"); |
926 | |
|
927 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
928 | 0 | } /* H5B2__remove_leaf_by_idx() */ |
929 | | |
930 | | /*------------------------------------------------------------------------- |
931 | | * Function: H5B2__leaf_free |
932 | | * |
933 | | * Purpose: Destroys a B-tree leaf node in memory. |
934 | | * |
935 | | * Return: Non-negative on success/Negative on failure |
936 | | * |
937 | | *------------------------------------------------------------------------- |
938 | | */ |
939 | | herr_t |
940 | | H5B2__leaf_free(H5B2_leaf_t *leaf) |
941 | 0 | { |
942 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
943 | |
|
944 | 0 | FUNC_ENTER_PACKAGE |
945 | | |
946 | | /* |
947 | | * Check arguments. |
948 | | */ |
949 | 0 | assert(leaf); |
950 | | |
951 | | /* Release leaf's native key buffer */ |
952 | 0 | if (leaf->leaf_native) |
953 | 0 | leaf->leaf_native = (uint8_t *)H5FL_FAC_FREE(leaf->hdr->node_info[0].nat_rec_fac, leaf->leaf_native); |
954 | | |
955 | | /* Decrement ref. count on B-tree header */ |
956 | 0 | if (H5B2__hdr_decr(leaf->hdr) < 0) |
957 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTDEC, FAIL, "can't decrement ref. count on B-tree header"); |
958 | | |
959 | | /* Sanity check */ |
960 | 0 | assert(NULL == leaf->top_proxy); |
961 | | |
962 | | /* Free B-tree leaf node info */ |
963 | 0 | leaf = H5FL_FREE(H5B2_leaf_t, leaf); |
964 | |
|
965 | 0 | done: |
966 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
967 | 0 | } /* end H5B2__leaf_free() */ |
968 | | |
969 | | #ifdef H5B2_DEBUG |
970 | | |
971 | | /*------------------------------------------------------------------------- |
972 | | * Function: H5B2__assert_leaf |
973 | | * |
974 | | * Purpose: Verify than a leaf node is mostly sane |
975 | | * |
976 | | * Return: Non-negative on success, negative on failure |
977 | | * |
978 | | *------------------------------------------------------------------------- |
979 | | */ |
980 | | H5_ATTR_PURE herr_t |
981 | | H5B2__assert_leaf(const H5B2_hdr_t H5_ATTR_NDEBUG_UNUSED *hdr, const H5B2_leaf_t H5_ATTR_NDEBUG_UNUSED *leaf) |
982 | | { |
983 | | /* General sanity checking on node */ |
984 | | assert(leaf->nrec <= hdr->node_info->split_nrec); |
985 | | |
986 | | return (0); |
987 | | } /* end H5B2__assert_leaf() */ |
988 | | |
989 | | /*------------------------------------------------------------------------- |
990 | | * Function: H5B2__assert_leaf2 |
991 | | * |
992 | | * Purpose: Verify than a leaf node is mostly sane |
993 | | * |
994 | | * Return: Non-negative on success, negative on failure |
995 | | * |
996 | | *------------------------------------------------------------------------- |
997 | | */ |
998 | | H5_ATTR_PURE herr_t |
999 | | H5B2__assert_leaf2(const H5B2_hdr_t H5_ATTR_NDEBUG_UNUSED *hdr, const H5B2_leaf_t H5_ATTR_NDEBUG_UNUSED *leaf, |
1000 | | const H5B2_leaf_t H5_ATTR_UNUSED *leaf2) |
1001 | | { |
1002 | | /* General sanity checking on node */ |
1003 | | assert(leaf->nrec <= hdr->node_info->split_nrec); |
1004 | | |
1005 | | return (0); |
1006 | | } /* end H5B2__assert_leaf2() */ |
1007 | | #endif /* H5B2_DEBUG */ |