1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://www.hdfgroup.org/licenses.               *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /*-------------------------------------------------------------------------
15  *
16  * Created:		H5B2int.c
17  *			Feb 27 2006
18  *			Quincey Koziol
19  *
20  * Purpose:		Internal routines for managing v2 B-trees.
21  *
22  *-------------------------------------------------------------------------
23  */
24 
25 /****************/
26 /* Module Setup */
27 /****************/
28 
29 #include "H5B2module.h" /* This source code file is part of the H5B2 module */
30 
31 /***********/
32 /* Headers */
33 /***********/
34 #include "H5private.h"   /* Generic Functions			*/
35 #include "H5B2pkg.h"     /* v2 B-trees				*/
36 #include "H5Eprivate.h"  /* Error handling		  	*/
37 #include "H5MFprivate.h" /* File memory management		*/
38 #include "H5MMprivate.h" /* Memory management			*/
39 #include "H5VMprivate.h" /* Vectors and arrays 			*/
40 
41 /****************/
42 /* Local Macros */
43 /****************/
44 
45 /* Number of records that fit into leaf node */
46 #define H5B2_NUM_LEAF_REC(n, r) (((n)-H5B2_LEAF_PREFIX_SIZE) / (r))
47 
48 /* Uncomment this macro to enable extra sanity checking */
49 /* #define H5B2_DEBUG */
50 
51 /******************/
52 /* Local Typedefs */
53 /******************/
54 
55 /********************/
56 /* Package Typedefs */
57 /********************/
58 
59 /********************/
60 /* Local Prototypes */
61 /********************/
62 
63 /*********************/
64 /* Package Variables */
65 /*********************/
66 
67 /*****************************/
68 /* Library Private Variables */
69 /*****************************/
70 
71 /*******************/
72 /* Local Variables */
73 /*******************/
74 
75 /* Declare a free list to manage the H5B2_hdr_t struct */
76 H5FL_DEFINE_STATIC(H5B2_hdr_t);
77 
78 /* Declare a free list to manage B-tree node pages to/from disk */
79 H5FL_BLK_DEFINE_STATIC(node_page);
80 
81 /* Declare a free list to manage the 'size_t' sequence information */
82 H5FL_SEQ_DEFINE_STATIC(size_t);
83 
84 /* Declare a free list to manage the 'H5B2_node_info_t' sequence information */
85 H5FL_SEQ_DEFINE(H5B2_node_info_t);
86 
87 /*-------------------------------------------------------------------------
88  * Function:	H5B2__hdr_init
89  *
90  * Purpose:	Allocate & initialize B-tree header info
91  *
92  * Return:	Non-negative on success/Negative on failure
93  *
94  * Programmer:	Quincey Koziol
95  *		Feb  2 2005
96  *
97  *-------------------------------------------------------------------------
98  */
99 herr_t
H5B2__hdr_init(H5B2_hdr_t * hdr,const H5B2_create_t * cparam,void * ctx_udata,uint16_t depth)100 H5B2__hdr_init(H5B2_hdr_t *hdr, const H5B2_create_t *cparam, void *ctx_udata, uint16_t depth)
101 {
102     size_t   sz_max_nrec;         /* Temporary variable for range checking */
103     unsigned u_max_nrec_size;     /* Temporary variable for range checking */
104     unsigned u;                   /* Local index variable */
105     herr_t   ret_value = SUCCEED; /* Return value */
106 
107     FUNC_ENTER_PACKAGE
108 
109     /*
110      * Check arguments.
111      */
112     HDassert(hdr);
113     HDassert(cparam);
114     HDassert(cparam->cls);
115     HDassert((cparam->cls->crt_context && cparam->cls->dst_context) ||
116              (NULL == cparam->cls->crt_context && NULL == cparam->cls->dst_context));
117     HDassert(cparam->node_size > 0);
118     HDassert(cparam->rrec_size > 0);
119     HDassert(cparam->merge_percent > 0 && cparam->merge_percent <= 100);
120     HDassert(cparam->split_percent > 0 && cparam->split_percent <= 100);
121     HDassert(cparam->merge_percent < (cparam->split_percent / 2));
122 
123     /* Assign dynamic information */
124     hdr->depth = depth;
125 
126     /* Assign user's information */
127     hdr->split_percent = cparam->split_percent;
128     hdr->merge_percent = cparam->merge_percent;
129     hdr->node_size     = cparam->node_size;
130     hdr->rrec_size     = cparam->rrec_size;
131 
132     /* Assign common type information */
133     hdr->cls = cparam->cls;
134 
135     /* Allocate "page" for node I/O */
136     if (NULL == (hdr->page = H5FL_BLK_MALLOC(node_page, hdr->node_size)))
137         HGOTO_ERROR(H5E_BTREE, H5E_NOSPACE, FAIL, "memory allocation failed")
138     HDmemset(hdr->page, 0, hdr->node_size);
139 
140     /* Allocate array of node info structs */
141     if (NULL == (hdr->node_info = H5FL_SEQ_MALLOC(H5B2_node_info_t, (size_t)(hdr->depth + 1))))
142         HGOTO_ERROR(H5E_BTREE, H5E_NOSPACE, FAIL, "memory allocation failed")
143 
144     /* Initialize leaf node info */
145     sz_max_nrec = H5B2_NUM_LEAF_REC(hdr->node_size, hdr->rrec_size);
146     H5_CHECKED_ASSIGN(hdr->node_info[0].max_nrec, unsigned, sz_max_nrec, size_t)
147     hdr->node_info[0].split_nrec        = (hdr->node_info[0].max_nrec * hdr->split_percent) / 100;
148     hdr->node_info[0].merge_nrec        = (hdr->node_info[0].max_nrec * hdr->merge_percent) / 100;
149     hdr->node_info[0].cum_max_nrec      = hdr->node_info[0].max_nrec;
150     hdr->node_info[0].cum_max_nrec_size = 0;
151     if (NULL ==
152         (hdr->node_info[0].nat_rec_fac = H5FL_fac_init(hdr->cls->nrec_size * hdr->node_info[0].max_nrec)))
153         HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't create node native key block factory")
154     hdr->node_info[0].node_ptr_fac = NULL;
155 
156     /* Allocate array of pointers to internal node native keys */
157     /* (uses leaf # of records because its the largest) */
158     if (NULL == (hdr->nat_off = H5FL_SEQ_MALLOC(size_t, (size_t)hdr->node_info[0].max_nrec)))
159         HGOTO_ERROR(H5E_BTREE, H5E_NOSPACE, FAIL, "memory allocation failed")
160 
161     /* Initialize offsets in native key block */
162     /* (uses leaf # of records because its the largest) */
163     for (u = 0; u < hdr->node_info[0].max_nrec; u++)
164         hdr->nat_off[u] = hdr->cls->nrec_size * u;
165 
166     /* Compute size to store # of records in each node */
167     /* (uses leaf # of records because its the largest) */
168     u_max_nrec_size = H5VM_limit_enc_size((uint64_t)hdr->node_info[0].max_nrec);
169     H5_CHECKED_ASSIGN(hdr->max_nrec_size, uint8_t, u_max_nrec_size, unsigned)
170     HDassert(hdr->max_nrec_size <= H5B2_SIZEOF_RECORDS_PER_NODE);
171 
172     /* Initialize internal node info */
173     if (depth > 0) {
174         for (u = 1; u < (unsigned)(depth + 1); u++) {
175             sz_max_nrec = H5B2_NUM_INT_REC(hdr, u);
176             H5_CHECKED_ASSIGN(hdr->node_info[u].max_nrec, unsigned, sz_max_nrec, size_t)
177             HDassert(hdr->node_info[u].max_nrec <= hdr->node_info[u - 1].max_nrec);
178 
179             hdr->node_info[u].split_nrec = (hdr->node_info[u].max_nrec * hdr->split_percent) / 100;
180             hdr->node_info[u].merge_nrec = (hdr->node_info[u].max_nrec * hdr->merge_percent) / 100;
181 
182             hdr->node_info[u].cum_max_nrec =
183                 ((hdr->node_info[u].max_nrec + 1) * hdr->node_info[u - 1].cum_max_nrec) +
184                 hdr->node_info[u].max_nrec;
185             u_max_nrec_size = H5VM_limit_enc_size((uint64_t)hdr->node_info[u].cum_max_nrec);
186             H5_CHECKED_ASSIGN(hdr->node_info[u].cum_max_nrec_size, uint8_t, u_max_nrec_size, unsigned)
187 
188             if (NULL == (hdr->node_info[u].nat_rec_fac =
189                              H5FL_fac_init(hdr->cls->nrec_size * hdr->node_info[u].max_nrec)))
190                 HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't create node native key block factory")
191             if (NULL == (hdr->node_info[u].node_ptr_fac =
192                              H5FL_fac_init(sizeof(H5B2_node_ptr_t) * (hdr->node_info[u].max_nrec + 1))))
193                 HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL,
194                             "can't create internal 'branch' node node pointer block factory")
195         } /* end for */
196     }     /* end if */
197 
198     /* Determine if we are doing SWMR writes.  Only enable for data chunks for now. */
199     hdr->swmr_write = (H5F_INTENT(hdr->f) & H5F_ACC_SWMR_WRITE) > 0 &&
200                       (hdr->cls->id == H5B2_CDSET_ID || hdr->cls->id == H5B2_CDSET_FILT_ID);
201 
202     /* Reset the shadow epoch */
203     hdr->shadow_epoch = 0;
204 
205     /* Create the callback context, if the callback exists */
206     if (hdr->cls->crt_context)
207         if (NULL == (hdr->cb_ctx = (*hdr->cls->crt_context)(ctx_udata)))
208             HGOTO_ERROR(H5E_BTREE, H5E_CANTCREATE, FAIL, "unable to create v2 B-tree client callback context")
209 
210 done:
211     if (ret_value < 0)
212         if (H5B2__hdr_free(hdr) < 0)
213             HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to free shared v2 B-tree info")
214 
215     FUNC_LEAVE_NOAPI(ret_value)
216 } /* end H5B2__hdr_init() */
217 
218 /*-------------------------------------------------------------------------
219  * Function:	H5B2__hdr_alloc
220  *
221  * Purpose:	Allocate B-tree header
222  *
223  * Return:	Non-negative on success/Negative on failure
224  *
225  * Programmer:	Quincey Koziol
226  *		Oct 27 2009
227  *
228  *-------------------------------------------------------------------------
229  */
230 H5B2_hdr_t *
H5B2__hdr_alloc(H5F_t * f)231 H5B2__hdr_alloc(H5F_t *f)
232 {
233     H5B2_hdr_t *hdr       = NULL; /* v2 B-tree header */
234     H5B2_hdr_t *ret_value = NULL; /* Return value */
235 
236     FUNC_ENTER_PACKAGE
237 
238     /*
239      * Check arguments.
240      */
241     HDassert(f);
242 
243     /* Allocate space for the shared information */
244     if (NULL == (hdr = H5FL_CALLOC(H5B2_hdr_t)))
245         HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, NULL, "memory allocation failed for B-tree header")
246 
247     /* Assign non-zero information */
248     hdr->f           = f;
249     hdr->sizeof_addr = H5F_SIZEOF_ADDR(f);
250     hdr->sizeof_size = H5F_SIZEOF_SIZE(f);
251     hdr->hdr_size    = H5B2_HEADER_SIZE_HDR(hdr);
252     hdr->root.addr   = HADDR_UNDEF;
253 
254     /* Set return value */
255     ret_value = hdr;
256 
257 done:
258 
259     FUNC_LEAVE_NOAPI(ret_value)
260 } /* end H5B2__hdr_alloc() */
261 
262 /*-------------------------------------------------------------------------
263  * Function:	H5B2__hdr_create
264  *
265  * Purpose:	Create new fractal heap header
266  *
267  * Return:	Non-negative on success/Negative on failure
268  *
269  * Programmer:	Quincey Koziol
270  *		Mar 21 2006
271  *
272  *-------------------------------------------------------------------------
273  */
274 haddr_t
H5B2__hdr_create(H5F_t * f,const H5B2_create_t * cparam,void * ctx_udata)275 H5B2__hdr_create(H5F_t *f, const H5B2_create_t *cparam, void *ctx_udata)
276 {
277     H5B2_hdr_t *hdr       = NULL;        /* The new v2 B-tree header information */
278     hbool_t     inserted  = FALSE;       /* Whether the header was inserted into cache */
279     haddr_t     ret_value = HADDR_UNDEF; /* Return value */
280 
281     FUNC_ENTER_PACKAGE
282 
283     /*
284      * Check arguments.
285      */
286     HDassert(f);
287     HDassert(cparam);
288 
289     /* Allocate v2 B-tree header */
290     if (NULL == (hdr = H5B2__hdr_alloc(f)))
291         HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed for B-tree header")
292 
293     /* Initialize shared B-tree info */
294     if (H5B2__hdr_init(hdr, cparam, ctx_udata, (uint16_t)0) < 0)
295         HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, HADDR_UNDEF, "can't create shared B-tree info")
296 
297     /* Allocate space for the header on disk */
298     if (HADDR_UNDEF == (hdr->addr = H5MF_alloc(f, H5FD_MEM_BTREE, (hsize_t)hdr->hdr_size)))
299         HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, HADDR_UNDEF, "file allocation failed for B-tree header")
300 
301     /* Create 'top' proxy for extensible array entries */
302     if (hdr->swmr_write)
303         if (NULL == (hdr->top_proxy = H5AC_proxy_entry_create()))
304             HGOTO_ERROR(H5E_BTREE, H5E_CANTCREATE, HADDR_UNDEF, "can't create v2 B-tree proxy")
305 
306     /* Cache the new B-tree node */
307     if (H5AC_insert_entry(f, H5AC_BT2_HDR, hdr->addr, hdr, H5AC__NO_FLAGS_SET) < 0)
308         HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, HADDR_UNDEF, "can't add B-tree header to cache")
309     inserted = TRUE;
310 
311     /* Add header as child of 'top' proxy */
312     if (hdr->top_proxy)
313         if (H5AC_proxy_entry_add_child(hdr->top_proxy, f, hdr) < 0)
314             HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, HADDR_UNDEF,
315                         "unable to add v2 B-tree header as child of array proxy")
316 
317     /* Set address of v2 B-tree header to return */
318     ret_value = hdr->addr;
319 
320 done:
321     if (!H5F_addr_defined(ret_value))
322         if (hdr) {
323             /* Remove from cache, if inserted */
324             if (inserted)
325                 if (H5AC_remove_entry(hdr) < 0)
326                     HDONE_ERROR(H5E_BTREE, H5E_CANTREMOVE, HADDR_UNDEF,
327                                 "unable to remove v2 B-tree header from cache")
328 
329             /* Release header's disk space */
330             if (H5F_addr_defined(hdr->addr) &&
331                 H5MF_xfree(f, H5FD_MEM_BTREE, hdr->addr, (hsize_t)hdr->hdr_size) < 0)
332                 HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, HADDR_UNDEF, "unable to free v2 B-tree header")
333 
334             /* Destroy header */
335             if (H5B2__hdr_free(hdr) < 0)
336                 HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, HADDR_UNDEF, "unable to release v2 B-tree header")
337         } /* end if */
338 
339     FUNC_LEAVE_NOAPI(ret_value)
340 } /* end H5B2__hdr_create() */
341 
342 /*-------------------------------------------------------------------------
343  * Function:	H5B2__hdr_incr
344  *
345  * Purpose:	Increment reference count on B-tree header
346  *
347  * Return:	Non-negative on success/Negative on failure
348  *
349  * Programmer:	Quincey Koziol
350  *		Oct 13 2009
351  *
352  *-------------------------------------------------------------------------
353  */
354 herr_t
H5B2__hdr_incr(H5B2_hdr_t * hdr)355 H5B2__hdr_incr(H5B2_hdr_t *hdr)
356 {
357     herr_t ret_value = SUCCEED; /* Return value */
358 
359     FUNC_ENTER_PACKAGE
360 
361     /* Sanity checks */
362     HDassert(hdr);
363 
364     /* Mark header as un-evictable when a B-tree node is depending on it */
365     if (hdr->rc == 0)
366         if (H5AC_pin_protected_entry(hdr) < 0)
367             HGOTO_ERROR(H5E_BTREE, H5E_CANTPIN, FAIL, "unable to pin v2 B-tree header")
368 
369     /* Increment reference count on B-tree header */
370     hdr->rc++;
371 
372 done:
373     FUNC_LEAVE_NOAPI(ret_value)
374 } /* end H5B2__hdr_incr() */
375 
376 /*-------------------------------------------------------------------------
377  * Function:	H5B2__hdr_decr
378  *
379  * Purpose:	Decrement reference count on B-tree header
380  *
381  * Return:	Non-negative on success/Negative on failure
382  *
383  * Programmer:	Quincey Koziol
384  *		Oct 13 2009
385  *
386  *-------------------------------------------------------------------------
387  */
388 herr_t
H5B2__hdr_decr(H5B2_hdr_t * hdr)389 H5B2__hdr_decr(H5B2_hdr_t *hdr)
390 {
391     herr_t ret_value = SUCCEED; /* Return value */
392 
393     FUNC_ENTER_PACKAGE
394 
395     /* Sanity check */
396     HDassert(hdr);
397     HDassert(hdr->rc > 0);
398 
399     /* Decrement reference count on B-tree header */
400     hdr->rc--;
401 
402     /* Mark header as evictable again when no nodes depend on it */
403     if (hdr->rc == 0)
404         if (H5AC_unpin_entry(hdr) < 0)
405             HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPIN, FAIL, "unable to unpin v2 B-tree header")
406 
407 done:
408     FUNC_LEAVE_NOAPI(ret_value)
409 } /* end H5B2__hdr_decr() */
410 
411 /*-------------------------------------------------------------------------
412  * Function:	H5B2__hdr_fuse_incr
413  *
414  * Purpose:     Increment file reference count on shared v2 B-tree header
415  *
416  * Return:      SUCCEED (Can't fail)
417  *
418  * Programmer:  Quincey Koziol
419  *              Oct 27 2009
420  *
421  *-------------------------------------------------------------------------
422  */
423 herr_t
H5B2__hdr_fuse_incr(H5B2_hdr_t * hdr)424 H5B2__hdr_fuse_incr(H5B2_hdr_t *hdr)
425 {
426     FUNC_ENTER_NOAPI_NOINIT_NOERR
427 
428     /* Sanity check */
429     HDassert(hdr);
430 
431     /* Increment file reference count on shared header */
432     hdr->file_rc++;
433 
434     FUNC_LEAVE_NOAPI(SUCCEED)
435 } /* end H5B2__hdr_fuse_incr() */
436 
437 /*-------------------------------------------------------------------------
438  * Function:	H5B2__hdr_fuse_decr
439  *
440  * Purpose:     Decrement file reference count on shared v2 B-tree header
441  *
442  * Return:      The file's reference count after the decrement. (Can't fail)
443  *
444  * Programmer:  Quincey Koziol
445  *              Oct 27 2009
446  *
447  *-------------------------------------------------------------------------
448  */
449 size_t
H5B2__hdr_fuse_decr(H5B2_hdr_t * hdr)450 H5B2__hdr_fuse_decr(H5B2_hdr_t *hdr)
451 {
452     FUNC_ENTER_NOAPI_NOINIT_NOERR
453 
454     /* Sanity check */
455     HDassert(hdr);
456     HDassert(hdr->file_rc);
457 
458     /* Decrement file reference count on shared header */
459     hdr->file_rc--;
460 
461     FUNC_LEAVE_NOAPI(hdr->file_rc)
462 } /* end H5B2__hdr_fuse_decr() */
463 
464 /*-------------------------------------------------------------------------
465  * Function:	H5B2__hdr_dirty
466  *
467  * Purpose:	Mark B-tree header as dirty
468  *
469  * Return:	Non-negative on success/Negative on failure
470  *
471  * Programmer:	Quincey Koziol
472  *		Oct 13 2009
473  *
474  *-------------------------------------------------------------------------
475  */
476 herr_t
H5B2__hdr_dirty(H5B2_hdr_t * hdr)477 H5B2__hdr_dirty(H5B2_hdr_t *hdr)
478 {
479     herr_t ret_value = SUCCEED; /* Return value */
480 
481     FUNC_ENTER_PACKAGE
482 
483     /* Sanity check */
484     HDassert(hdr);
485 
486     /* Mark B-tree header as dirty in cache */
487     if (H5AC_mark_entry_dirty(hdr) < 0)
488         HGOTO_ERROR(H5E_BTREE, H5E_CANTMARKDIRTY, FAIL, "unable to mark v2 B-tree header as dirty")
489 
490 done:
491     FUNC_LEAVE_NOAPI(ret_value)
492 } /* end H5B2__hdr_dirty() */
493 
494 /*-------------------------------------------------------------------------
495  * Function:	H5B2__hdr_protect
496  *
497  * Purpose:	Convenience wrapper around protecting v2 B-tree header
498  *
499  * Return:	Non-NULL pointer to header on success/NULL on failure
500  *
501  * Programmer:	Quincey Koziol
502  *		Dec 18 2015
503  *
504  *-------------------------------------------------------------------------
505  */
506 H5B2_hdr_t *
H5B2__hdr_protect(H5F_t * f,haddr_t hdr_addr,void * ctx_udata,unsigned flags)507 H5B2__hdr_protect(H5F_t *f, haddr_t hdr_addr, void *ctx_udata, unsigned flags)
508 {
509     H5B2_hdr_cache_ud_t udata;            /* User data for cache callbacks */
510     H5B2_hdr_t *        hdr       = NULL; /* v2 B-tree header */
511     H5B2_hdr_t *        ret_value = NULL; /* Return value */
512 
513     FUNC_ENTER_PACKAGE
514 
515     /* Sanity check */
516     HDassert(f);
517     HDassert(H5F_addr_defined(hdr_addr));
518 
519     /* only the H5AC__READ_ONLY_FLAG may appear in flags */
520     HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
521 
522     /* Set up user data for cache callbacks */
523     udata.f         = f;
524     udata.addr      = hdr_addr;
525     udata.ctx_udata = ctx_udata;
526 
527     /* Protect the header */
528     if (NULL == (hdr = (H5B2_hdr_t *)H5AC_protect(f, H5AC_BT2_HDR, hdr_addr, &udata, flags)))
529         HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, NULL, "unable to load v2 B-tree header, address = %llu",
530                     (unsigned long long)hdr_addr)
531     hdr->f = f; /* (Must be set again here, in case the header was already in the cache -QAK) */
532 
533     /* Create top proxy, if it doesn't exist */
534     if (hdr->swmr_write && NULL == hdr->top_proxy) {
535         /* Create 'top' proxy for v2 B-tree entries */
536         if (NULL == (hdr->top_proxy = H5AC_proxy_entry_create()))
537             HGOTO_ERROR(H5E_BTREE, H5E_CANTCREATE, NULL, "can't create v2 B-tree proxy")
538 
539         /* Add header as child of 'top' proxy */
540         if (H5AC_proxy_entry_add_child(hdr->top_proxy, f, hdr) < 0)
541             HGOTO_ERROR(H5E_BTREE, H5E_CANTSET, NULL, "unable to add v2 B-tree header as child of proxy")
542     } /* end if */
543 
544     /* Set return value */
545     ret_value = hdr;
546 
547 done:
548     /* Clean up on error */
549     if (!ret_value) {
550         /* Release the header, if it was protected */
551         if (hdr && H5AC_unprotect(hdr->f, H5AC_BT2_HDR, hdr_addr, hdr, H5AC__NO_FLAGS_SET) < 0)
552             HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, NULL,
553                         "unable to unprotect v2 B-tree header, address = %llu", (unsigned long long)hdr_addr)
554     } /* end if */
555 
556     FUNC_LEAVE_NOAPI(ret_value)
557 } /* end H5B2__hdr_protect() */
558 
559 /*-------------------------------------------------------------------------
560  * Function:	H5B2__hdr_unprotect
561  *
562  * Purpose:	Convenience wrapper around unprotecting v2 B-tree header
563  *
564  * Return:	Non-negative on success/Negative on failure
565  *
566  * Programmer:	Quincey Koziol
567  *		Dec 18 2015
568  *
569  *-------------------------------------------------------------------------
570  */
571 herr_t
H5B2__hdr_unprotect(H5B2_hdr_t * hdr,unsigned cache_flags)572 H5B2__hdr_unprotect(H5B2_hdr_t *hdr, unsigned cache_flags)
573 {
574     herr_t ret_value = SUCCEED; /* Return value */
575 
576     FUNC_ENTER_PACKAGE
577 
578     /* Sanity check */
579     HDassert(hdr);
580 
581     /* Unprotect the header */
582     if (H5AC_unprotect(hdr->f, H5AC_BT2_HDR, hdr->addr, hdr, cache_flags) < 0)
583         HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL,
584                     "unable to unprotect v2 B-tree header, address = %llu", (unsigned long long)hdr->addr)
585 
586 done:
587     FUNC_LEAVE_NOAPI(ret_value)
588 } /* end H5B2__hdr_unprotect() */
589 
590 /*-------------------------------------------------------------------------
591  * Function:	H5B2__hdr_free
592  *
593  * Purpose:	Free B-tree header info
594  *
595  * Return:	Non-negative on success/Negative on failure
596  *
597  * Programmer:	Quincey Koziol
598  *		Feb  2 2005
599  *
600  *-------------------------------------------------------------------------
601  */
602 herr_t
H5B2__hdr_free(H5B2_hdr_t * hdr)603 H5B2__hdr_free(H5B2_hdr_t *hdr)
604 {
605     herr_t ret_value = SUCCEED; /* Return value */
606 
607     FUNC_ENTER_PACKAGE
608 
609     /* Sanity check */
610     HDassert(hdr);
611 
612     /* Destroy the callback context */
613     if (hdr->cb_ctx) {
614         if ((*hdr->cls->dst_context)(hdr->cb_ctx) < 0)
615             HGOTO_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "can't destroy v2 B-tree client callback context")
616         hdr->cb_ctx = NULL;
617     } /* end if */
618 
619     /* Free the B-tree node buffer */
620     if (hdr->page)
621         hdr->page = H5FL_BLK_FREE(node_page, hdr->page);
622 
623     /* Free the array of offsets into the native key block */
624     if (hdr->nat_off)
625         hdr->nat_off = H5FL_SEQ_FREE(size_t, hdr->nat_off);
626 
627     /* Release the node info */
628     if (hdr->node_info) {
629         unsigned u; /* Local index variable */
630 
631         /* Destroy free list factories */
632         for (u = 0; u < (unsigned)(hdr->depth + 1); u++) {
633             if (hdr->node_info[u].nat_rec_fac)
634                 if (H5FL_fac_term(hdr->node_info[u].nat_rec_fac) < 0)
635                     HGOTO_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL,
636                                 "can't destroy node's native record block factory")
637             if (hdr->node_info[u].node_ptr_fac)
638                 if (H5FL_fac_term(hdr->node_info[u].node_ptr_fac) < 0)
639                     HGOTO_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL,
640                                 "can't destroy node's node pointer block factory")
641         } /* end for */
642 
643         /* Free the array of node info structs */
644         hdr->node_info = H5FL_SEQ_FREE(H5B2_node_info_t, hdr->node_info);
645     } /* end if */
646 
647     /* Release the min & max record info, if set */
648     if (hdr->min_native_rec)
649         hdr->min_native_rec = H5MM_xfree(hdr->min_native_rec);
650     if (hdr->max_native_rec)
651         hdr->max_native_rec = H5MM_xfree(hdr->max_native_rec);
652 
653     /* Destroy the 'top' proxy */
654     if (hdr->top_proxy) {
655         if (H5AC_proxy_entry_dest(hdr->top_proxy) < 0)
656             HGOTO_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "unable to destroy v2 B-tree 'top' proxy")
657         hdr->top_proxy = NULL;
658     } /* end if */
659 
660     /* Free B-tree header info */
661     hdr = H5FL_FREE(H5B2_hdr_t, hdr);
662 
663 done:
664     FUNC_LEAVE_NOAPI(ret_value)
665 } /* end H5B2__hdr_free() */
666 
667 /*-------------------------------------------------------------------------
668  * Function:	H5B2__hdr_delete
669  *
670  * Purpose:	Delete a v2 B-tree, starting with the header
671  *
672  * Return:	Non-negative on success/Negative on failure
673  *
674  * Programmer:	Quincey Koziol
675  *		Oct 15 2009
676  *
677  *-------------------------------------------------------------------------
678  */
679 herr_t
H5B2__hdr_delete(H5B2_hdr_t * hdr)680 H5B2__hdr_delete(H5B2_hdr_t *hdr)
681 {
682     unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting v2 B-tree header */
683     herr_t   ret_value   = SUCCEED;            /* Return value */
684 
685     FUNC_ENTER_PACKAGE
686 
687     /* Sanity check */
688     HDassert(hdr);
689 
690 #ifndef NDEBUG
691     {
692         unsigned hdr_status = 0; /* v2 B-tree header's status in the metadata cache */
693 
694         /* Check the v2 B-tree header's status in the metadata cache */
695         if (H5AC_get_entry_status(hdr->f, hdr->addr, &hdr_status) < 0)
696             HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL,
697                         "unable to check metadata cache status for v2 B-tree header")
698 
699         /* Sanity checks on v2 B-tree header */
700         HDassert(hdr_status & H5AC_ES__IN_CACHE);
701         HDassert(hdr_status & H5AC_ES__IS_PROTECTED);
702     }  /* end block */
703 #endif /* NDEBUG */
704 
705     /* Delete all nodes in B-tree */
706     if (H5F_addr_defined(hdr->root.addr))
707         if (H5B2__delete_node(hdr, hdr->depth, &hdr->root, hdr, hdr->remove_op, hdr->remove_op_data) < 0)
708             HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to delete B-tree nodes")
709 
710     /* Indicate that the heap header should be deleted & file space freed */
711     cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
712 
713 done:
714     /* Unprotect the header with appropriate flags */
715     if (H5B2__hdr_unprotect(hdr, cache_flags) < 0)
716         HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release v2 B-tree header")
717 
718     FUNC_LEAVE_NOAPI(ret_value)
719 } /* end H5B2__hdr_delete() */
720