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: H5Bdbg.c |
16 | | * |
17 | | * Purpose: Debugging routines for B-link tree package |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | /****************/ |
23 | | /* Module Setup */ |
24 | | /****************/ |
25 | | |
26 | | #include "H5Bmodule.h" /* This source code file is part of the H5B module */ |
27 | | |
28 | | /***********/ |
29 | | /* Headers */ |
30 | | /***********/ |
31 | | #include "H5private.h" /* Generic Functions */ |
32 | | #include "H5Bpkg.h" /* B-link trees */ |
33 | | #include "H5Eprivate.h" /* Error handling */ |
34 | | #include "H5MMprivate.h" /* Memory management */ |
35 | | |
36 | | /*------------------------------------------------------------------------- |
37 | | * Function: H5B_debug |
38 | | * |
39 | | * Purpose: Prints debugging info about a B-tree |
40 | | * |
41 | | * Return: Non-negative on success/Negative on failure |
42 | | *------------------------------------------------------------------------- |
43 | | */ |
44 | | herr_t |
45 | | H5B_debug(H5F_t *f, haddr_t addr, FILE *stream, int indent, int fwidth, const H5B_class_t *type, void *udata) |
46 | 0 | { |
47 | 0 | H5B_t *bt = NULL; |
48 | 0 | H5UC_t *rc_shared; /* Ref-counted shared info */ |
49 | 0 | H5B_shared_t *shared; /* Pointer to shared B-tree info */ |
50 | 0 | H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */ |
51 | 0 | unsigned u; /* Local index variable */ |
52 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
53 | |
|
54 | 0 | FUNC_ENTER_NOAPI(FAIL) |
55 | | |
56 | | /* Check arguments */ |
57 | 0 | assert(f); |
58 | 0 | assert(H5_addr_defined(addr)); |
59 | 0 | assert(stream); |
60 | 0 | assert(indent >= 0); |
61 | 0 | assert(fwidth >= 0); |
62 | 0 | assert(type); |
63 | | |
64 | | /* Currently does not support SWMR access */ |
65 | 0 | assert(!(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE)); |
66 | | |
67 | | /* Get shared info for B-tree */ |
68 | 0 | if (NULL == (rc_shared = (type->get_shared)(f, udata))) |
69 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object"); |
70 | 0 | shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared); |
71 | 0 | assert(shared); |
72 | | |
73 | | /* |
74 | | * Load the tree node. |
75 | | */ |
76 | 0 | cache_udata.f = f; |
77 | 0 | cache_udata.type = type; |
78 | 0 | cache_udata.rc_shared = rc_shared; |
79 | 0 | if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) |
80 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node"); |
81 | | |
82 | | /* |
83 | | * Print the values. |
84 | | */ |
85 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Tree type ID:", |
86 | 0 | ((shared->type->id) == H5B_SNODE_ID |
87 | 0 | ? "H5B_SNODE_ID" |
88 | 0 | : ((shared->type->id) == H5B_CHUNK_ID ? "H5B_CHUNK_ID" : "Unknown!"))); |
89 | 0 | fprintf(stream, "%*s%-*s %zu\n", indent, "", fwidth, "Size of node:", shared->sizeof_rnode); |
90 | 0 | fprintf(stream, "%*s%-*s %zu\n", indent, "", fwidth, "Size of raw (disk) key:", shared->sizeof_rkey); |
91 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, |
92 | 0 | "Dirty flag:", bt->cache_info.is_dirty ? "True" : "False"); |
93 | 0 | fprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, "Level:", bt->level); |
94 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth, "Address of left sibling:", bt->left); |
95 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth, "Address of right sibling:", bt->right); |
96 | 0 | fprintf(stream, "%*s%-*s %u (%u)\n", indent, "", fwidth, "Number of children (max):", bt->nchildren, |
97 | 0 | shared->two_k); |
98 | | |
99 | | /* |
100 | | * Print the child addresses |
101 | | */ |
102 | 0 | for (u = 0; u < bt->nchildren; u++) { |
103 | 0 | fprintf(stream, "%*sChild %d...\n", indent, "", u); |
104 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent + 3, "", MAX(3, fwidth) - 3, |
105 | 0 | "Address:", bt->child[u]); |
106 | | |
107 | | /* If there is a key debugging routine, use it to display the left & right keys */ |
108 | 0 | if (type->debug_key) { |
109 | | /* Decode the 'left' key & print it */ |
110 | 0 | fprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(3, fwidth) - 3, "Left Key:"); |
111 | 0 | assert(H5B_NKEY(bt, shared, u)); |
112 | 0 | (void)(type->debug_key)(stream, indent + 6, MAX(6, fwidth) - 6, H5B_NKEY(bt, shared, u), udata); |
113 | | |
114 | | /* Decode the 'right' key & print it */ |
115 | 0 | fprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(3, fwidth) - 3, "Right Key:"); |
116 | 0 | assert(H5B_NKEY(bt, shared, u + 1)); |
117 | 0 | (void)(type->debug_key)(stream, indent + 6, MAX(6, fwidth) - 6, H5B_NKEY(bt, shared, u + 1), |
118 | 0 | udata); |
119 | 0 | } /* end if */ |
120 | 0 | } /* end for */ |
121 | |
|
122 | 0 | done: |
123 | 0 | if (bt && H5AC_unprotect(f, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0) |
124 | 0 | HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release B-tree node"); |
125 | |
|
126 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
127 | 0 | } /* end H5B_debug() */ |
128 | | |
129 | | /*------------------------------------------------------------------------- |
130 | | * Function: H5B__verify_structure |
131 | | * |
132 | | * Purpose: Verifies that the tree is structured correctly |
133 | | * |
134 | | * Return: SUCCEED/FAIL |
135 | | *------------------------------------------------------------------------- |
136 | | */ |
137 | | herr_t |
138 | | H5B__verify_structure(H5F_t *f, haddr_t addr, const H5B_class_t *type, void *udata) |
139 | 0 | { |
140 | 0 | H5B_t *bt = NULL; |
141 | 0 | H5UC_t *rc_shared; /* Ref-counted shared info */ |
142 | 0 | H5B_shared_t *shared; /* Pointer to shared B-tree info */ |
143 | 0 | H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */ |
144 | 0 | int cmp; |
145 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
146 | | |
147 | | /* A queue of child data */ |
148 | 0 | struct child_t { |
149 | 0 | haddr_t addr; |
150 | 0 | unsigned level; |
151 | 0 | struct child_t *next; |
152 | 0 | } *head = NULL, *tail = NULL, *prev = NULL, *cur = NULL, *tmp = NULL; |
153 | |
|
154 | 0 | FUNC_ENTER_PACKAGE |
155 | | |
156 | | /* Get shared info for B-tree */ |
157 | 0 | if (NULL == (rc_shared = (type->get_shared)(f, udata))) |
158 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's shared ref. count object"); |
159 | 0 | if (NULL == (shared = (H5B_shared_t *)H5UC_GET_OBJ(rc_shared))) |
160 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't retrieve B-tree's ref counted shared info"); |
161 | | |
162 | | /* Initialize the queue */ |
163 | 0 | cache_udata.f = f; |
164 | 0 | cache_udata.type = type; |
165 | 0 | cache_udata.rc_shared = rc_shared; |
166 | |
|
167 | 0 | if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) |
168 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "can't protect B-tree node"); |
169 | | |
170 | 0 | if (NULL == (shared = (H5B_shared_t *)H5UC_GET_OBJ(bt->rc_shared))) |
171 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTGET, FAIL, "can't get B-tree shared data"); |
172 | | |
173 | 0 | if (NULL == (cur = (struct child_t *)H5MM_calloc(sizeof(struct child_t)))) |
174 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "can't allocate memory for queue"); |
175 | | |
176 | 0 | cur->addr = addr; |
177 | 0 | cur->level = bt->level; |
178 | 0 | head = tail = cur; |
179 | |
|
180 | 0 | if (H5AC_unprotect(f, H5AC_BT, addr, bt, H5AC__NO_FLAGS_SET) < 0) |
181 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "can't unprotect B-tree node"); |
182 | | |
183 | 0 | bt = NULL; /* Make certain future references will be caught */ |
184 | | |
185 | | /* Do a breadth-first search of the tree. New nodes are added to the end |
186 | | * of the queue as the `cur' pointer is advanced toward the end. We don't |
187 | | * remove any nodes from the queue because we need them in the uniqueness |
188 | | * test. |
189 | | */ |
190 | 0 | while (cur) { |
191 | 0 | if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, cur->addr, &cache_udata, H5AC__READ_ONLY_FLAG))) |
192 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "can't protect B-tree node"); |
193 | | |
194 | | /* Check node header */ |
195 | 0 | if (bt->level != cur->level) |
196 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "B-tree level incorrect"); |
197 | | |
198 | 0 | if (cur->next && cur->next->level == bt->level) { |
199 | 0 | if (!H5_addr_eq(bt->right, cur->next->addr)) |
200 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "right address should not equal next"); |
201 | 0 | } |
202 | 0 | else { |
203 | 0 | if (H5_addr_defined(bt->right)) |
204 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "bt->right should be HADDR_UNDEF"); |
205 | 0 | } |
206 | | |
207 | 0 | if (prev && prev->level == bt->level) { |
208 | 0 | if (!H5_addr_eq(bt->left, prev->addr)) |
209 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "left address should not equal previous"); |
210 | 0 | } |
211 | 0 | else { |
212 | 0 | if (H5_addr_defined(bt->left)) |
213 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "bt->left should be HADDR_UNDEF"); |
214 | 0 | } |
215 | | |
216 | 0 | if (cur->level > 0) { |
217 | 0 | for (unsigned u = 0; u < bt->nchildren; u++) { |
218 | | /* Check that child nodes haven't already been seen. If they |
219 | | * have then the tree has a cycle. |
220 | | */ |
221 | 0 | for (tmp = head; tmp; tmp = tmp->next) |
222 | 0 | if (!H5_addr_ne(tmp->addr, bt->child[u])) |
223 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "cycle detected in tree"); |
224 | | |
225 | | /* Add the child node to the end of the queue */ |
226 | 0 | if (NULL == (tmp = (struct child_t *)H5MM_calloc(sizeof(struct child_t)))) |
227 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTALLOC, FAIL, "can't allocate memory for child node"); |
228 | | |
229 | 0 | tmp->addr = bt->child[u]; |
230 | 0 | tmp->level = bt->level - 1; |
231 | 0 | tail->next = tmp; |
232 | 0 | tail = tmp; |
233 | | |
234 | | /* Check that the keys are monotonically increasing */ |
235 | 0 | cmp = (type->cmp2)(H5B_NKEY(bt, shared, u), udata, H5B_NKEY(bt, shared, u + 1)); |
236 | 0 | if (cmp >= 0) |
237 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "keys not monotonically increasing"); |
238 | 0 | } |
239 | 0 | } |
240 | | |
241 | | /* Release node */ |
242 | 0 | if (H5AC_unprotect(f, H5AC_BT, cur->addr, bt, H5AC__NO_FLAGS_SET) < 0) |
243 | 0 | HGOTO_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "can't unprotect B-tree node"); |
244 | | |
245 | 0 | bt = NULL; /* Make certain future references will be caught */ |
246 | | |
247 | | /* Advance current location in queue */ |
248 | 0 | prev = cur; |
249 | 0 | cur = cur->next; |
250 | 0 | } |
251 | | |
252 | | /* Free all entries from queue */ |
253 | 0 | while (head) { |
254 | 0 | tmp = head->next; |
255 | 0 | H5MM_xfree(head); |
256 | 0 | head = tmp; |
257 | 0 | } |
258 | |
|
259 | 0 | done: |
260 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
261 | 0 | } /* end H5B__verify_structure() */ |