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: H5Gdense.c |
16 | | * |
17 | | * Purpose: Routines for operating on "dense" link storage for a |
18 | | * group in a file. |
19 | | * |
20 | | *------------------------------------------------------------------------- |
21 | | */ |
22 | | |
23 | | /****************/ |
24 | | /* Module Setup */ |
25 | | /****************/ |
26 | | |
27 | | #include "H5Gmodule.h" /* This source code file is part of the H5G module */ |
28 | | |
29 | | /***********/ |
30 | | /* Headers */ |
31 | | /***********/ |
32 | | #include "H5private.h" /* Generic Functions */ |
33 | | #include "H5Eprivate.h" /* Error handling */ |
34 | | #include "H5Gpkg.h" /* Groups */ |
35 | | #include "H5MMprivate.h" /* Memory management */ |
36 | | #include "H5WBprivate.h" /* Wrapped Buffers */ |
37 | | |
38 | | /****************/ |
39 | | /* Local Macros */ |
40 | | /****************/ |
41 | | |
42 | | /* Fractal heap creation parameters for "dense" link storage */ |
43 | 0 | #define H5G_FHEAP_MAN_WIDTH 4 |
44 | 0 | #define H5G_FHEAP_MAN_START_BLOCK_SIZE 512 |
45 | 0 | #define H5G_FHEAP_MAN_MAX_DIRECT_SIZE (64 * 1024) |
46 | 0 | #define H5G_FHEAP_MAN_MAX_INDEX 32 |
47 | 0 | #define H5G_FHEAP_MAN_START_ROOT_ROWS 1 |
48 | 0 | #define H5G_FHEAP_CHECKSUM_DBLOCKS true |
49 | 0 | #define H5G_FHEAP_MAX_MAN_SIZE (4 * 1024) |
50 | | |
51 | | /* v2 B-tree creation macros for 'name' field index */ |
52 | 0 | #define H5G_NAME_BT2_NODE_SIZE 512 |
53 | 0 | #define H5G_NAME_BT2_MERGE_PERC 40 |
54 | 0 | #define H5G_NAME_BT2_SPLIT_PERC 100 |
55 | | |
56 | | /* v2 B-tree creation macros for 'corder' field index */ |
57 | 0 | #define H5G_CORDER_BT2_NODE_SIZE 512 |
58 | 0 | #define H5G_CORDER_BT2_MERGE_PERC 40 |
59 | 0 | #define H5G_CORDER_BT2_SPLIT_PERC 100 |
60 | | |
61 | | /* Size of stack buffer for serialized link */ |
62 | | #define H5G_LINK_BUF_SIZE 128 |
63 | | |
64 | | /******************/ |
65 | | /* Local Typedefs */ |
66 | | /******************/ |
67 | | |
68 | | /* Data exchange structure to use when building table of links in group */ |
69 | | typedef struct { |
70 | | H5G_link_table_t *ltable; /* Pointer to link table to build */ |
71 | | size_t curr_lnk; /* Current link to operate on */ |
72 | | } H5G_dense_bt_ud_t; |
73 | | |
74 | | /* |
75 | | * Data exchange structure to pass through the v2 B-tree layer for the |
76 | | * H5B2_iterate function when iterating over densely stored links. |
77 | | */ |
78 | | typedef struct { |
79 | | /* downward (internal) */ |
80 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
81 | | H5HF_t *fheap; /* Fractal heap handle */ |
82 | | hsize_t count; /* # of links examined */ |
83 | | |
84 | | /* downward (from application) */ |
85 | | hsize_t skip; /* Number of links to skip */ |
86 | | H5G_lib_iterate_t op; /* Callback for each link */ |
87 | | void *op_data; /* Callback data for each link */ |
88 | | |
89 | | /* upward */ |
90 | | int op_ret; /* Return value from callback */ |
91 | | } H5G_bt2_ud_it_t; |
92 | | |
93 | | /* |
94 | | * Data exchange structure to pass through the fractal heap layer for the |
95 | | * H5HF_op function when iterating over densely stored links. |
96 | | */ |
97 | | typedef struct { |
98 | | /* downward (internal) */ |
99 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
100 | | |
101 | | /* upward */ |
102 | | H5O_link_t *lnk; /* Copy of link */ |
103 | | } H5G_fh_ud_it_t; |
104 | | |
105 | | /* |
106 | | * Data exchange structure for dense link storage. This structure is |
107 | | * passed through the v2 B-tree layer when removing links. |
108 | | */ |
109 | | typedef struct { |
110 | | /* downward */ |
111 | | H5G_bt2_ud_common_t common; /* Common info for B-tree user data (must be first) */ |
112 | | bool rem_from_fheap; /* Whether to remove the link from the fractal heap */ |
113 | | haddr_t corder_bt2_addr; /* Address of v2 B-tree indexing creation order */ |
114 | | H5RS_str_t *grp_full_path_r; /* Full path of group where link is removed */ |
115 | | bool replace_names; /* Whether to replace the names of open objects */ |
116 | | } H5G_bt2_ud_rm_t; |
117 | | |
118 | | /* |
119 | | * Data exchange structure to pass through the fractal heap layer for the |
120 | | * H5HF_op function when removing a link from densely stored links. |
121 | | */ |
122 | | typedef struct { |
123 | | /* downward */ |
124 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
125 | | haddr_t corder_bt2_addr; /* Address of v2 B-tree indexing creation order */ |
126 | | H5RS_str_t *grp_full_path_r; /* Full path of group where link is removed */ |
127 | | bool replace_names; /* Whether to replace the names of open objects */ |
128 | | } H5G_fh_ud_rm_t; |
129 | | |
130 | | /* |
131 | | * Data exchange structure for dense link storage. This structure is |
132 | | * passed through the v2 B-tree layer when removing links by index. |
133 | | */ |
134 | | typedef struct { |
135 | | /* downward */ |
136 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
137 | | H5HF_t *fheap; /* Fractal heap handle */ |
138 | | H5_index_t idx_type; /* Primary index for removing link */ |
139 | | haddr_t other_bt2_addr; /* Address of "other" v2 B-tree indexing link */ |
140 | | H5RS_str_t *grp_full_path_r; /* Full path of group where link is removed */ |
141 | | } H5G_bt2_ud_rmbi_t; |
142 | | |
143 | | /* |
144 | | * Data exchange structure to pass through the fractal heap layer for the |
145 | | * H5HF_op function when removing a link from densely stored links by index. |
146 | | */ |
147 | | typedef struct { |
148 | | /* downward */ |
149 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
150 | | |
151 | | /* upward */ |
152 | | H5O_link_t *lnk; /* Pointer to link to remove */ |
153 | | } H5G_fh_ud_rmbi_t; |
154 | | |
155 | | /* |
156 | | * Data exchange structure to pass through the v2 B-tree layer for the |
157 | | * H5B2_index function when retrieving the name of a link by index. |
158 | | */ |
159 | | typedef struct { |
160 | | /* downward (internal) */ |
161 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
162 | | H5HF_t *fheap; /* Fractal heap handle */ |
163 | | |
164 | | /* downward (from application) */ |
165 | | char *name; /* Name buffer to fill */ |
166 | | size_t name_size; /* Size of name buffer to fill */ |
167 | | |
168 | | /* upward */ |
169 | | size_t name_len; /* Full length of name */ |
170 | | } H5G_bt2_ud_gnbi_t; |
171 | | |
172 | | /* |
173 | | * Data exchange structure to pass through the fractal heap layer for the |
174 | | * H5HF_op function when retrieving the name of a link by index. |
175 | | */ |
176 | | typedef struct { |
177 | | /* downward (internal) */ |
178 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
179 | | |
180 | | /* downward (from application) */ |
181 | | char *name; /* Name buffer to fill */ |
182 | | size_t name_size; /* Size of name buffer to fill */ |
183 | | |
184 | | /* upward */ |
185 | | size_t name_len; /* Full length of name */ |
186 | | } H5G_fh_ud_gnbi_t; |
187 | | |
188 | | /* |
189 | | * Data exchange structure to pass through the v2 B-tree layer for the |
190 | | * H5B2_index function when retrieving a link by index. |
191 | | */ |
192 | | typedef struct { |
193 | | /* downward (internal) */ |
194 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
195 | | H5HF_t *fheap; /* Fractal heap handle */ |
196 | | |
197 | | /* upward */ |
198 | | H5O_link_t *lnk; /* Pointer to link */ |
199 | | } H5G_bt2_ud_lbi_t; |
200 | | |
201 | | /* |
202 | | * Data exchange structure to pass through the fractal heap layer for the |
203 | | * H5HF_op function when retrieving a link by index. |
204 | | */ |
205 | | typedef struct { |
206 | | /* downward (internal) */ |
207 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
208 | | |
209 | | /* upward */ |
210 | | H5O_link_t *lnk; /* Pointer to link */ |
211 | | } H5G_fh_ud_lbi_t; |
212 | | |
213 | | /********************/ |
214 | | /* Package Typedefs */ |
215 | | /********************/ |
216 | | |
217 | | /********************/ |
218 | | /* Local Prototypes */ |
219 | | /********************/ |
220 | | |
221 | | /*********************/ |
222 | | /* Package Variables */ |
223 | | /*********************/ |
224 | | |
225 | | /*****************************/ |
226 | | /* Library Private Variables */ |
227 | | /*****************************/ |
228 | | |
229 | | /*******************/ |
230 | | /* Local Variables */ |
231 | | /*******************/ |
232 | | |
233 | | /*------------------------------------------------------------------------- |
234 | | * Function: H5G__dense_create |
235 | | * |
236 | | * Purpose: Creates dense link storage structures for a group |
237 | | * |
238 | | * Return: Non-negative on success/Negative on failure |
239 | | * |
240 | | *------------------------------------------------------------------------- |
241 | | */ |
242 | | herr_t |
243 | | H5G__dense_create(H5F_t *f, H5O_linfo_t *linfo, const H5O_pline_t *pline) |
244 | 0 | { |
245 | 0 | H5HF_create_t fheap_cparam; /* Fractal heap creation parameters */ |
246 | 0 | H5B2_create_t bt2_cparam; /* v2 B-tree creation parameters */ |
247 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
248 | 0 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for names */ |
249 | 0 | H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order */ |
250 | 0 | size_t fheap_id_len; /* Fractal heap ID length */ |
251 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
252 | |
|
253 | 0 | FUNC_ENTER_PACKAGE |
254 | | |
255 | | /* |
256 | | * Check arguments. |
257 | | */ |
258 | 0 | assert(f); |
259 | 0 | assert(linfo); |
260 | | |
261 | | /* Set fractal heap creation parameters */ |
262 | | /* XXX: Give some control of these to applications? */ |
263 | 0 | memset(&fheap_cparam, 0, sizeof(fheap_cparam)); |
264 | 0 | fheap_cparam.managed.width = H5G_FHEAP_MAN_WIDTH; |
265 | 0 | fheap_cparam.managed.start_block_size = H5G_FHEAP_MAN_START_BLOCK_SIZE; |
266 | 0 | fheap_cparam.managed.max_direct_size = H5G_FHEAP_MAN_MAX_DIRECT_SIZE; |
267 | 0 | fheap_cparam.managed.max_index = H5G_FHEAP_MAN_MAX_INDEX; |
268 | 0 | fheap_cparam.managed.start_root_rows = H5G_FHEAP_MAN_START_ROOT_ROWS; |
269 | 0 | fheap_cparam.checksum_dblocks = H5G_FHEAP_CHECKSUM_DBLOCKS; |
270 | 0 | fheap_cparam.max_man_size = H5G_FHEAP_MAX_MAN_SIZE; |
271 | 0 | if (pline) |
272 | 0 | fheap_cparam.pline = *pline; |
273 | | |
274 | | /* Create fractal heap for storing links */ |
275 | 0 | if (NULL == (fheap = H5HF_create(f, &fheap_cparam))) |
276 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create fractal heap"); |
277 | | |
278 | | /* Retrieve the heap's address in the file */ |
279 | 0 | if (H5HF_get_heap_addr(fheap, &(linfo->fheap_addr)) < 0) |
280 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get fractal heap address"); |
281 | | |
282 | | /* Retrieve the heap's ID length in the file */ |
283 | 0 | if (H5HF_get_id_len(fheap, &fheap_id_len) < 0) |
284 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, FAIL, "can't get fractal heap ID length"); |
285 | 0 | assert(fheap_id_len == H5G_DENSE_FHEAP_ID_LEN); |
286 | | |
287 | | /* Create the name index v2 B-tree */ |
288 | 0 | memset(&bt2_cparam, 0, sizeof(bt2_cparam)); |
289 | 0 | bt2_cparam.cls = H5G_BT2_NAME; |
290 | 0 | bt2_cparam.node_size = (size_t)H5G_NAME_BT2_NODE_SIZE; |
291 | 0 | H5_CHECK_OVERFLOW(fheap_id_len, /* From: */ hsize_t, /* To: */ uint32_t); |
292 | 0 | bt2_cparam.rrec_size = 4 + /* Name's hash value */ |
293 | 0 | (uint32_t)fheap_id_len; /* Fractal heap ID */ |
294 | 0 | bt2_cparam.split_percent = H5G_NAME_BT2_SPLIT_PERC; |
295 | 0 | bt2_cparam.merge_percent = H5G_NAME_BT2_MERGE_PERC; |
296 | 0 | if (NULL == (bt2_name = H5B2_create(f, &bt2_cparam, NULL))) |
297 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create v2 B-tree for name index"); |
298 | | |
299 | | /* Retrieve the v2 B-tree's address in the file */ |
300 | 0 | if (H5B2_get_addr(bt2_name, &(linfo->name_bt2_addr)) < 0) |
301 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get v2 B-tree address for name index"); |
302 | | |
303 | | /* Check if we should create a creation order index v2 B-tree */ |
304 | 0 | if (linfo->index_corder) { |
305 | | /* Create the creation order index v2 B-tree */ |
306 | 0 | memset(&bt2_cparam, 0, sizeof(bt2_cparam)); |
307 | 0 | bt2_cparam.cls = H5G_BT2_CORDER; |
308 | 0 | bt2_cparam.node_size = (size_t)H5G_CORDER_BT2_NODE_SIZE; |
309 | 0 | H5_CHECK_OVERFLOW(fheap_id_len, /* From: */ hsize_t, /* To: */ uint32_t); |
310 | 0 | bt2_cparam.rrec_size = 8 + /* Creation order value */ |
311 | 0 | (uint32_t)fheap_id_len; /* Fractal heap ID */ |
312 | 0 | bt2_cparam.split_percent = H5G_CORDER_BT2_SPLIT_PERC; |
313 | 0 | bt2_cparam.merge_percent = H5G_CORDER_BT2_MERGE_PERC; |
314 | 0 | if (NULL == (bt2_corder = H5B2_create(f, &bt2_cparam, NULL))) |
315 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create v2 B-tree for creation order index"); |
316 | | |
317 | | /* Retrieve the v2 B-tree's address in the file */ |
318 | 0 | if (H5B2_get_addr(bt2_corder, &(linfo->corder_bt2_addr)) < 0) |
319 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get v2 B-tree address for creation order index"); |
320 | 0 | } /* end if */ |
321 | | |
322 | 0 | done: |
323 | | /* Close the open objects */ |
324 | 0 | if (fheap && H5HF_close(fheap) < 0) |
325 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
326 | 0 | if (bt2_name && H5B2_close(bt2_name) < 0) |
327 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
328 | 0 | if (bt2_corder && H5B2_close(bt2_corder) < 0) |
329 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index"); |
330 | |
|
331 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
332 | 0 | } /* end H5G__dense_create() */ |
333 | | |
334 | | /*------------------------------------------------------------------------- |
335 | | * Function: H5G__dense_insert |
336 | | * |
337 | | * Purpose: Insert a link into the dense link storage structures for a group |
338 | | * |
339 | | * Return: Non-negative on success/Negative on failure |
340 | | * |
341 | | *------------------------------------------------------------------------- |
342 | | */ |
343 | | herr_t |
344 | | H5G__dense_insert(H5F_t *f, const H5O_linfo_t *linfo, const H5O_link_t *lnk) |
345 | 0 | { |
346 | 0 | H5G_bt2_ud_ins_t udata; /* User data for v2 B-tree insertion */ |
347 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
348 | 0 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */ |
349 | 0 | H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */ |
350 | 0 | size_t link_size; /* Size of serialized link in the heap */ |
351 | 0 | H5WB_t *wb = NULL; /* Wrapped buffer for link data */ |
352 | 0 | uint8_t link_buf[H5G_LINK_BUF_SIZE]; /* Buffer for serializing link */ |
353 | 0 | void *link_ptr = NULL; /* Pointer to serialized link */ |
354 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
355 | |
|
356 | 0 | FUNC_ENTER_PACKAGE |
357 | | |
358 | | /* |
359 | | * Check arguments. |
360 | | */ |
361 | 0 | assert(f); |
362 | 0 | assert(linfo); |
363 | 0 | assert(lnk); |
364 | | |
365 | | /* Find out the size of buffer needed for serialized link */ |
366 | 0 | if ((link_size = H5O_msg_raw_size(f, H5O_LINK_ID, false, lnk)) == 0) |
367 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, FAIL, "can't get link size"); |
368 | | |
369 | | /* Wrap the local buffer for serialized link */ |
370 | 0 | if (NULL == (wb = H5WB_wrap(link_buf, sizeof(link_buf)))) |
371 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't wrap buffer"); |
372 | | |
373 | | /* Get a pointer to a buffer that's large enough for link */ |
374 | 0 | if (NULL == (link_ptr = H5WB_actual(wb, link_size))) |
375 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "can't get actual buffer"); |
376 | | |
377 | | /* Create serialized form of link */ |
378 | 0 | if (H5O_msg_encode(f, H5O_LINK_ID, false, (unsigned char *)link_ptr, lnk) < 0) |
379 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTENCODE, FAIL, "can't encode link"); |
380 | | |
381 | | /* Open the fractal heap */ |
382 | 0 | if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr))) |
383 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
384 | | |
385 | | /* Insert the serialized link into the fractal heap */ |
386 | 0 | if (H5HF_insert(fheap, link_size, link_ptr, udata.id) < 0) |
387 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link into fractal heap"); |
388 | | |
389 | | /* Open the name index v2 B-tree */ |
390 | 0 | if (NULL == (bt2_name = H5B2_open(f, linfo->name_bt2_addr, NULL))) |
391 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index"); |
392 | | |
393 | | /* Create the callback information for v2 B-tree record insertion */ |
394 | 0 | udata.common.f = f; |
395 | 0 | udata.common.fheap = fheap; |
396 | 0 | udata.common.name = lnk->name; |
397 | 0 | udata.common.name_hash = H5_checksum_lookup3(lnk->name, strlen(lnk->name), 0); |
398 | 0 | udata.common.corder = lnk->corder; |
399 | 0 | udata.common.found_op = NULL; |
400 | 0 | udata.common.found_op_data = NULL; |
401 | | /* udata.id already set in H5HF_insert() call */ |
402 | | |
403 | | /* Insert link into 'name' tracking v2 B-tree */ |
404 | 0 | if (H5B2_insert(bt2_name, &udata) < 0) |
405 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert record into v2 B-tree"); |
406 | | |
407 | | /* Check if we should create a creation order index v2 B-tree record */ |
408 | 0 | if (linfo->index_corder) { |
409 | | /* Open the creation order index v2 B-tree */ |
410 | 0 | assert(H5_addr_defined(linfo->corder_bt2_addr)); |
411 | 0 | if (NULL == (bt2_corder = H5B2_open(f, linfo->corder_bt2_addr, NULL))) |
412 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index"); |
413 | | |
414 | | /* Insert the record into the creation order index v2 B-tree */ |
415 | 0 | if (H5B2_insert(bt2_corder, &udata) < 0) |
416 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert record into v2 B-tree"); |
417 | 0 | } /* end if */ |
418 | | |
419 | 0 | done: |
420 | | /* Release resources */ |
421 | 0 | if (fheap && H5HF_close(fheap) < 0) |
422 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
423 | 0 | if (bt2_name && H5B2_close(bt2_name) < 0) |
424 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
425 | 0 | if (bt2_corder && H5B2_close(bt2_corder) < 0) |
426 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index"); |
427 | 0 | if (wb && H5WB_unwrap(wb) < 0) |
428 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer"); |
429 | |
|
430 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
431 | 0 | } /* end H5G__dense_insert() */ |
432 | | |
433 | | /*------------------------------------------------------------------------- |
434 | | * Function: H5G__dense_lookup_cb |
435 | | * |
436 | | * Purpose: Callback when a link is located in an index |
437 | | * |
438 | | * Return: Non-negative on success/Negative on failure |
439 | | * |
440 | | *------------------------------------------------------------------------- |
441 | | */ |
442 | | static herr_t |
443 | | H5G__dense_lookup_cb(const void *_lnk, void *_user_lnk) |
444 | 0 | { |
445 | 0 | const H5O_link_t *lnk = (const H5O_link_t *)_lnk; /* Record from B-tree */ |
446 | 0 | H5O_link_t *user_lnk = (H5O_link_t *)_user_lnk; /* User data from v2 B-tree link lookup */ |
447 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
448 | |
|
449 | 0 | FUNC_ENTER_PACKAGE |
450 | | |
451 | | /* |
452 | | * Check arguments. |
453 | | */ |
454 | 0 | assert(lnk); |
455 | 0 | assert(user_lnk); |
456 | | |
457 | | /* Copy link information */ |
458 | 0 | if (H5O_msg_copy(H5O_LINK_ID, lnk, user_lnk) == NULL) |
459 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message"); |
460 | | |
461 | 0 | done: |
462 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
463 | 0 | } /* end H5G__dense_lookup_cb() */ |
464 | | |
465 | | /*------------------------------------------------------------------------- |
466 | | * Function: H5G__dense_lookup |
467 | | * |
468 | | * Purpose: Look up a link within a group that uses dense link storage |
469 | | * |
470 | | * Return: SUCCEED/FAIL |
471 | | * |
472 | | *------------------------------------------------------------------------- |
473 | | */ |
474 | | herr_t |
475 | | H5G__dense_lookup(H5F_t *f, const H5O_linfo_t *linfo, const char *name, bool *found, H5O_link_t *lnk) |
476 | 0 | { |
477 | 0 | H5G_bt2_ud_common_t udata; /* User data for v2 B-tree link lookup */ |
478 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
479 | 0 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */ |
480 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
481 | |
|
482 | 0 | FUNC_ENTER_PACKAGE |
483 | | |
484 | | /* |
485 | | * Check arguments. |
486 | | */ |
487 | 0 | assert(f); |
488 | 0 | assert(linfo); |
489 | 0 | assert(name && *name); |
490 | 0 | assert(found); |
491 | 0 | assert(lnk); |
492 | | |
493 | | /* Open the fractal heap */ |
494 | 0 | if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr))) |
495 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
496 | | |
497 | | /* Open the name index v2 B-tree */ |
498 | 0 | if (NULL == (bt2_name = H5B2_open(f, linfo->name_bt2_addr, NULL))) |
499 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index"); |
500 | | |
501 | | /* Construct the user data for v2 B-tree callback */ |
502 | 0 | udata.f = f; |
503 | 0 | udata.fheap = fheap; |
504 | 0 | udata.name = name; |
505 | 0 | udata.name_hash = H5_checksum_lookup3(name, strlen(name), 0); |
506 | 0 | udata.found_op = H5G__dense_lookup_cb; /* v2 B-tree comparison callback */ |
507 | 0 | udata.found_op_data = lnk; |
508 | | |
509 | | /* Find & copy the named link in the 'name' index */ |
510 | 0 | if (H5B2_find(bt2_name, &udata, found, NULL, NULL) < 0) |
511 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to locate link in name index"); |
512 | | |
513 | 0 | done: |
514 | | /* Release resources */ |
515 | 0 | if (fheap && H5HF_close(fheap) < 0) |
516 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
517 | 0 | if (bt2_name && H5B2_close(bt2_name) < 0) |
518 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
519 | |
|
520 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
521 | 0 | } /* end H5G__dense_lookup() */ |
522 | | |
523 | | /*------------------------------------------------------------------------- |
524 | | * Function: H5G__dense_lookup_by_idx_fh_cb |
525 | | * |
526 | | * Purpose: Callback for fractal heap operator, to make copy of link when |
527 | | * when lookup up a link by index |
528 | | * |
529 | | * Return: SUCCEED/FAIL |
530 | | * |
531 | | *------------------------------------------------------------------------- |
532 | | */ |
533 | | static herr_t |
534 | | H5G__dense_lookup_by_idx_fh_cb(const void *obj, size_t obj_len, void *_udata) |
535 | 0 | { |
536 | 0 | H5G_fh_ud_lbi_t *udata = (H5G_fh_ud_lbi_t *)_udata; /* User data for fractal heap 'op' callback */ |
537 | 0 | H5O_link_t *tmp_lnk = NULL; /* Temporary pointer to link */ |
538 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
539 | |
|
540 | 0 | FUNC_ENTER_PACKAGE |
541 | | |
542 | | /* Decode link information & keep a copy */ |
543 | 0 | if (NULL == (tmp_lnk = (H5O_link_t *)H5O_msg_decode(udata->f, NULL, H5O_LINK_ID, obj_len, |
544 | 0 | (const unsigned char *)obj))) |
545 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link"); |
546 | | |
547 | | /* Copy link information */ |
548 | 0 | if (NULL == H5O_msg_copy(H5O_LINK_ID, tmp_lnk, udata->lnk)) |
549 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message"); |
550 | | |
551 | 0 | done: |
552 | | /* Release the space allocated for the link */ |
553 | 0 | if (tmp_lnk) |
554 | 0 | H5O_msg_free(H5O_LINK_ID, tmp_lnk); |
555 | |
|
556 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
557 | 0 | } /* end H5G__dense_lookup_by_idx_fh_cb() */ |
558 | | |
559 | | /*------------------------------------------------------------------------- |
560 | | * Function: H5G__dense_lookup_by_idx_bt2_cb |
561 | | * |
562 | | * Purpose: v2 B-tree callback for dense link storage lookup by index |
563 | | * |
564 | | * Return: H5_ITER_ERROR/H5_ITER_CONT/H5_ITER_STOP |
565 | | * |
566 | | *------------------------------------------------------------------------- |
567 | | */ |
568 | | static herr_t |
569 | | H5G__dense_lookup_by_idx_bt2_cb(const void *_record, void *_bt2_udata) |
570 | 0 | { |
571 | 0 | const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record; |
572 | 0 | H5G_bt2_ud_lbi_t *bt2_udata = (H5G_bt2_ud_lbi_t *)_bt2_udata; /* User data for callback */ |
573 | 0 | H5G_fh_ud_lbi_t fh_udata; /* User data for fractal heap 'op' callback */ |
574 | 0 | int ret_value = H5_ITER_CONT; /* Return value */ |
575 | |
|
576 | 0 | FUNC_ENTER_PACKAGE |
577 | | |
578 | | /* Prepare user data for callback */ |
579 | | /* down */ |
580 | 0 | fh_udata.f = bt2_udata->f; |
581 | 0 | fh_udata.lnk = bt2_udata->lnk; |
582 | | |
583 | | /* Call fractal heap 'op' routine, to copy the link information */ |
584 | 0 | if (H5HF_op(bt2_udata->fheap, record->id, H5G__dense_lookup_by_idx_fh_cb, &fh_udata) < 0) |
585 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, H5_ITER_ERROR, "link found callback failed"); |
586 | | |
587 | 0 | done: |
588 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
589 | 0 | } /* end H5G__dense_lookup_by_idx_bt2_cb() */ |
590 | | |
591 | | /*------------------------------------------------------------------------- |
592 | | * Function: H5G__dense_lookup_by_idx |
593 | | * |
594 | | * Purpose: Look up a link within a group that uses dense link storage, |
595 | | * according to the order of an index |
596 | | * |
597 | | * Return: Non-negative on success/Negative on failure |
598 | | * |
599 | | *------------------------------------------------------------------------- |
600 | | */ |
601 | | herr_t |
602 | | H5G__dense_lookup_by_idx(H5F_t *f, const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order, |
603 | | hsize_t n, H5O_link_t *lnk) |
604 | 0 | { |
605 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
606 | 0 | H5G_link_table_t ltable = {0, NULL}; /* Table of links */ |
607 | 0 | H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */ |
608 | 0 | haddr_t bt2_addr; /* Address of v2 B-tree to use for lookup */ |
609 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
610 | |
|
611 | 0 | FUNC_ENTER_PACKAGE |
612 | | |
613 | | /* |
614 | | * Check arguments. |
615 | | */ |
616 | 0 | assert(f); |
617 | 0 | assert(linfo); |
618 | 0 | assert(lnk); |
619 | | |
620 | | /* Determine the address of the index to use */ |
621 | 0 | if (idx_type == H5_INDEX_NAME) { |
622 | | /* Since names are hashed, getting them in strictly increasing or |
623 | | * decreasing order requires building a table and sorting it. |
624 | | * If the order is native, use the B-tree for names. |
625 | | */ |
626 | 0 | bt2_addr = HADDR_UNDEF; |
627 | 0 | } /* end if */ |
628 | 0 | else { |
629 | 0 | assert(idx_type == H5_INDEX_CRT_ORDER); |
630 | | |
631 | | /* This address may not be defined if creation order is tracked, but |
632 | | * there's no index on it. If there's no v2 B-tree that indexes |
633 | | * the links and the order is native, use the B-tree for names. |
634 | | * Otherwise, build a table. |
635 | | */ |
636 | 0 | bt2_addr = linfo->corder_bt2_addr; |
637 | 0 | } /* end else */ |
638 | | |
639 | | /* If the order is native and there's no B-tree for indexing the links, |
640 | | * use the B-tree for names instead of building a table to speed up the |
641 | | * process. |
642 | | */ |
643 | 0 | if (order == H5_ITER_NATIVE && !H5_addr_defined(bt2_addr)) { |
644 | 0 | bt2_addr = linfo->name_bt2_addr; |
645 | 0 | assert(H5_addr_defined(bt2_addr)); |
646 | 0 | } /* end if */ |
647 | | |
648 | | /* If there is an index defined for the field, use it */ |
649 | 0 | if (H5_addr_defined(bt2_addr)) { |
650 | 0 | H5G_bt2_ud_lbi_t udata; /* User data for v2 B-tree link lookup */ |
651 | | |
652 | | /* Open the fractal heap */ |
653 | 0 | if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr))) |
654 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
655 | | |
656 | | /* Open the index v2 B-tree */ |
657 | 0 | if (NULL == (bt2 = H5B2_open(f, bt2_addr, NULL))) |
658 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index"); |
659 | | |
660 | | /* Construct the user data for v2 B-tree callback */ |
661 | 0 | udata.f = f; |
662 | 0 | udata.fheap = fheap; |
663 | 0 | udata.lnk = lnk; |
664 | | |
665 | | /* Find & copy the link in the appropriate index */ |
666 | 0 | if (H5B2_index(bt2, order, n, H5G__dense_lookup_by_idx_bt2_cb, &udata) < 0) |
667 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to locate link in index"); |
668 | 0 | } /* end if */ |
669 | 0 | else { /* Otherwise, we need to build a table of the links and sort it */ |
670 | | /* Build the table of links for this group */ |
671 | 0 | if (H5G__dense_build_table(f, linfo, idx_type, order, <able) < 0) |
672 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links"); |
673 | | |
674 | | /* Check for going out of bounds */ |
675 | 0 | if (n >= ltable.nlinks) |
676 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound"); |
677 | | |
678 | | /* Copy link information */ |
679 | 0 | if (NULL == H5O_msg_copy(H5O_LINK_ID, <able.lnks[n], lnk)) |
680 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message"); |
681 | 0 | } /* end else */ |
682 | | |
683 | 0 | done: |
684 | | /* Release resources */ |
685 | 0 | if (fheap && H5HF_close(fheap) < 0) |
686 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
687 | 0 | if (bt2 && H5B2_close(bt2) < 0) |
688 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index"); |
689 | 0 | if (ltable.lnks && H5G__link_release_table(<able) < 0) |
690 | 0 | HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table"); |
691 | |
|
692 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
693 | 0 | } /* end H5G__dense_lookup_by_idx() */ |
694 | | |
695 | | /*------------------------------------------------------------------------- |
696 | | * Function: H5G__dense_build_table_cb |
697 | | * |
698 | | * Purpose: Callback routine for building table of links from dense |
699 | | * link storage. |
700 | | * |
701 | | * Return: Success: Non-negative |
702 | | * Failure: Negative |
703 | | * |
704 | | *------------------------------------------------------------------------- |
705 | | */ |
706 | | static herr_t |
707 | | H5G__dense_build_table_cb(const H5O_link_t *lnk, void *_udata) |
708 | 0 | { |
709 | 0 | H5G_dense_bt_ud_t *udata = (H5G_dense_bt_ud_t *)_udata; /* 'User data' passed in */ |
710 | 0 | herr_t ret_value = H5_ITER_CONT; /* Return value */ |
711 | |
|
712 | 0 | FUNC_ENTER_PACKAGE |
713 | | |
714 | | /* check arguments */ |
715 | 0 | assert(lnk); |
716 | 0 | assert(udata); |
717 | 0 | assert(udata->curr_lnk < udata->ltable->nlinks); |
718 | | |
719 | | /* Copy link information */ |
720 | 0 | if (H5O_msg_copy(H5O_LINK_ID, lnk, &(udata->ltable->lnks[udata->curr_lnk])) == NULL) |
721 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message"); |
722 | | |
723 | | /* Increment number of links stored */ |
724 | 0 | udata->curr_lnk++; |
725 | |
|
726 | 0 | done: |
727 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
728 | 0 | } /* end H5G__dense_build_table_cb() */ |
729 | | |
730 | | /*------------------------------------------------------------------------- |
731 | | * Function: H5G__dense_build_table |
732 | | * |
733 | | * Purpose: Builds a table containing a sorted list of links for a group |
734 | | * |
735 | | * Note: Used for building table of links in non-native iteration order |
736 | | * for an index |
737 | | * |
738 | | * Return: Success: Non-negative |
739 | | * Failure: Negative |
740 | | * |
741 | | *------------------------------------------------------------------------- |
742 | | */ |
743 | | herr_t |
744 | | H5G__dense_build_table(H5F_t *f, const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order, |
745 | | H5G_link_table_t *ltable) |
746 | 0 | { |
747 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
748 | |
|
749 | 0 | FUNC_ENTER_PACKAGE |
750 | | |
751 | | /* Sanity check */ |
752 | 0 | assert(f); |
753 | 0 | assert(linfo); |
754 | 0 | assert(ltable); |
755 | | |
756 | | /* Set size of table */ |
757 | 0 | H5_CHECK_OVERFLOW(linfo->nlinks, /* From: */ hsize_t, /* To: */ size_t); |
758 | 0 | ltable->nlinks = (size_t)linfo->nlinks; |
759 | | |
760 | | /* Allocate space for the table entries */ |
761 | 0 | if (ltable->nlinks > 0) { |
762 | 0 | H5G_dense_bt_ud_t udata; /* User data for iteration callback */ |
763 | | |
764 | | /* Allocate the table to store the links */ |
765 | 0 | if ((ltable->lnks = (H5O_link_t *)H5MM_calloc(sizeof(H5O_link_t) * ltable->nlinks)) == NULL) |
766 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); |
767 | | |
768 | | /* Initialize all links to invalid. NOTE: If H5O_link_t changes, update this loop. */ |
769 | 0 | for (size_t i = 0; i < ltable->nlinks; i++) |
770 | 0 | ltable->lnks[i].type = H5L_TYPE_ERROR; |
771 | | |
772 | | /* Set up user data for iteration */ |
773 | 0 | udata.ltable = ltable; |
774 | 0 | udata.curr_lnk = 0; |
775 | | |
776 | | /* Iterate over the links in the group, building a table of the link messages */ |
777 | 0 | if (H5G__dense_iterate(f, linfo, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL, |
778 | 0 | H5G__dense_build_table_cb, &udata) < 0) |
779 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over links"); |
780 | | |
781 | | /* Sort link table in correct iteration order */ |
782 | 0 | if (H5G__link_sort_table(ltable, idx_type, order) < 0) |
783 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTSORT, FAIL, "error sorting link messages"); |
784 | 0 | } /* end if */ |
785 | 0 | else |
786 | 0 | ltable->lnks = NULL; |
787 | | |
788 | 0 | done: |
789 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
790 | 0 | } /* end H5G__dense_build_table() */ |
791 | | |
792 | | /*------------------------------------------------------------------------- |
793 | | * Function: H5G__dense_iterate_fh_cb |
794 | | * |
795 | | * Purpose: Callback for fractal heap operator, to make user's callback |
796 | | * when iterating over links |
797 | | * |
798 | | * Return: SUCCEED/FAIL |
799 | | * |
800 | | *------------------------------------------------------------------------- |
801 | | */ |
802 | | static herr_t |
803 | | H5G__dense_iterate_fh_cb(const void *obj, size_t obj_len, void *_udata) |
804 | 0 | { |
805 | 0 | H5G_fh_ud_it_t *udata = (H5G_fh_ud_it_t *)_udata; /* User data for fractal heap 'op' callback */ |
806 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
807 | |
|
808 | 0 | FUNC_ENTER_PACKAGE |
809 | | |
810 | | /* Decode link information & keep a copy */ |
811 | | /* (we make a copy instead of calling the user/library callback directly in |
812 | | * this routine because this fractal heap 'op' callback routine is called |
813 | | * with the direct block protected and if the callback routine invokes an |
814 | | * HDF5 routine, it could attempt to re-protect that direct block for the |
815 | | * heap, causing the HDF5 routine called to fail - QAK) |
816 | | */ |
817 | 0 | if (NULL == (udata->lnk = (H5O_link_t *)H5O_msg_decode(udata->f, NULL, H5O_LINK_ID, obj_len, |
818 | 0 | (const unsigned char *)obj))) |
819 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link"); |
820 | | |
821 | 0 | done: |
822 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
823 | 0 | } /* end H5G__dense_iterate_fh_cb() */ |
824 | | |
825 | | /*------------------------------------------------------------------------- |
826 | | * Function: H5G__dense_iterate_bt2_cb |
827 | | * |
828 | | * Purpose: v2 B-tree callback for dense link storage iterator |
829 | | * |
830 | | * Return: H5_ITER_ERROR/H5_ITER_CONT/H5_ITER_STOP |
831 | | * |
832 | | *------------------------------------------------------------------------- |
833 | | */ |
834 | | static herr_t |
835 | | H5G__dense_iterate_bt2_cb(const void *_record, void *_bt2_udata) |
836 | 0 | { |
837 | 0 | const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record; |
838 | 0 | H5G_bt2_ud_it_t *bt2_udata = (H5G_bt2_ud_it_t *)_bt2_udata; /* User data for callback */ |
839 | 0 | herr_t ret_value = H5_ITER_CONT; /* Return value */ |
840 | |
|
841 | 0 | FUNC_ENTER_PACKAGE |
842 | | |
843 | | /* Check for skipping links */ |
844 | 0 | if (bt2_udata->skip > 0) |
845 | 0 | --bt2_udata->skip; |
846 | 0 | else { |
847 | 0 | H5G_fh_ud_it_t fh_udata; /* User data for fractal heap 'op' callback */ |
848 | | |
849 | | /* Prepare user data for callback */ |
850 | | /* down */ |
851 | 0 | fh_udata.f = bt2_udata->f; |
852 | | |
853 | | /* Call fractal heap 'op' routine, to copy the link information */ |
854 | 0 | if (H5HF_op(bt2_udata->fheap, record->id, H5G__dense_iterate_fh_cb, &fh_udata) < 0) |
855 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, H5_ITER_ERROR, "heap op callback failed"); |
856 | | |
857 | | /* Make the callback */ |
858 | 0 | ret_value = (bt2_udata->op)(fh_udata.lnk, bt2_udata->op_data); |
859 | | |
860 | | /* Release the space allocated for the link */ |
861 | 0 | H5O_msg_free(H5O_LINK_ID, fh_udata.lnk); |
862 | 0 | } /* end else */ |
863 | | |
864 | | /* Increment the number of entries passed through */ |
865 | | /* (whether we skipped them or not) */ |
866 | 0 | bt2_udata->count++; |
867 | | |
868 | | /* Check for callback failure and pass along return value */ |
869 | 0 | if (ret_value < 0) |
870 | 0 | HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed"); |
871 | |
|
872 | 0 | done: |
873 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
874 | 0 | } /* end H5G__dense_iterate_bt2_cb() */ |
875 | | |
876 | | /*------------------------------------------------------------------------- |
877 | | * Function: H5G__dense_iterate |
878 | | * |
879 | | * Purpose: Iterate over the objects in a group using dense link storage |
880 | | * |
881 | | * Return: Non-negative on success/Negative on failure |
882 | | * |
883 | | *------------------------------------------------------------------------- |
884 | | */ |
885 | | herr_t |
886 | | H5G__dense_iterate(H5F_t *f, const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order, |
887 | | hsize_t skip, hsize_t *last_lnk, H5G_lib_iterate_t op, void *op_data) |
888 | 0 | { |
889 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
890 | 0 | H5G_link_table_t ltable = {0, NULL}; /* Table of links */ |
891 | 0 | H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */ |
892 | 0 | haddr_t bt2_addr; /* Address of v2 B-tree to use for lookup */ |
893 | 0 | herr_t ret_value = FAIL; /* Return value */ |
894 | |
|
895 | 0 | FUNC_ENTER_PACKAGE |
896 | | |
897 | | /* |
898 | | * Check arguments. |
899 | | */ |
900 | 0 | assert(f); |
901 | 0 | assert(linfo); |
902 | 0 | assert(op); |
903 | | |
904 | | /* Determine the address of the index to use */ |
905 | 0 | if (idx_type == H5_INDEX_NAME) { |
906 | | /* Since names are hashed, getting them in strictly increasing or |
907 | | * decreasing order requires building a table and sorting it. If |
908 | | * the order is native, use the B-tree for names. |
909 | | */ |
910 | 0 | bt2_addr = HADDR_UNDEF; |
911 | 0 | } /* end if */ |
912 | 0 | else { |
913 | 0 | assert(idx_type == H5_INDEX_CRT_ORDER); |
914 | | |
915 | | /* This address may not be defined if creation order is tracked, but |
916 | | * there's no index on it. If there's no v2 B-tree that indexes |
917 | | * the links and the order is native, use the B-tree for names. |
918 | | * Otherwise, build a table. |
919 | | */ |
920 | 0 | bt2_addr = linfo->corder_bt2_addr; |
921 | 0 | } /* end else */ |
922 | | |
923 | | /* If the order is native and there's no B-tree for indexing the links, |
924 | | * use the B-tree for names instead of building a table to speed up the |
925 | | * process. |
926 | | */ |
927 | 0 | if (order == H5_ITER_NATIVE && !H5_addr_defined(bt2_addr)) { |
928 | 0 | assert(H5_addr_defined(linfo->name_bt2_addr)); |
929 | 0 | bt2_addr = linfo->name_bt2_addr; |
930 | 0 | } /* end if */ |
931 | | |
932 | | /* Check on iteration order */ |
933 | 0 | if (order == H5_ITER_NATIVE) { |
934 | 0 | H5G_bt2_ud_it_t udata; /* User data for iterator callback */ |
935 | | |
936 | | /* Sanity check */ |
937 | 0 | assert(H5_addr_defined(bt2_addr)); |
938 | | |
939 | | /* Open the fractal heap */ |
940 | 0 | if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr))) |
941 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
942 | | |
943 | | /* Open the index v2 B-tree */ |
944 | 0 | if (NULL == (bt2 = H5B2_open(f, bt2_addr, NULL))) |
945 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index"); |
946 | | |
947 | | /* Construct the user data for v2 B-tree iterator callback */ |
948 | 0 | udata.f = f; |
949 | 0 | udata.fheap = fheap; |
950 | 0 | udata.skip = skip; |
951 | 0 | udata.count = 0; |
952 | 0 | udata.op = op; |
953 | 0 | udata.op_data = op_data; |
954 | | |
955 | | /* Iterate over the records in the v2 B-tree's "native" order */ |
956 | | /* (by hash of name) */ |
957 | 0 | if ((ret_value = H5B2_iterate(bt2, H5G__dense_iterate_bt2_cb, &udata)) < 0) |
958 | 0 | HERROR(H5E_SYM, H5E_BADITER, "link iteration failed"); |
959 | | |
960 | | /* Update the last link examined, if requested */ |
961 | 0 | if (last_lnk) |
962 | 0 | *last_lnk = udata.count; |
963 | 0 | } /* end if */ |
964 | 0 | else { |
965 | | /* Build the table of links for this group */ |
966 | 0 | if (H5G__dense_build_table(f, linfo, idx_type, order, <able) < 0) |
967 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links"); |
968 | | |
969 | | /* Iterate over links in table */ |
970 | 0 | if ((ret_value = H5G__link_iterate_table(<able, skip, last_lnk, op, op_data)) < 0) |
971 | 0 | HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed"); |
972 | 0 | } /* end else */ |
973 | | |
974 | 0 | done: |
975 | | /* Release resources */ |
976 | 0 | if (fheap && H5HF_close(fheap) < 0) |
977 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
978 | 0 | if (bt2 && H5B2_close(bt2) < 0) |
979 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index"); |
980 | 0 | if (ltable.lnks && H5G__link_release_table(<able) < 0) |
981 | 0 | HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table"); |
982 | |
|
983 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
984 | 0 | } /* end H5G__dense_iterate() */ |
985 | | |
986 | | /*------------------------------------------------------------------------- |
987 | | * Function: H5G__dense_get_name_by_idx_fh_cb |
988 | | * |
989 | | * Purpose: Callback for fractal heap operator, to retrieve name according |
990 | | * to an index |
991 | | * |
992 | | * Return: SUCCEED/FAIL |
993 | | * |
994 | | *------------------------------------------------------------------------- |
995 | | */ |
996 | | static herr_t |
997 | | H5G__dense_get_name_by_idx_fh_cb(const void *obj, size_t obj_len, void *_udata) |
998 | 0 | { |
999 | 0 | H5G_fh_ud_gnbi_t *udata = (H5G_fh_ud_gnbi_t *)_udata; /* User data for fractal heap 'op' callback */ |
1000 | 0 | H5O_link_t *lnk; /* Pointer to link created from heap object */ |
1001 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1002 | |
|
1003 | 0 | FUNC_ENTER_PACKAGE |
1004 | | |
1005 | | /* Decode link information */ |
1006 | 0 | if (NULL == (lnk = (H5O_link_t *)H5O_msg_decode(udata->f, NULL, H5O_LINK_ID, obj_len, |
1007 | 0 | (const unsigned char *)obj))) |
1008 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link"); |
1009 | | |
1010 | | /* Get the length of the name */ |
1011 | 0 | udata->name_len = strlen(lnk->name); |
1012 | | |
1013 | | /* Copy the name into the user's buffer, if given */ |
1014 | 0 | if (udata->name) { |
1015 | 0 | strncpy(udata->name, lnk->name, MIN((udata->name_len + 1), udata->name_size)); |
1016 | 0 | if (udata->name_len >= udata->name_size) |
1017 | 0 | udata->name[udata->name_size - 1] = '\0'; |
1018 | 0 | } /* end if */ |
1019 | | |
1020 | | /* Release the space allocated for the link */ |
1021 | 0 | H5O_msg_free(H5O_LINK_ID, lnk); |
1022 | |
|
1023 | 0 | done: |
1024 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1025 | 0 | } /* end H5G__dense_get_name_by_idx_fh_cb() */ |
1026 | | |
1027 | | /*------------------------------------------------------------------------- |
1028 | | * Function: H5G__dense_get_name_by_idx_bt2_cb |
1029 | | * |
1030 | | * Purpose: v2 B-tree callback for dense link storage 'get name by idx' call |
1031 | | * |
1032 | | * Return: Non-negative on success/Negative on failure |
1033 | | * |
1034 | | *------------------------------------------------------------------------- |
1035 | | */ |
1036 | | static herr_t |
1037 | | H5G__dense_get_name_by_idx_bt2_cb(const void *_record, void *_bt2_udata) |
1038 | 0 | { |
1039 | 0 | const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record; |
1040 | 0 | H5G_bt2_ud_gnbi_t *bt2_udata = (H5G_bt2_ud_gnbi_t *)_bt2_udata; /* User data for callback */ |
1041 | 0 | H5G_fh_ud_gnbi_t fh_udata; /* User data for fractal heap 'op' callback */ |
1042 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1043 | |
|
1044 | 0 | FUNC_ENTER_PACKAGE |
1045 | | |
1046 | | /* Prepare user data for callback */ |
1047 | | /* down */ |
1048 | 0 | fh_udata.f = bt2_udata->f; |
1049 | 0 | fh_udata.name = bt2_udata->name; |
1050 | 0 | fh_udata.name_size = bt2_udata->name_size; |
1051 | | |
1052 | | /* Call fractal heap 'op' routine, to perform user callback */ |
1053 | 0 | if (H5HF_op(bt2_udata->fheap, record->id, H5G__dense_get_name_by_idx_fh_cb, &fh_udata) < 0) |
1054 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, FAIL, "link found callback failed"); |
1055 | | |
1056 | | /* Set the name's full length to return */ |
1057 | 0 | bt2_udata->name_len = fh_udata.name_len; |
1058 | |
|
1059 | 0 | done: |
1060 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1061 | 0 | } /* end H5G__dense_get_name_by_idx_bt2_cb() */ |
1062 | | |
1063 | | /*------------------------------------------------------------------------- |
1064 | | * Function: H5G__dense_get_name_by_idx |
1065 | | * |
1066 | | * Purpose: Returns the name of objects in the group by giving index. |
1067 | | * |
1068 | | * Return: Non-negative on success/Negative on failure |
1069 | | * |
1070 | | *------------------------------------------------------------------------- |
1071 | | */ |
1072 | | herr_t |
1073 | | H5G__dense_get_name_by_idx(H5F_t *f, H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order, |
1074 | | hsize_t n, char *name, size_t name_size, size_t *name_len) |
1075 | 0 | { |
1076 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
1077 | 0 | H5G_link_table_t ltable = {0, NULL}; /* Table of links */ |
1078 | 0 | H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */ |
1079 | 0 | haddr_t bt2_addr; /* Address of v2 B-tree to use for lookup */ |
1080 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1081 | |
|
1082 | 0 | FUNC_ENTER_PACKAGE |
1083 | | |
1084 | | /* |
1085 | | * Check arguments. |
1086 | | */ |
1087 | 0 | assert(f); |
1088 | 0 | assert(linfo); |
1089 | | |
1090 | | /* Determine the address of the index to use */ |
1091 | 0 | if (idx_type == H5_INDEX_NAME) { |
1092 | | /* Since names are hashed, getting them in strictly increasing or |
1093 | | * decreasing order requires building a table and sorting it. If |
1094 | | * the order is native, use the B-tree for names. |
1095 | | */ |
1096 | 0 | bt2_addr = HADDR_UNDEF; |
1097 | 0 | } /* end if */ |
1098 | 0 | else { |
1099 | 0 | assert(idx_type == H5_INDEX_CRT_ORDER); |
1100 | | |
1101 | | /* This address may not be defined if creation order is tracked, but |
1102 | | * there's no index on it. If there's no v2 B-tree that indexes |
1103 | | * the links and the order is native, use the B-tree for names. |
1104 | | * Otherwise, build a table. |
1105 | | */ |
1106 | 0 | bt2_addr = linfo->corder_bt2_addr; |
1107 | 0 | } /* end else */ |
1108 | | |
1109 | | /* If the order is native and there's no B-tree for indexing the links, |
1110 | | * use the B-tree for names instead of building a table to speed up the |
1111 | | * process. |
1112 | | */ |
1113 | 0 | if (order == H5_ITER_NATIVE && !H5_addr_defined(bt2_addr)) { |
1114 | 0 | bt2_addr = linfo->name_bt2_addr; |
1115 | 0 | assert(H5_addr_defined(bt2_addr)); |
1116 | 0 | } /* end if */ |
1117 | | |
1118 | | /* If there is an index defined for the field, use it */ |
1119 | 0 | if (H5_addr_defined(bt2_addr)) { |
1120 | 0 | H5G_bt2_ud_gnbi_t udata; /* User data for v2 B-tree callback */ |
1121 | | |
1122 | | /* Open the fractal heap */ |
1123 | 0 | if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr))) |
1124 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1125 | | |
1126 | | /* Open the index v2 B-tree */ |
1127 | 0 | if (NULL == (bt2 = H5B2_open(f, bt2_addr, NULL))) |
1128 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index"); |
1129 | | |
1130 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1131 | 0 | udata.f = f; |
1132 | 0 | udata.fheap = fheap; |
1133 | 0 | udata.name = name; |
1134 | 0 | udata.name_size = name_size; |
1135 | | |
1136 | | /* Retrieve the name according to the v2 B-tree's index order */ |
1137 | 0 | if (H5B2_index(bt2, order, n, H5G__dense_get_name_by_idx_bt2_cb, &udata) < 0) |
1138 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTLIST, FAIL, "can't locate object in v2 B-tree"); |
1139 | | |
1140 | | /* Set return value */ |
1141 | 0 | *name_len = udata.name_len; |
1142 | 0 | } /* end if */ |
1143 | 0 | else { /* Otherwise, we need to build a table of the links and sort it */ |
1144 | | /* Build the table of links for this group */ |
1145 | 0 | if (H5G__dense_build_table(f, linfo, idx_type, order, <able) < 0) |
1146 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links"); |
1147 | | |
1148 | | /* Check for going out of bounds */ |
1149 | 0 | if (n >= ltable.nlinks) |
1150 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound"); |
1151 | | |
1152 | | /* Get the length of the name */ |
1153 | 0 | *name_len = strlen(ltable.lnks[n].name); |
1154 | | |
1155 | | /* Copy the name into the user's buffer, if given */ |
1156 | 0 | if (name) { |
1157 | 0 | strncpy(name, ltable.lnks[n].name, MIN((*name_len + 1), name_size)); |
1158 | 0 | if (*name_len >= name_size) |
1159 | 0 | name[name_size - 1] = '\0'; |
1160 | 0 | } /* end if */ |
1161 | 0 | } /* end else */ |
1162 | | |
1163 | 0 | done: |
1164 | | /* Release resources */ |
1165 | 0 | if (fheap && H5HF_close(fheap) < 0) |
1166 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1167 | 0 | if (bt2 && H5B2_close(bt2) < 0) |
1168 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index"); |
1169 | 0 | if (ltable.lnks && H5G__link_release_table(<able) < 0) |
1170 | 0 | HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table"); |
1171 | |
|
1172 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1173 | 0 | } /* end H5G__dense_get_name_by_idx() */ |
1174 | | |
1175 | | /*------------------------------------------------------------------------- |
1176 | | * Function: H5G__dense_remove_fh_cb |
1177 | | * |
1178 | | * Purpose: Callback for fractal heap operator when removing links |
1179 | | * |
1180 | | * Return: SUCCEED/FAIL |
1181 | | * |
1182 | | *------------------------------------------------------------------------- |
1183 | | */ |
1184 | | static herr_t |
1185 | | H5G__dense_remove_fh_cb(const void *obj, size_t obj_len, void *_udata) |
1186 | 0 | { |
1187 | 0 | H5G_fh_ud_rm_t *udata = (H5G_fh_ud_rm_t *)_udata; /* User data for fractal heap 'op' callback */ |
1188 | 0 | H5O_link_t *lnk = NULL; /* Pointer to link created from heap object */ |
1189 | 0 | H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */ |
1190 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1191 | |
|
1192 | 0 | FUNC_ENTER_PACKAGE |
1193 | | |
1194 | | /* Decode link information */ |
1195 | 0 | if (NULL == (lnk = (H5O_link_t *)H5O_msg_decode(udata->f, NULL, H5O_LINK_ID, obj_len, |
1196 | 0 | (const unsigned char *)obj))) |
1197 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link"); |
1198 | | |
1199 | | /* Check for removing the link from the creation order index */ |
1200 | 0 | if (H5_addr_defined(udata->corder_bt2_addr)) { |
1201 | 0 | H5G_bt2_ud_common_t bt2_udata; /* Info for B-tree callbacks */ |
1202 | | |
1203 | | /* Open the creation order index v2 B-tree */ |
1204 | 0 | if (NULL == (bt2 = H5B2_open(udata->f, udata->corder_bt2_addr, NULL))) |
1205 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index"); |
1206 | | |
1207 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1208 | 0 | assert(lnk->corder_valid); |
1209 | 0 | bt2_udata.corder = lnk->corder; |
1210 | | |
1211 | | /* Remove the record from the name index v2 B-tree */ |
1212 | 0 | if (H5B2_remove(bt2, &bt2_udata, NULL, NULL) < 0) |
1213 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, |
1214 | 0 | "unable to remove link from creation order index v2 B-tree"); |
1215 | 0 | } /* end if */ |
1216 | | |
1217 | | /* Replace open objects' names, if requested */ |
1218 | 0 | if (udata->replace_names) |
1219 | 0 | if (H5G__link_name_replace(udata->f, udata->grp_full_path_r, lnk) < 0) |
1220 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTRENAME, FAIL, "unable to rename open objects"); |
1221 | | |
1222 | | /* Perform the deletion action on the link, if requested */ |
1223 | | /* (call message "delete" callback directly: *ick* - QAK) */ |
1224 | 0 | if (H5O_link_delete(udata->f, NULL, lnk) < 0) |
1225 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link"); |
1226 | | |
1227 | 0 | done: |
1228 | | /* Release resources */ |
1229 | 0 | if (bt2 && H5B2_close(bt2) < 0) |
1230 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index"); |
1231 | 0 | if (lnk) |
1232 | 0 | H5O_msg_free(H5O_LINK_ID, lnk); |
1233 | |
|
1234 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1235 | 0 | } /* end H5G__dense_remove_fh_cb() */ |
1236 | | |
1237 | | /*------------------------------------------------------------------------- |
1238 | | * Function: H5G__dense_remove_bt2_cb |
1239 | | * |
1240 | | * Purpose: v2 B-tree callback for dense link storage record removal |
1241 | | * |
1242 | | * Return: Non-negative on success/Negative on failure |
1243 | | * |
1244 | | *------------------------------------------------------------------------- |
1245 | | */ |
1246 | | static herr_t |
1247 | | H5G__dense_remove_bt2_cb(const void *_record, void *_bt2_udata) |
1248 | 0 | { |
1249 | 0 | const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record; |
1250 | 0 | H5G_bt2_ud_rm_t *bt2_udata = (H5G_bt2_ud_rm_t *)_bt2_udata; /* User data for callback */ |
1251 | 0 | H5G_fh_ud_rm_t fh_udata; /* User data for fractal heap 'op' callback */ |
1252 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1253 | |
|
1254 | 0 | FUNC_ENTER_PACKAGE |
1255 | | |
1256 | | /* Set up the user data for fractal heap 'op' callback */ |
1257 | 0 | fh_udata.f = bt2_udata->common.f; |
1258 | 0 | fh_udata.corder_bt2_addr = bt2_udata->corder_bt2_addr; |
1259 | 0 | fh_udata.grp_full_path_r = bt2_udata->grp_full_path_r; |
1260 | 0 | fh_udata.replace_names = bt2_udata->replace_names; |
1261 | | |
1262 | | /* Call fractal heap 'op' routine, to perform user callback */ |
1263 | 0 | if (H5HF_op(bt2_udata->common.fheap, record->id, H5G__dense_remove_fh_cb, &fh_udata) < 0) |
1264 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, FAIL, "link removal callback failed"); |
1265 | | |
1266 | | /* Remove record from fractal heap, if requested */ |
1267 | 0 | if (bt2_udata->rem_from_fheap) |
1268 | 0 | if (H5HF_remove(bt2_udata->common.fheap, record->id) < 0) |
1269 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from fractal heap"); |
1270 | | |
1271 | 0 | done: |
1272 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1273 | 0 | } /* end H5G__dense_remove_bt2_cb() */ |
1274 | | |
1275 | | /*------------------------------------------------------------------------- |
1276 | | * Function: H5G__dense_remove |
1277 | | * |
1278 | | * Purpose: Remove a link from the dense storage of a group |
1279 | | * |
1280 | | * Return: Non-negative on success/Negative on failure |
1281 | | * |
1282 | | *------------------------------------------------------------------------- |
1283 | | */ |
1284 | | herr_t |
1285 | | H5G__dense_remove(H5F_t *f, const H5O_linfo_t *linfo, H5RS_str_t *grp_full_path_r, const char *name) |
1286 | 0 | { |
1287 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
1288 | 0 | H5G_bt2_ud_rm_t udata; /* User data for v2 B-tree record removal */ |
1289 | 0 | H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */ |
1290 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1291 | |
|
1292 | 0 | FUNC_ENTER_PACKAGE |
1293 | | |
1294 | | /* |
1295 | | * Check arguments. |
1296 | | */ |
1297 | 0 | assert(f); |
1298 | 0 | assert(linfo); |
1299 | 0 | assert(name && *name); |
1300 | | |
1301 | | /* Open the fractal heap */ |
1302 | 0 | if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr))) |
1303 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1304 | | |
1305 | | /* Open the name index v2 B-tree */ |
1306 | 0 | if (NULL == (bt2 = H5B2_open(f, linfo->name_bt2_addr, NULL))) |
1307 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index"); |
1308 | | |
1309 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1310 | 0 | udata.common.f = f; |
1311 | 0 | udata.common.fheap = fheap; |
1312 | 0 | udata.common.name = name; |
1313 | 0 | udata.common.name_hash = H5_checksum_lookup3(name, strlen(name), 0); |
1314 | 0 | udata.common.found_op = NULL; |
1315 | 0 | udata.common.found_op_data = NULL; |
1316 | 0 | udata.rem_from_fheap = true; |
1317 | 0 | udata.corder_bt2_addr = linfo->corder_bt2_addr; |
1318 | 0 | udata.grp_full_path_r = grp_full_path_r; |
1319 | 0 | udata.replace_names = true; |
1320 | | |
1321 | | /* Remove the record from the name index v2 B-tree */ |
1322 | 0 | if (H5B2_remove(bt2, &udata, H5G__dense_remove_bt2_cb, &udata) < 0) |
1323 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from name index v2 B-tree"); |
1324 | | |
1325 | 0 | done: |
1326 | | /* Release resources */ |
1327 | 0 | if (fheap && H5HF_close(fheap) < 0) |
1328 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1329 | 0 | if (bt2 && H5B2_close(bt2) < 0) |
1330 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
1331 | |
|
1332 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1333 | 0 | } /* end H5G__dense_remove() */ |
1334 | | |
1335 | | /*------------------------------------------------------------------------- |
1336 | | * Function: H5G__dense_remove_by_idx_fh_cb |
1337 | | * |
1338 | | * Purpose: Callback for fractal heap operator when removing links by index |
1339 | | * |
1340 | | * Return: SUCCEED/FAIL |
1341 | | * |
1342 | | *------------------------------------------------------------------------- |
1343 | | */ |
1344 | | static herr_t |
1345 | | H5G__dense_remove_by_idx_fh_cb(const void *obj, size_t obj_len, void *_udata) |
1346 | 0 | { |
1347 | 0 | H5G_fh_ud_rmbi_t *udata = (H5G_fh_ud_rmbi_t *)_udata; /* User data for fractal heap 'op' callback */ |
1348 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1349 | |
|
1350 | 0 | FUNC_ENTER_PACKAGE |
1351 | | |
1352 | | /* Decode link information */ |
1353 | 0 | if (NULL == (udata->lnk = (H5O_link_t *)H5O_msg_decode(udata->f, NULL, H5O_LINK_ID, obj_len, |
1354 | 0 | (const unsigned char *)obj))) |
1355 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, H5_ITER_ERROR, "can't decode link"); |
1356 | | |
1357 | | /* Can't operate on link here because the fractal heap block is locked */ |
1358 | | |
1359 | 0 | done: |
1360 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1361 | 0 | } /* end H5G__dense_remove_by_idx_fh_cb() */ |
1362 | | |
1363 | | /*------------------------------------------------------------------------- |
1364 | | * Function: H5G__dense_remove_by_idx_bt2_cb |
1365 | | * |
1366 | | * Purpose: v2 B-tree callback for dense link storage record removal by index |
1367 | | * |
1368 | | * Return: Non-negative on success/Negative on failure |
1369 | | * |
1370 | | *------------------------------------------------------------------------- |
1371 | | */ |
1372 | | static herr_t |
1373 | | H5G__dense_remove_by_idx_bt2_cb(const void *_record, void *_bt2_udata) |
1374 | 0 | { |
1375 | 0 | H5G_bt2_ud_rmbi_t *bt2_udata = (H5G_bt2_ud_rmbi_t *)_bt2_udata; /* User data for callback */ |
1376 | 0 | H5G_fh_ud_rmbi_t fh_udata; /* User data for fractal heap 'op' callback */ |
1377 | 0 | H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */ |
1378 | 0 | const uint8_t *heap_id; /* Heap ID for link */ |
1379 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1380 | |
|
1381 | 0 | FUNC_ENTER_PACKAGE |
1382 | | |
1383 | | /* Determine the index being used */ |
1384 | 0 | if (bt2_udata->idx_type == H5_INDEX_NAME) { |
1385 | 0 | const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record; |
1386 | | |
1387 | | /* Set the heap ID to operate on */ |
1388 | 0 | heap_id = record->id; |
1389 | 0 | } /* end if */ |
1390 | 0 | else { |
1391 | 0 | const H5G_dense_bt2_corder_rec_t *record = (const H5G_dense_bt2_corder_rec_t *)_record; |
1392 | |
|
1393 | 0 | assert(bt2_udata->idx_type == H5_INDEX_CRT_ORDER); |
1394 | | |
1395 | | /* Set the heap ID to operate on */ |
1396 | 0 | heap_id = record->id; |
1397 | 0 | } /* end else */ |
1398 | | |
1399 | | /* Set up the user data for fractal heap 'op' callback */ |
1400 | 0 | fh_udata.f = bt2_udata->f; |
1401 | 0 | fh_udata.lnk = NULL; |
1402 | | |
1403 | | /* Call fractal heap 'op' routine, to perform user callback */ |
1404 | 0 | if (H5HF_op(bt2_udata->fheap, heap_id, H5G__dense_remove_by_idx_fh_cb, &fh_udata) < 0) |
1405 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, FAIL, "link removal callback failed"); |
1406 | 0 | assert(fh_udata.lnk); |
1407 | | |
1408 | | /* Check for removing the link from the "other" index (creation order, when name used and vice versa) */ |
1409 | 0 | if (H5_addr_defined(bt2_udata->other_bt2_addr)) { |
1410 | 0 | H5G_bt2_ud_common_t other_bt2_udata; /* Info for B-tree callbacks */ |
1411 | | |
1412 | | /* Determine the index being used */ |
1413 | 0 | if (bt2_udata->idx_type == H5_INDEX_NAME) { |
1414 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1415 | 0 | other_bt2_udata.corder = fh_udata.lnk->corder; |
1416 | 0 | } /* end if */ |
1417 | 0 | else { |
1418 | 0 | assert(bt2_udata->idx_type == H5_INDEX_CRT_ORDER); |
1419 | | |
1420 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1421 | 0 | other_bt2_udata.f = bt2_udata->f; |
1422 | 0 | other_bt2_udata.fheap = bt2_udata->fheap; |
1423 | 0 | other_bt2_udata.name = fh_udata.lnk->name; |
1424 | 0 | other_bt2_udata.name_hash = |
1425 | 0 | H5_checksum_lookup3(fh_udata.lnk->name, strlen(fh_udata.lnk->name), 0); |
1426 | 0 | other_bt2_udata.found_op = NULL; |
1427 | 0 | other_bt2_udata.found_op_data = NULL; |
1428 | 0 | } /* end else */ |
1429 | | |
1430 | | /* Open the index v2 B-tree */ |
1431 | 0 | if (NULL == (bt2 = H5B2_open(bt2_udata->f, bt2_udata->other_bt2_addr, NULL))) |
1432 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for 'other' index"); |
1433 | | |
1434 | | /* Set the common information for the v2 B-tree remove operation */ |
1435 | | |
1436 | | /* Remove the record from the name index v2 B-tree */ |
1437 | 0 | if (H5B2_remove(bt2, &other_bt2_udata, NULL, NULL) < 0) |
1438 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, H5_ITER_ERROR, |
1439 | 0 | "unable to remove link from 'other' index v2 B-tree"); |
1440 | 0 | } /* end if */ |
1441 | | |
1442 | | /* Replace open objects' names */ |
1443 | 0 | if (H5G__link_name_replace(bt2_udata->f, bt2_udata->grp_full_path_r, fh_udata.lnk) < 0) |
1444 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTRENAME, FAIL, "unable to rename open objects"); |
1445 | | |
1446 | | /* Perform the deletion action on the link */ |
1447 | | /* (call link message "delete" callback directly: *ick* - QAK) */ |
1448 | 0 | if (H5O_link_delete(bt2_udata->f, NULL, fh_udata.lnk) < 0) |
1449 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link"); |
1450 | | |
1451 | | /* Release the space allocated for the link */ |
1452 | 0 | H5O_msg_free(H5O_LINK_ID, fh_udata.lnk); |
1453 | | |
1454 | | /* Remove record from fractal heap */ |
1455 | 0 | if (H5HF_remove(bt2_udata->fheap, heap_id) < 0) |
1456 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from fractal heap"); |
1457 | | |
1458 | 0 | done: |
1459 | | /* Release resources */ |
1460 | 0 | if (bt2 && H5B2_close(bt2) < 0) |
1461 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for 'other' index"); |
1462 | |
|
1463 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1464 | 0 | } /* end H5G__dense_remove_by_idx_bt2_cb() */ |
1465 | | |
1466 | | /*------------------------------------------------------------------------- |
1467 | | * Function: H5G__dense_remove_by_idx |
1468 | | * |
1469 | | * Purpose: Remove a link from the dense storage of a group, according to |
1470 | | * to the offset in an indexed order |
1471 | | * |
1472 | | * Return: Non-negative on success/Negative on failure |
1473 | | * |
1474 | | *------------------------------------------------------------------------- |
1475 | | */ |
1476 | | herr_t |
1477 | | H5G__dense_remove_by_idx(H5F_t *f, const H5O_linfo_t *linfo, H5RS_str_t *grp_full_path_r, H5_index_t idx_type, |
1478 | | H5_iter_order_t order, hsize_t n) |
1479 | 0 | { |
1480 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
1481 | 0 | H5G_link_table_t ltable = {0, NULL}; /* Table of links */ |
1482 | 0 | H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */ |
1483 | 0 | haddr_t bt2_addr; /* Address of v2 B-tree to use for lookup */ |
1484 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1485 | |
|
1486 | 0 | FUNC_ENTER_PACKAGE |
1487 | | |
1488 | | /* |
1489 | | * Check arguments. |
1490 | | */ |
1491 | 0 | assert(f); |
1492 | 0 | assert(linfo); |
1493 | | |
1494 | | /* Determine the address of the index to use */ |
1495 | 0 | if (idx_type == H5_INDEX_NAME) { |
1496 | | /* Since names are hashed, getting them in strictly increasing or |
1497 | | * decreasing order requires building a table and sorting it. If |
1498 | | * the order is native, use the B-tree for names. |
1499 | | */ |
1500 | 0 | bt2_addr = HADDR_UNDEF; |
1501 | 0 | } /* end if */ |
1502 | 0 | else { |
1503 | 0 | assert(idx_type == H5_INDEX_CRT_ORDER); |
1504 | | |
1505 | | /* This address may not be defined if creation order is tracked, but |
1506 | | * there's no index on it. If there's no v2 B-tree that indexes |
1507 | | * the links and the order is native, use the B-tree for names. |
1508 | | * Otherwise, build a table. |
1509 | | */ |
1510 | 0 | bt2_addr = linfo->corder_bt2_addr; |
1511 | 0 | } /* end else */ |
1512 | | |
1513 | | /* If the order is native and there's no B-tree for indexing the links, |
1514 | | * use the B-tree for names instead of building a table to speed up the |
1515 | | * process. |
1516 | | */ |
1517 | 0 | if (order == H5_ITER_NATIVE && !H5_addr_defined(bt2_addr)) { |
1518 | 0 | bt2_addr = linfo->name_bt2_addr; |
1519 | 0 | assert(H5_addr_defined(bt2_addr)); |
1520 | 0 | } /* end if */ |
1521 | | |
1522 | | /* If there is an index defined for the field, use it */ |
1523 | 0 | if (H5_addr_defined(bt2_addr)) { |
1524 | 0 | H5G_bt2_ud_rmbi_t udata; /* User data for v2 B-tree record removal */ |
1525 | | |
1526 | | /* Open the fractal heap */ |
1527 | 0 | if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr))) |
1528 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1529 | | |
1530 | | /* Open the index v2 B-tree */ |
1531 | 0 | if (NULL == (bt2 = H5B2_open(f, bt2_addr, NULL))) |
1532 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index"); |
1533 | | |
1534 | | /* Set up the user data for the v2 B-tree 'remove by index' callback */ |
1535 | 0 | udata.f = f; |
1536 | 0 | udata.fheap = fheap; |
1537 | 0 | udata.idx_type = idx_type; |
1538 | 0 | udata.other_bt2_addr = idx_type == H5_INDEX_NAME ? linfo->corder_bt2_addr : linfo->name_bt2_addr; |
1539 | 0 | udata.grp_full_path_r = grp_full_path_r; |
1540 | | |
1541 | | /* Remove the record from the name index v2 B-tree */ |
1542 | 0 | if (H5B2_remove_by_idx(bt2, order, n, H5G__dense_remove_by_idx_bt2_cb, &udata) < 0) |
1543 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from indexed v2 B-tree"); |
1544 | 0 | } /* end if */ |
1545 | 0 | else { /* Otherwise, we need to build a table of the links and sort it */ |
1546 | | /* Build the table of links for this group */ |
1547 | 0 | if (H5G__dense_build_table(f, linfo, idx_type, order, <able) < 0) |
1548 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links"); |
1549 | | |
1550 | | /* Check for going out of bounds */ |
1551 | 0 | if (n >= ltable.nlinks) |
1552 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound"); |
1553 | | |
1554 | | /* Remove the appropriate link from the dense storage */ |
1555 | 0 | if (H5G__dense_remove(f, linfo, grp_full_path_r, ltable.lnks[n].name) < 0) |
1556 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from dense storage"); |
1557 | 0 | } /* end else */ |
1558 | | |
1559 | 0 | done: |
1560 | | /* Release resources */ |
1561 | 0 | if (fheap && H5HF_close(fheap) < 0) |
1562 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1563 | 0 | if (bt2 && H5B2_close(bt2) < 0) |
1564 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index"); |
1565 | 0 | if (ltable.lnks && H5G__link_release_table(<able) < 0) |
1566 | 0 | HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table"); |
1567 | |
|
1568 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1569 | 0 | } /* end H5G__dense_remove_by_idx() */ |
1570 | | |
1571 | | /*------------------------------------------------------------------------- |
1572 | | * Function: H5G__dense_delete |
1573 | | * |
1574 | | * Purpose: Delete the dense storage for a group |
1575 | | * |
1576 | | * Return: Non-negative on success/Negative on failure |
1577 | | * |
1578 | | *------------------------------------------------------------------------- |
1579 | | */ |
1580 | | herr_t |
1581 | | H5G__dense_delete(H5F_t *f, H5O_linfo_t *linfo, bool adj_link) |
1582 | 0 | { |
1583 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1584 | |
|
1585 | 0 | FUNC_ENTER_PACKAGE |
1586 | | |
1587 | | /* |
1588 | | * Check arguments. |
1589 | | */ |
1590 | 0 | assert(f); |
1591 | 0 | assert(linfo); |
1592 | | |
1593 | | /* Check if we are to adjust the ref. count for all the links */ |
1594 | | /* (we adjust the ref. count when deleting a group and we _don't_ adjust |
1595 | | * the ref. count when transitioning back to compact storage) |
1596 | | */ |
1597 | 0 | if (adj_link) { |
1598 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
1599 | 0 | H5G_bt2_ud_rm_t udata; /* User data for v2 B-tree record removal */ |
1600 | | |
1601 | | /* Open the fractal heap */ |
1602 | 0 | if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr))) |
1603 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1604 | | |
1605 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1606 | 0 | udata.common.f = f; |
1607 | 0 | udata.common.fheap = fheap; |
1608 | 0 | udata.common.name = NULL; |
1609 | 0 | udata.common.name_hash = 0; |
1610 | 0 | udata.common.found_op = NULL; |
1611 | 0 | udata.common.found_op_data = NULL; |
1612 | 0 | udata.rem_from_fheap = false; /* handled in "bulk" below by deleting entire heap */ |
1613 | 0 | udata.corder_bt2_addr = linfo->corder_bt2_addr; |
1614 | 0 | udata.grp_full_path_r = NULL; |
1615 | 0 | udata.replace_names = false; |
1616 | | |
1617 | | /* Delete the name index, adjusting the ref. count on links removed */ |
1618 | 0 | if (H5B2_delete(f, linfo->name_bt2_addr, NULL, H5G__dense_remove_bt2_cb, &udata) < 0) |
1619 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for name index"); |
1620 | | |
1621 | | /* Close the fractal heap */ |
1622 | 0 | if (H5HF_close(fheap) < 0) |
1623 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1624 | 0 | } /* end if */ |
1625 | 0 | else { |
1626 | | /* Delete the name index, without adjusting the ref. count on the links */ |
1627 | 0 | if (H5B2_delete(f, linfo->name_bt2_addr, NULL, NULL, NULL) < 0) |
1628 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for name index"); |
1629 | 0 | } /* end else */ |
1630 | 0 | linfo->name_bt2_addr = HADDR_UNDEF; |
1631 | | |
1632 | | /* Check if we should delete the creation order index v2 B-tree */ |
1633 | 0 | if (linfo->index_corder) { |
1634 | | /* Delete the creation order index, without adjusting the ref. count on the links */ |
1635 | 0 | assert(H5_addr_defined(linfo->corder_bt2_addr)); |
1636 | 0 | if (H5B2_delete(f, linfo->corder_bt2_addr, NULL, NULL, NULL) < 0) |
1637 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for creation order index"); |
1638 | 0 | linfo->corder_bt2_addr = HADDR_UNDEF; |
1639 | 0 | } /* end if */ |
1640 | 0 | else |
1641 | 0 | assert(!H5_addr_defined(linfo->corder_bt2_addr)); |
1642 | | |
1643 | | /* Delete the fractal heap */ |
1644 | 0 | if (H5HF_delete(f, linfo->fheap_addr) < 0) |
1645 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete fractal heap"); |
1646 | 0 | linfo->fheap_addr = HADDR_UNDEF; |
1647 | |
|
1648 | 0 | done: |
1649 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1650 | 0 | } /* end H5G__dense_delete() */ |