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: H5Adense.c |
16 | | * |
17 | | * Purpose: Routines for operating on "dense" attribute storage |
18 | | * for an object. |
19 | | * |
20 | | *------------------------------------------------------------------------- |
21 | | */ |
22 | | |
23 | | /****************/ |
24 | | /* Module Setup */ |
25 | | /****************/ |
26 | | |
27 | | #include "H5Amodule.h" /* This source code file is part of the H5A module */ |
28 | | #define H5O_FRIEND /*suppress error about including H5Opkg */ |
29 | | |
30 | | /***********/ |
31 | | /* Headers */ |
32 | | /***********/ |
33 | | #include "H5private.h" /* Generic Functions */ |
34 | | #include "H5Apkg.h" /* Attributes */ |
35 | | #include "H5Eprivate.h" /* Error handling */ |
36 | | #include "H5FLprivate.h" /* Free Lists */ |
37 | | #include "H5MMprivate.h" /* Memory management */ |
38 | | #include "H5Opkg.h" /* Object headers */ |
39 | | #include "H5SMprivate.h" /* Shared object header messages */ |
40 | | #include "H5WBprivate.h" /* Wrapped Buffers */ |
41 | | |
42 | | /****************/ |
43 | | /* Local Macros */ |
44 | | /****************/ |
45 | | |
46 | | /* v2 B-tree creation macros for 'name' field index */ |
47 | 0 | #define H5A_NAME_BT2_NODE_SIZE 512 |
48 | 0 | #define H5A_NAME_BT2_MERGE_PERC 40 |
49 | 0 | #define H5A_NAME_BT2_SPLIT_PERC 100 |
50 | | |
51 | | /* v2 B-tree creation macros for 'corder' field index */ |
52 | 0 | #define H5A_CORDER_BT2_NODE_SIZE 512 |
53 | 0 | #define H5A_CORDER_BT2_MERGE_PERC 40 |
54 | 0 | #define H5A_CORDER_BT2_SPLIT_PERC 100 |
55 | | |
56 | | /* Size of stack buffer for serialized attributes */ |
57 | | #define H5A_ATTR_BUF_SIZE 128 |
58 | | |
59 | | /******************/ |
60 | | /* Local Typedefs */ |
61 | | /******************/ |
62 | | |
63 | | /* |
64 | | * Data exchange structure for dense attribute storage. This structure is |
65 | | * passed through the v2 B-tree layer when modifying the attribute data value. |
66 | | */ |
67 | | typedef struct H5A_bt2_od_wrt_t { |
68 | | /* downward */ |
69 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
70 | | H5HF_t *fheap; /* Fractal heap handle to operate on */ |
71 | | H5HF_t *shared_fheap; /* Fractal heap handle for shared messages */ |
72 | | H5A_t *attr; /* Attribute to write */ |
73 | | haddr_t corder_bt2_addr; /* v2 B-tree address of creation order index */ |
74 | | } H5A_bt2_od_wrt_t; |
75 | | |
76 | | /* |
77 | | * Data exchange structure to pass through the v2 B-tree layer for the |
78 | | * H5B2_iterate function when iterating over densely stored attributes. |
79 | | */ |
80 | | typedef struct { |
81 | | /* downward (internal) */ |
82 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
83 | | H5HF_t *fheap; /* Fractal heap handle */ |
84 | | H5HF_t *shared_fheap; /* Fractal heap handle for shared messages */ |
85 | | hsize_t count; /* # of attributes examined */ |
86 | | |
87 | | /* downward (from application) */ |
88 | | hid_t loc_id; /* Object ID for application callback */ |
89 | | hsize_t skip; /* Number of attributes to skip */ |
90 | | const H5A_attr_iter_op_t *attr_op; /* Callback for each attribute */ |
91 | | void *op_data; /* Callback data for each attribute */ |
92 | | |
93 | | /* upward */ |
94 | | int op_ret; /* Return value from callback */ |
95 | | } H5A_bt2_ud_it_t; |
96 | | |
97 | | /* |
98 | | * Data exchange structure to pass through the fractal heap layer for the |
99 | | * H5HF_op function when copying an attribute stored in densely stored attributes. |
100 | | * (or the shared message heap) |
101 | | */ |
102 | | typedef struct { |
103 | | /* downward (internal) */ |
104 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
105 | | const H5A_dense_bt2_name_rec_t *record; /* v2 B-tree record for attribute */ |
106 | | |
107 | | /* upward */ |
108 | | H5A_t *attr; /* Copy of attribute */ |
109 | | } H5A_fh_ud_cp_t; |
110 | | |
111 | | /* |
112 | | * Data exchange structure for dense attribute storage. This structure is |
113 | | * passed through the v2 B-tree layer when removing attributes. |
114 | | */ |
115 | | typedef struct H5A_bt2_ud_rm_t { |
116 | | /* downward */ |
117 | | H5A_bt2_ud_common_t common; /* Common info for B-tree user data (must be first) */ |
118 | | haddr_t corder_bt2_addr; /* v2 B-tree address of creation order index */ |
119 | | } H5A_bt2_ud_rm_t; |
120 | | |
121 | | /* |
122 | | * Data exchange structure for dense attribute storage. This structure is |
123 | | * passed through the v2 B-tree layer when removing attributes by index. |
124 | | */ |
125 | | typedef struct H5A_bt2_ud_rmbi_t { |
126 | | /* downward */ |
127 | | H5F_t *f; /* Pointer to file that fractal heap is in */ |
128 | | H5HF_t *fheap; /* Fractal heap handle */ |
129 | | H5HF_t *shared_fheap; /* Fractal heap handle for shared messages */ |
130 | | H5_index_t idx_type; /* Index type for operation */ |
131 | | haddr_t other_bt2_addr; /* v2 B-tree address of "other" index */ |
132 | | } H5A_bt2_ud_rmbi_t; |
133 | | |
134 | | /********************/ |
135 | | /* Package Typedefs */ |
136 | | /********************/ |
137 | | |
138 | | /********************/ |
139 | | /* Local Prototypes */ |
140 | | /********************/ |
141 | | |
142 | | /*********************/ |
143 | | /* Package Variables */ |
144 | | /*********************/ |
145 | | |
146 | | /*****************************/ |
147 | | /* Library Private Variables */ |
148 | | /*****************************/ |
149 | | |
150 | | /*******************/ |
151 | | /* Local Variables */ |
152 | | /*******************/ |
153 | | |
154 | | /*------------------------------------------------------------------------- |
155 | | * Function: H5A__dense_create |
156 | | * |
157 | | * Purpose: Creates dense attribute storage structures for an object |
158 | | * |
159 | | * Return: SUCCEED/FAIL |
160 | | * |
161 | | *------------------------------------------------------------------------- |
162 | | */ |
163 | | herr_t |
164 | | H5A__dense_create(H5F_t *f, H5O_ainfo_t *ainfo) |
165 | 0 | { |
166 | 0 | H5HF_create_t fheap_cparam; /* Fractal heap creation parameters */ |
167 | 0 | H5B2_create_t bt2_cparam; /* v2 B-tree creation parameters */ |
168 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
169 | 0 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for names */ |
170 | 0 | H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order */ |
171 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
172 | |
|
173 | 0 | FUNC_ENTER_PACKAGE |
174 | | |
175 | | /* Check arguments */ |
176 | 0 | assert(f); |
177 | 0 | assert(ainfo); |
178 | | |
179 | | /* Set fractal heap creation parameters */ |
180 | | /* XXX: Give some control of these to applications? */ |
181 | 0 | memset(&fheap_cparam, 0, sizeof(fheap_cparam)); |
182 | 0 | fheap_cparam.managed.width = H5O_FHEAP_MAN_WIDTH; |
183 | 0 | fheap_cparam.managed.start_block_size = H5O_FHEAP_MAN_START_BLOCK_SIZE; |
184 | 0 | fheap_cparam.managed.max_direct_size = H5O_FHEAP_MAN_MAX_DIRECT_SIZE; |
185 | 0 | fheap_cparam.managed.max_index = H5O_FHEAP_MAN_MAX_INDEX; |
186 | 0 | fheap_cparam.managed.start_root_rows = H5O_FHEAP_MAN_START_ROOT_ROWS; |
187 | 0 | fheap_cparam.checksum_dblocks = H5O_FHEAP_CHECKSUM_DBLOCKS; |
188 | 0 | fheap_cparam.max_man_size = H5O_FHEAP_MAX_MAN_SIZE; |
189 | | |
190 | | /* Create fractal heap for storing attributes */ |
191 | 0 | if (NULL == (fheap = H5HF_create(f, &fheap_cparam))) |
192 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to create fractal heap"); |
193 | | |
194 | | /* Retrieve the heap's address in the file */ |
195 | 0 | if (H5HF_get_heap_addr(fheap, &ainfo->fheap_addr) < 0) |
196 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGETSIZE, FAIL, "can't get fractal heap address"); |
197 | | |
198 | | #ifndef NDEBUG |
199 | | { |
200 | | size_t fheap_id_len; /* Fractal heap ID length */ |
201 | | |
202 | | /* Retrieve the heap's ID length in the file */ |
203 | | if (H5HF_get_id_len(fheap, &fheap_id_len) < 0) |
204 | | HGOTO_ERROR(H5E_ATTR, H5E_CANTGETSIZE, FAIL, "can't get fractal heap ID length"); |
205 | | assert(fheap_id_len == H5O_FHEAP_ID_LEN); |
206 | | } |
207 | | #endif /* NDEBUG */ |
208 | | |
209 | | /* Create the name index v2 B-tree */ |
210 | 0 | memset(&bt2_cparam, 0, sizeof(bt2_cparam)); |
211 | 0 | bt2_cparam.cls = H5A_BT2_NAME; |
212 | 0 | bt2_cparam.node_size = (size_t)H5A_NAME_BT2_NODE_SIZE; |
213 | 0 | bt2_cparam.rrec_size = 4 + /* Name's hash value */ |
214 | 0 | 4 + /* Creation order index */ |
215 | 0 | 1 + /* Message flags */ |
216 | 0 | H5O_FHEAP_ID_LEN; /* Fractal heap ID */ |
217 | 0 | bt2_cparam.split_percent = H5A_NAME_BT2_SPLIT_PERC; |
218 | 0 | bt2_cparam.merge_percent = H5A_NAME_BT2_MERGE_PERC; |
219 | 0 | if (NULL == (bt2_name = H5B2_create(f, &bt2_cparam, NULL))) |
220 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to create v2 B-tree for name index"); |
221 | | |
222 | | /* Retrieve the v2 B-tree's address in the file */ |
223 | 0 | if (H5B2_get_addr(bt2_name, &ainfo->name_bt2_addr) < 0) |
224 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get v2 B-tree address for name index"); |
225 | | |
226 | | /* Check if we should create a creation order index v2 B-tree */ |
227 | 0 | if (ainfo->index_corder) { |
228 | | /* Create the creation order index v2 B-tree */ |
229 | 0 | memset(&bt2_cparam, 0, sizeof(bt2_cparam)); |
230 | 0 | bt2_cparam.cls = H5A_BT2_CORDER; |
231 | 0 | bt2_cparam.node_size = (size_t)H5A_CORDER_BT2_NODE_SIZE; |
232 | 0 | bt2_cparam.rrec_size = 4 + /* Creation order index */ |
233 | 0 | 1 + /* Message flags */ |
234 | 0 | H5O_FHEAP_ID_LEN; /* Fractal heap ID */ |
235 | 0 | bt2_cparam.split_percent = H5A_CORDER_BT2_SPLIT_PERC; |
236 | 0 | bt2_cparam.merge_percent = H5A_CORDER_BT2_MERGE_PERC; |
237 | 0 | if (NULL == (bt2_corder = H5B2_create(f, &bt2_cparam, NULL))) |
238 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "unable to create v2 B-tree for creation order index"); |
239 | | |
240 | | /* Retrieve the v2 B-tree's address in the file */ |
241 | 0 | if (H5B2_get_addr(bt2_corder, &ainfo->corder_bt2_addr) < 0) |
242 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get v2 B-tree address for creation order index"); |
243 | 0 | } /* end if */ |
244 | | |
245 | 0 | done: |
246 | | /* Release resources */ |
247 | 0 | if (fheap && H5HF_close(fheap) < 0) |
248 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
249 | 0 | if (bt2_name && H5B2_close(bt2_name) < 0) |
250 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
251 | 0 | if (bt2_corder && H5B2_close(bt2_corder) < 0) |
252 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index"); |
253 | |
|
254 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
255 | 0 | } /* end H5A__dense_create() */ |
256 | | |
257 | | /*------------------------------------------------------------------------- |
258 | | * Function: H5A__dense_fnd_cb |
259 | | * |
260 | | * Purpose: Callback when an attribute is located in an index |
261 | | * |
262 | | * Return: SUCCEED/FAIL |
263 | | * |
264 | | *------------------------------------------------------------------------- |
265 | | */ |
266 | | static herr_t |
267 | | H5A__dense_fnd_cb(const H5A_t *attr, bool *took_ownership, void *_user_attr) |
268 | 0 | { |
269 | 0 | const H5A_t **user_attr = (const H5A_t **)_user_attr; /* User data from v2 B-tree attribute lookup */ |
270 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
271 | |
|
272 | 0 | FUNC_ENTER_PACKAGE |
273 | | |
274 | | /* Check arguments */ |
275 | 0 | assert(attr); |
276 | 0 | assert(user_attr); |
277 | 0 | assert(took_ownership); |
278 | | |
279 | | /* |
280 | | * If there is an attribute already stored in "user_attr", |
281 | | * we need to free the dynamially allocated spaces for the |
282 | | * attribute, otherwise we got infinite loop closing library due to |
283 | | * outstanding allocation. (HDFFV-10659) |
284 | | * |
285 | | * This callback is used by H5A__dense_remove() to close/free the |
286 | | * attribute stored in "user_attr" (via H5O__msg_free_real()) after |
287 | | * the attribute node is deleted from the name index v2 B-tree. |
288 | | * The issue is: |
289 | | * When deleting the attribute node from the B-tree, |
290 | | * if the attribute is found in the intermediate B-tree nodes, |
291 | | * which may be merged/redistributed, we need to free the dynamically |
292 | | * allocated spaces for the intermediate decoded attribute. |
293 | | */ |
294 | 0 | if (*user_attr != NULL) { |
295 | 0 | H5A_t *old_attr = *(H5A_t **)_user_attr; |
296 | | |
297 | | /* Free any dynamically allocated items */ |
298 | 0 | if (old_attr->shared) |
299 | 0 | if (H5A__shared_free(old_attr) < 0) |
300 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTRELEASE, FAIL, "can't release attribute info"); |
301 | | |
302 | 0 | old_attr = H5FL_FREE(H5A_t, old_attr); |
303 | 0 | } /* end if */ |
304 | | |
305 | | /* Take over attribute ownership */ |
306 | 0 | *user_attr = attr; |
307 | 0 | *took_ownership = true; |
308 | |
|
309 | 0 | done: |
310 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
311 | 0 | } /* end H5A__dense_fnd_cb() */ |
312 | | |
313 | | /*------------------------------------------------------------------------- |
314 | | * Function: H5A__dense_open |
315 | | * |
316 | | * Purpose: Open an attribute in dense storage structures for an object |
317 | | * |
318 | | * Return: SUCCEED/FAIL |
319 | | * |
320 | | *------------------------------------------------------------------------- |
321 | | */ |
322 | | H5A_t * |
323 | | H5A__dense_open(H5F_t *f, const H5O_ainfo_t *ainfo, const char *name) |
324 | 0 | { |
325 | 0 | H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */ |
326 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
327 | 0 | H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */ |
328 | 0 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */ |
329 | 0 | htri_t attr_sharable; /* Flag indicating attributes are shareable */ |
330 | 0 | bool attr_exists; /* Attribute exists in v2 B-tree */ |
331 | 0 | H5A_t *ret_value = NULL; /* Return value */ |
332 | |
|
333 | 0 | FUNC_ENTER_PACKAGE |
334 | | |
335 | | /* Check arguments */ |
336 | 0 | assert(f); |
337 | 0 | assert(ainfo); |
338 | 0 | assert(name); |
339 | | |
340 | | /* Open the fractal heap */ |
341 | 0 | if (NULL == (fheap = H5HF_open(f, ainfo->fheap_addr))) |
342 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to open fractal heap"); |
343 | | |
344 | | /* Check if attributes are shared in this file */ |
345 | 0 | if ((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID)) < 0) |
346 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "can't determine if attributes are shared"); |
347 | | |
348 | | /* Get handle for shared message heap, if attributes are shareable */ |
349 | 0 | if (attr_sharable) { |
350 | 0 | haddr_t shared_fheap_addr; /* Address of fractal heap to use */ |
351 | | |
352 | | /* Retrieve the address of the shared message's fractal heap */ |
353 | 0 | if (H5SM_get_fheap_addr(f, H5O_ATTR_ID, &shared_fheap_addr) < 0) |
354 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, NULL, "can't get shared message heap address"); |
355 | | |
356 | | /* Check if there are any shared messages currently */ |
357 | 0 | if (H5_addr_defined(shared_fheap_addr)) { |
358 | | /* Open the fractal heap for shared header messages */ |
359 | 0 | if (NULL == (shared_fheap = H5HF_open(f, shared_fheap_addr))) |
360 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to open fractal heap"); |
361 | 0 | } /* end if */ |
362 | 0 | } /* end if */ |
363 | | |
364 | | /* Open the name index v2 B-tree */ |
365 | 0 | if (NULL == (bt2_name = H5B2_open(f, ainfo->name_bt2_addr, NULL))) |
366 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, NULL, "unable to open v2 B-tree for name index"); |
367 | | |
368 | | /* Create the "udata" information for v2 B-tree record find */ |
369 | 0 | udata.f = f; |
370 | 0 | udata.fheap = fheap; |
371 | 0 | udata.shared_fheap = shared_fheap; |
372 | 0 | udata.name = name; |
373 | 0 | udata.name_hash = H5_checksum_lookup3(name, strlen(name), 0); |
374 | 0 | udata.flags = 0; |
375 | 0 | udata.corder = 0; |
376 | 0 | udata.found_op = H5A__dense_fnd_cb; /* v2 B-tree comparison callback */ |
377 | 0 | udata.found_op_data = &ret_value; |
378 | | |
379 | | /* Find & copy the attribute in the 'name' index */ |
380 | 0 | attr_exists = false; |
381 | 0 | if (H5B2_find(bt2_name, &udata, &attr_exists, NULL, NULL) < 0) |
382 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "can't search for attribute in name index"); |
383 | 0 | if (attr_exists == false) |
384 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, NULL, "can't locate attribute in name index"); |
385 | | |
386 | 0 | done: |
387 | | /* Release resources */ |
388 | 0 | if (shared_fheap && H5HF_close(shared_fheap) < 0) |
389 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, NULL, "can't close fractal heap"); |
390 | 0 | if (fheap && H5HF_close(fheap) < 0) |
391 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, NULL, "can't close fractal heap"); |
392 | 0 | if (bt2_name && H5B2_close(bt2_name) < 0) |
393 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, NULL, "can't close v2 B-tree for name index"); |
394 | |
|
395 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
396 | 0 | } /* end H5A__dense_open() */ |
397 | | |
398 | | /*------------------------------------------------------------------------- |
399 | | * Function: H5A__dense_insert |
400 | | * |
401 | | * Purpose: Insert an attribute into dense storage structures for an object |
402 | | * |
403 | | * Return: SUCCEED/FAIL |
404 | | * |
405 | | *------------------------------------------------------------------------- |
406 | | */ |
407 | | herr_t |
408 | | H5A__dense_insert(H5F_t *f, const H5O_ainfo_t *ainfo, H5A_t *attr) |
409 | 0 | { |
410 | 0 | H5A_bt2_ud_ins_t udata; /* User data for v2 B-tree insertion */ |
411 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle for attributes */ |
412 | 0 | H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */ |
413 | 0 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */ |
414 | 0 | H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */ |
415 | 0 | H5WB_t *wb = NULL; /* Wrapped buffer for attribute data */ |
416 | 0 | uint8_t attr_buf[H5A_ATTR_BUF_SIZE]; /* Buffer for serializing message */ |
417 | 0 | unsigned mesg_flags = 0; /* Flags for storing message */ |
418 | 0 | htri_t attr_sharable; /* Flag indicating attributes are shareable */ |
419 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
420 | |
|
421 | 0 | FUNC_ENTER_PACKAGE |
422 | | |
423 | | /* Check arguments */ |
424 | 0 | assert(f); |
425 | 0 | assert(ainfo); |
426 | 0 | assert(attr); |
427 | | |
428 | | /* Check if attributes are shared in this file */ |
429 | 0 | if ((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID)) < 0) |
430 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared"); |
431 | | |
432 | | /* Get handle for shared message heap, if attributes are shareable */ |
433 | 0 | if (attr_sharable) { |
434 | 0 | haddr_t shared_fheap_addr; /* Address of fractal heap to use */ |
435 | 0 | htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */ |
436 | | |
437 | | /* Check if message is already shared */ |
438 | 0 | if ((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, attr)) < 0) |
439 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error determining if message is shared"); |
440 | 0 | else if (shared_mesg > 0) |
441 | | /* Mark the message as shared */ |
442 | 0 | mesg_flags |= H5O_MSG_FLAG_SHARED; |
443 | 0 | else { |
444 | | /* Should this attribute be written as a SOHM? */ |
445 | 0 | if (H5SM_try_share(f, NULL, 0, H5O_ATTR_ID, attr, &mesg_flags) < 0) |
446 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "error determining if message should be shared"); |
447 | | |
448 | | /* Attributes can't be "unique be shareable" yet */ |
449 | 0 | assert(!(mesg_flags & H5O_MSG_FLAG_SHAREABLE)); |
450 | 0 | } /* end else */ |
451 | | |
452 | | /* Retrieve the address of the shared message's fractal heap */ |
453 | 0 | if (H5SM_get_fheap_addr(f, H5O_ATTR_ID, &shared_fheap_addr) < 0) |
454 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address"); |
455 | | |
456 | | /* Check if there are any shared messages currently */ |
457 | 0 | if (H5_addr_defined(shared_fheap_addr)) { |
458 | | /* Open the fractal heap for shared header messages */ |
459 | 0 | if (NULL == (shared_fheap = H5HF_open(f, shared_fheap_addr))) |
460 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
461 | 0 | } /* end if */ |
462 | 0 | } /* end if */ |
463 | | |
464 | | /* Open the fractal heap */ |
465 | 0 | if (NULL == (fheap = H5HF_open(f, ainfo->fheap_addr))) |
466 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
467 | | |
468 | | /* Check for inserting shared attribute */ |
469 | 0 | if (mesg_flags & H5O_MSG_FLAG_SHARED) { |
470 | | /* Sanity check */ |
471 | 0 | assert(attr_sharable); |
472 | | |
473 | | /* Use heap ID for shared message heap */ |
474 | 0 | udata.id = attr->sh_loc.u.heap_id; |
475 | 0 | } /* end if */ |
476 | 0 | else { |
477 | 0 | void *attr_ptr; /* Pointer to serialized message */ |
478 | 0 | size_t attr_size; /* Size of serialized attribute in the heap */ |
479 | | |
480 | | /* Find out the size of buffer needed for serialized message */ |
481 | 0 | if ((attr_size = H5O_msg_raw_size(f, H5O_ATTR_ID, false, attr)) == 0) |
482 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGETSIZE, FAIL, "can't get message size"); |
483 | | |
484 | | /* Wrap the local buffer for serialized attributes */ |
485 | 0 | if (NULL == (wb = H5WB_wrap(attr_buf, sizeof(attr_buf)))) |
486 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't wrap buffer"); |
487 | | |
488 | | /* Get a pointer to a buffer that's large enough for attribute */ |
489 | 0 | if (NULL == (attr_ptr = H5WB_actual(wb, attr_size))) |
490 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_NOSPACE, FAIL, "can't get actual buffer"); |
491 | | |
492 | | /* Create serialized form of attribute or shared message */ |
493 | 0 | if (H5O_msg_encode(f, H5O_ATTR_ID, false, (unsigned char *)attr_ptr, attr) < 0) |
494 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTENCODE, FAIL, "can't encode attribute"); |
495 | | |
496 | | /* Insert the serialized attribute into the fractal heap */ |
497 | | /* (sets the heap ID in the user data) */ |
498 | 0 | if (H5HF_insert(fheap, attr_size, attr_ptr, &udata.id) < 0) |
499 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to insert attribute into fractal heap"); |
500 | 0 | } /* end else */ |
501 | | |
502 | | /* Open the name index v2 B-tree */ |
503 | 0 | if (NULL == (bt2_name = H5B2_open(f, ainfo->name_bt2_addr, NULL))) |
504 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index"); |
505 | | |
506 | | /* Create the callback information for v2 B-tree record insertion */ |
507 | 0 | udata.common.f = f; |
508 | 0 | udata.common.fheap = fheap; |
509 | 0 | udata.common.shared_fheap = shared_fheap; |
510 | 0 | udata.common.name = attr->shared->name; |
511 | 0 | udata.common.name_hash = H5_checksum_lookup3(attr->shared->name, strlen(attr->shared->name), 0); |
512 | 0 | H5_CHECKED_ASSIGN(udata.common.flags, uint8_t, mesg_flags, unsigned); |
513 | 0 | udata.common.corder = attr->shared->crt_idx; |
514 | 0 | udata.common.found_op = NULL; |
515 | 0 | udata.common.found_op_data = NULL; |
516 | | /* udata.id already set */ |
517 | | |
518 | | /* Insert attribute into 'name' tracking v2 B-tree */ |
519 | 0 | if (H5B2_insert(bt2_name, &udata) < 0) |
520 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to insert record into v2 B-tree"); |
521 | | |
522 | | /* Check if we should create a creation order index v2 B-tree record */ |
523 | 0 | if (ainfo->index_corder) { |
524 | | /* Open the creation order index v2 B-tree */ |
525 | 0 | assert(H5_addr_defined(ainfo->corder_bt2_addr)); |
526 | 0 | if (NULL == (bt2_corder = H5B2_open(f, ainfo->corder_bt2_addr, NULL))) |
527 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index"); |
528 | | |
529 | | /* Insert the record into the creation order index v2 B-tree */ |
530 | 0 | if (H5B2_insert(bt2_corder, &udata) < 0) |
531 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to insert record into v2 B-tree"); |
532 | 0 | } /* end if */ |
533 | | |
534 | 0 | done: |
535 | | /* Release resources */ |
536 | 0 | if (shared_fheap && H5HF_close(shared_fheap) < 0) |
537 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
538 | 0 | if (fheap && H5HF_close(fheap) < 0) |
539 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
540 | 0 | if (bt2_name && H5B2_close(bt2_name) < 0) |
541 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
542 | 0 | if (bt2_corder && H5B2_close(bt2_corder) < 0) |
543 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index"); |
544 | 0 | if (wb && H5WB_unwrap(wb) < 0) |
545 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer"); |
546 | |
|
547 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
548 | 0 | } /* end H5A__dense_insert() */ |
549 | | |
550 | | /*------------------------------------------------------------------------- |
551 | | * Function: H5A__dense_write_bt2_cb2 |
552 | | * |
553 | | * Purpose: v2 B-tree 'modify' callback to update the record for a creation |
554 | | * order index |
555 | | * |
556 | | * Return: SUCCEED/FAIL |
557 | | * |
558 | | *------------------------------------------------------------------------- |
559 | | */ |
560 | | static herr_t |
561 | | H5A__dense_write_bt2_cb2(void *_record, void *_op_data, bool *changed) |
562 | 0 | { |
563 | 0 | H5A_dense_bt2_corder_rec_t *record = (H5A_dense_bt2_corder_rec_t *)_record; /* Record from B-tree */ |
564 | 0 | H5O_fheap_id_t *new_heap_id = (H5O_fheap_id_t *)_op_data; /* "op data" from v2 B-tree modify */ |
565 | |
|
566 | 0 | FUNC_ENTER_PACKAGE_NOERR |
567 | | |
568 | | /* Check arguments */ |
569 | 0 | assert(record); |
570 | 0 | assert(new_heap_id); |
571 | | |
572 | | /* Update record's heap ID */ |
573 | 0 | record->id = *new_heap_id; |
574 | | |
575 | | /* Note that the record changed */ |
576 | 0 | *changed = true; |
577 | |
|
578 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
579 | 0 | } /* end H5A__dense_write_bt2_cb2() */ |
580 | | |
581 | | /*------------------------------------------------------------------------- |
582 | | * Function: H5A__dense_write_bt2_cb |
583 | | * |
584 | | * Purpose: v2 B-tree 'modify' callback to update the data for an attribute |
585 | | * |
586 | | * Return: SUCCEED/FAIL |
587 | | * |
588 | | *------------------------------------------------------------------------- |
589 | | */ |
590 | | static herr_t |
591 | | H5A__dense_write_bt2_cb(void *_record, void *_op_data, bool *changed) |
592 | 0 | { |
593 | 0 | H5A_dense_bt2_name_rec_t *record = (H5A_dense_bt2_name_rec_t *)_record; /* Record from B-tree */ |
594 | 0 | H5A_bt2_od_wrt_t *op_data = (H5A_bt2_od_wrt_t *)_op_data; /* "op data" from v2 B-tree modify */ |
595 | 0 | H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */ |
596 | 0 | H5WB_t *wb = NULL; /* Wrapped buffer for attribute data */ |
597 | 0 | uint8_t attr_buf[H5A_ATTR_BUF_SIZE]; /* Buffer for serializing attribute */ |
598 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
599 | |
|
600 | 0 | FUNC_ENTER_PACKAGE |
601 | | |
602 | | /* Check arguments */ |
603 | 0 | assert(record); |
604 | 0 | assert(op_data); |
605 | | |
606 | | /* Check for modifying shared attribute */ |
607 | 0 | if (record->flags & H5O_MSG_FLAG_SHARED) { |
608 | | /* Update the shared attribute in the SOHM info */ |
609 | 0 | if (H5O__attr_update_shared(op_data->f, NULL, op_data->attr, NULL) < 0) |
610 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute in shared storage"); |
611 | | |
612 | | /* Update record's heap ID */ |
613 | 0 | record->id = op_data->attr->sh_loc.u.heap_id; |
614 | | |
615 | | /* Check if we need to modify the creation order index with new heap ID */ |
616 | 0 | if (H5_addr_defined(op_data->corder_bt2_addr)) { |
617 | 0 | H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */ |
618 | | |
619 | | /* Open the creation order index v2 B-tree */ |
620 | 0 | if (NULL == (bt2_corder = H5B2_open(op_data->f, op_data->corder_bt2_addr, NULL))) |
621 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, |
622 | 0 | "unable to open v2 B-tree for creation order index"); |
623 | | |
624 | | /* Create the "udata" information for v2 B-tree record modify */ |
625 | 0 | udata.f = op_data->f; |
626 | 0 | udata.fheap = NULL; |
627 | 0 | udata.shared_fheap = NULL; |
628 | 0 | udata.name = NULL; |
629 | 0 | udata.name_hash = 0; |
630 | 0 | udata.flags = 0; |
631 | 0 | udata.corder = op_data->attr->shared->crt_idx; |
632 | 0 | udata.found_op = NULL; |
633 | 0 | udata.found_op_data = NULL; |
634 | | |
635 | | /* Modify record for creation order index */ |
636 | 0 | if (H5B2_modify(bt2_corder, &udata, false, H5A__dense_write_bt2_cb2, |
637 | 0 | &op_data->attr->sh_loc.u.heap_id) < 0) |
638 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to modify record in v2 B-tree"); |
639 | 0 | } /* end if */ |
640 | | |
641 | | /* Note that the record changed */ |
642 | 0 | *changed = true; |
643 | 0 | } /* end if */ |
644 | 0 | else { |
645 | 0 | void *attr_ptr; /* Pointer to serialized message */ |
646 | 0 | size_t attr_size; /* Size of serialized attribute in the heap */ |
647 | | |
648 | | /* Find out the size of buffer needed for serialized attribute */ |
649 | 0 | if ((attr_size = H5O_msg_raw_size(op_data->f, H5O_ATTR_ID, false, op_data->attr)) == 0) |
650 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGETSIZE, FAIL, "can't get attribute size"); |
651 | | |
652 | | /* Wrap the local buffer for serialized attributes */ |
653 | 0 | if (NULL == (wb = H5WB_wrap(attr_buf, sizeof(attr_buf)))) |
654 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINIT, FAIL, "can't wrap buffer"); |
655 | | |
656 | | /* Get a pointer to a buffer that's large enough for attribute */ |
657 | 0 | if (NULL == (attr_ptr = H5WB_actual(wb, attr_size))) |
658 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_NOSPACE, FAIL, "can't get actual buffer"); |
659 | | |
660 | | /* Create serialized form of attribute */ |
661 | 0 | if (H5O_msg_encode(op_data->f, H5O_ATTR_ID, false, (unsigned char *)attr_ptr, op_data->attr) < 0) |
662 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTENCODE, FAIL, "can't encode attribute"); |
663 | | |
664 | | /* Sanity check */ |
665 | | #ifndef NDEBUG |
666 | | { |
667 | | size_t obj_len; /* Length of existing encoded attribute */ |
668 | | |
669 | | if (H5HF_get_obj_len(op_data->fheap, &record->id, &obj_len) < 0) |
670 | | HGOTO_ERROR(H5E_ATTR, H5E_CANTGETSIZE, FAIL, "can't get object size"); |
671 | | assert(obj_len == attr_size); |
672 | | } |
673 | | #endif /* NDEBUG */ |
674 | | /* Update existing attribute in heap */ |
675 | | /* (might be more efficient as fractal heap 'op' callback, but leave that for later -QAK) */ |
676 | 0 | if (H5HF_write(op_data->fheap, &record->id, changed, attr_ptr) < 0) |
677 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update attribute in heap"); |
678 | 0 | } /* end else */ |
679 | | |
680 | 0 | done: |
681 | | /* Release resources */ |
682 | 0 | if (bt2_corder && H5B2_close(bt2_corder) < 0) |
683 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index"); |
684 | 0 | if (wb && H5WB_unwrap(wb) < 0) |
685 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer"); |
686 | |
|
687 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
688 | 0 | } /* end H5A__dense_write_bt2_cb() */ |
689 | | |
690 | | /*------------------------------------------------------------------------- |
691 | | * Function: H5A__dense_write |
692 | | * |
693 | | * Purpose: Modify an attribute in dense storage structures for an object |
694 | | * |
695 | | * Return: SUCCEED/FAIL |
696 | | * |
697 | | *------------------------------------------------------------------------- |
698 | | */ |
699 | | herr_t |
700 | | H5A__dense_write(H5F_t *f, const H5O_ainfo_t *ainfo, H5A_t *attr) |
701 | 0 | { |
702 | 0 | H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */ |
703 | 0 | H5A_bt2_od_wrt_t op_data; /* "Op data" for v2 B-tree modify */ |
704 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
705 | 0 | H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */ |
706 | 0 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */ |
707 | 0 | htri_t attr_sharable; /* Flag indicating attributes are shareable */ |
708 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
709 | |
|
710 | 0 | FUNC_ENTER_PACKAGE |
711 | | |
712 | | /* Check arguments */ |
713 | 0 | assert(f); |
714 | 0 | assert(ainfo); |
715 | 0 | assert(H5_addr_defined(ainfo->fheap_addr)); |
716 | 0 | assert(H5_addr_defined(ainfo->name_bt2_addr)); |
717 | 0 | assert(attr); |
718 | | |
719 | | /* Check if attributes are shared in this file */ |
720 | 0 | if ((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID)) < 0) |
721 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared"); |
722 | | |
723 | | /* Get handle for shared message heap, if attributes are shareable */ |
724 | 0 | if (attr_sharable) { |
725 | 0 | haddr_t shared_fheap_addr; /* Address of fractal heap to use */ |
726 | | |
727 | | /* Retrieve the address of the shared message's fractal heap */ |
728 | 0 | if (H5SM_get_fheap_addr(f, H5O_ATTR_ID, &shared_fheap_addr) < 0) |
729 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address"); |
730 | | |
731 | | /* Check if there are any shared messages currently */ |
732 | 0 | if (H5_addr_defined(shared_fheap_addr)) { |
733 | | /* Open the fractal heap for shared header messages */ |
734 | 0 | if (NULL == (shared_fheap = H5HF_open(f, shared_fheap_addr))) |
735 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
736 | 0 | } /* end if */ |
737 | 0 | } /* end if */ |
738 | | |
739 | | /* Open the fractal heap */ |
740 | 0 | if (NULL == (fheap = H5HF_open(f, ainfo->fheap_addr))) |
741 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
742 | | |
743 | | /* Open the name index v2 B-tree */ |
744 | 0 | if (NULL == (bt2_name = H5B2_open(f, ainfo->name_bt2_addr, NULL))) |
745 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index"); |
746 | | |
747 | | /* Create the "udata" information for v2 B-tree record modify */ |
748 | 0 | udata.f = f; |
749 | 0 | udata.fheap = fheap; |
750 | 0 | udata.shared_fheap = shared_fheap; |
751 | 0 | udata.name = attr->shared->name; |
752 | 0 | udata.name_hash = H5_checksum_lookup3(attr->shared->name, strlen(attr->shared->name), 0); |
753 | 0 | udata.flags = 0; |
754 | 0 | udata.corder = 0; |
755 | 0 | udata.found_op = NULL; |
756 | 0 | udata.found_op_data = NULL; |
757 | | |
758 | | /* Create the "op_data" for the v2 B-tree record 'modify' callback */ |
759 | 0 | op_data.f = f; |
760 | 0 | op_data.fheap = fheap; |
761 | 0 | op_data.shared_fheap = shared_fheap; |
762 | 0 | op_data.attr = attr; |
763 | 0 | op_data.corder_bt2_addr = ainfo->corder_bt2_addr; |
764 | | |
765 | | /* Modify attribute through 'name' tracking v2 B-tree */ |
766 | 0 | if (H5B2_modify(bt2_name, &udata, false, H5A__dense_write_bt2_cb, &op_data) < 0) |
767 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to modify record in v2 B-tree"); |
768 | | |
769 | 0 | done: |
770 | | /* Release resources */ |
771 | 0 | if (shared_fheap && H5HF_close(shared_fheap) < 0) |
772 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
773 | 0 | if (fheap && H5HF_close(fheap) < 0) |
774 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
775 | 0 | if (bt2_name && H5B2_close(bt2_name) < 0) |
776 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
777 | |
|
778 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
779 | 0 | } /* end H5A__dense_write() */ |
780 | | |
781 | | /*------------------------------------------------------------------------- |
782 | | * Function: H5A__dense_copy_fh_cb |
783 | | * |
784 | | * Purpose: Callback for fractal heap operator, to make copy of attribute |
785 | | * for calling routine |
786 | | * |
787 | | * Return: SUCCEED/FAIL |
788 | | * |
789 | | *------------------------------------------------------------------------- |
790 | | */ |
791 | | static herr_t |
792 | | H5A__dense_copy_fh_cb(const void *obj, size_t obj_len, void *_udata) |
793 | 0 | { |
794 | 0 | H5A_fh_ud_cp_t *udata = (H5A_fh_ud_cp_t *)_udata; /* User data for fractal heap 'op' callback */ |
795 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
796 | |
|
797 | 0 | FUNC_ENTER_PACKAGE |
798 | | |
799 | | /* Decode attribute information & keep a copy */ |
800 | | /* (we make a copy instead of calling the user/library callback directly in |
801 | | * this routine because this fractal heap 'op' callback routine is called |
802 | | * with the direct block protected and if the callback routine invokes an |
803 | | * HDF5 routine, it could attempt to re-protect that direct block for the |
804 | | * heap, causing the HDF5 routine called to fail) |
805 | | */ |
806 | 0 | if (NULL == (udata->attr = (H5A_t *)H5O_msg_decode(udata->f, NULL, H5O_ATTR_ID, obj_len, |
807 | 0 | (const unsigned char *)obj))) |
808 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTDECODE, FAIL, "can't decode attribute"); |
809 | | |
810 | | /* Set the creation order index for the attribute */ |
811 | 0 | udata->attr->shared->crt_idx = udata->record->corder; |
812 | | |
813 | | /* Check whether we should "reconstitute" the shared message info */ |
814 | 0 | if (udata->record->flags & H5O_MSG_FLAG_SHARED) |
815 | 0 | H5SM_reconstitute(&(udata->attr->sh_loc), udata->f, H5O_ATTR_ID, udata->record->id); |
816 | |
|
817 | 0 | done: |
818 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
819 | 0 | } /* end H5A__dense_copy_fh_cb() */ |
820 | | |
821 | | /*------------------------------------------------------------------------- |
822 | | * Function: H5A__dense_rename |
823 | | * |
824 | | * Purpose: Rename an attribute in dense storage structures for an object |
825 | | * |
826 | | * Return: SUCCEED/FAIL |
827 | | * |
828 | | *------------------------------------------------------------------------- |
829 | | */ |
830 | | herr_t |
831 | | H5A__dense_rename(H5F_t *f, const H5O_ainfo_t *ainfo, const char *old_name, const char *new_name) |
832 | 0 | { |
833 | 0 | H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */ |
834 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
835 | 0 | H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */ |
836 | 0 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */ |
837 | 0 | H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order ndex */ |
838 | 0 | H5A_t *attr_copy = NULL; /* Copy of attribute to rename */ |
839 | 0 | htri_t attr_sharable; /* Flag indicating attributes are shareable */ |
840 | 0 | htri_t shared_mesg; /* Should this message be stored in the Shared Message table? */ |
841 | 0 | bool attr_exists; /* Attribute exists in v2 B-tree */ |
842 | 0 | H5O_ainfo_t tainfo = *ainfo; /* Copy of ainfo */ |
843 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
844 | |
|
845 | 0 | FUNC_ENTER_PACKAGE |
846 | | |
847 | | /* Check arguments */ |
848 | 0 | assert(f); |
849 | 0 | assert(ainfo); |
850 | 0 | assert(old_name); |
851 | 0 | assert(new_name); |
852 | | |
853 | | /* Check if attributes are shared in this file */ |
854 | 0 | if ((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID)) < 0) |
855 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared"); |
856 | | |
857 | | /* Get handle for shared message heap, if attributes are shareable */ |
858 | 0 | if (attr_sharable) { |
859 | 0 | haddr_t shared_fheap_addr; /* Address of fractal heap to use */ |
860 | | |
861 | | /* Retrieve the address of the shared message's fractal heap */ |
862 | 0 | if (H5SM_get_fheap_addr(f, H5O_ATTR_ID, &shared_fheap_addr) < 0) |
863 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address"); |
864 | | |
865 | | /* Check if there are any shared messages currently */ |
866 | 0 | if (H5_addr_defined(shared_fheap_addr)) { |
867 | | /* Open the fractal heap for shared header messages */ |
868 | 0 | if (NULL == (shared_fheap = H5HF_open(f, shared_fheap_addr))) |
869 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
870 | 0 | } /* end if */ |
871 | 0 | } /* end if */ |
872 | | |
873 | | /* Open the fractal heap */ |
874 | 0 | if (NULL == (fheap = H5HF_open(f, ainfo->fheap_addr))) |
875 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
876 | | |
877 | | /* Open the name index v2 B-tree */ |
878 | 0 | if (NULL == (bt2_name = H5B2_open(f, ainfo->name_bt2_addr, NULL))) |
879 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index"); |
880 | | |
881 | | /* Create the "udata" information for v2 B-tree record modify */ |
882 | 0 | udata.f = f; |
883 | 0 | udata.fheap = fheap; |
884 | 0 | udata.shared_fheap = shared_fheap; |
885 | 0 | udata.name = old_name; |
886 | 0 | udata.name_hash = H5_checksum_lookup3(old_name, strlen(old_name), 0); |
887 | 0 | udata.flags = 0; |
888 | 0 | udata.corder = 0; |
889 | 0 | udata.found_op = H5A__dense_fnd_cb; /* v2 B-tree comparison callback */ |
890 | 0 | udata.found_op_data = &attr_copy; |
891 | | |
892 | | /* Get copy of attribute through 'name' tracking v2 B-tree */ |
893 | 0 | attr_exists = false; |
894 | 0 | if (H5B2_find(bt2_name, &udata, &attr_exists, NULL, NULL) < 0) |
895 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't search for attribute in name index"); |
896 | 0 | if (attr_exists == false) |
897 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't locate attribute in name index"); |
898 | 0 | assert(attr_copy); |
899 | | |
900 | | /* Check if message is already shared */ |
901 | 0 | if ((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, attr_copy)) < 0) |
902 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error determining if message is shared"); |
903 | 0 | else if (shared_mesg > 0) { |
904 | | /* Reset shared status of copy */ |
905 | | /* (so it will get shared again if necessary) */ |
906 | 0 | attr_copy->sh_loc.type = H5O_SHARE_TYPE_UNSHARED; |
907 | 0 | } /* end if */ |
908 | | |
909 | | /* Change name of attribute */ |
910 | 0 | H5MM_xfree(attr_copy->shared->name); |
911 | 0 | attr_copy->shared->name = H5MM_xstrdup(new_name); |
912 | | |
913 | | /* Recompute the version to encode the attribute with */ |
914 | 0 | if (H5A__set_version(f, attr_copy) < 0) |
915 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "unable to update attribute version"); |
916 | | |
917 | | /* Need to remove the attribute from the creation order index v2 B-tree */ |
918 | 0 | if (ainfo->index_corder) { |
919 | 0 | bool corder_attr_exists; /* Attribute exists in v2 B-tree */ |
920 | | |
921 | | /* Open the creation order index v2 B-tree */ |
922 | 0 | assert(H5_addr_defined(ainfo->corder_bt2_addr)); |
923 | 0 | if (NULL == (bt2_corder = H5B2_open(f, ainfo->corder_bt2_addr, NULL))) |
924 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation index"); |
925 | | |
926 | | /* Set up the creation order to search for */ |
927 | 0 | udata.corder = attr_copy->shared->crt_idx; |
928 | |
|
929 | 0 | corder_attr_exists = false; |
930 | 0 | if (H5B2_find(bt2_corder, &udata, &corder_attr_exists, NULL, NULL) < 0) |
931 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't search for attribute in name index"); |
932 | | |
933 | 0 | if (corder_attr_exists) { |
934 | 0 | H5A_bt2_ud_rm_t rm_udata; |
935 | | |
936 | | /* Set up the creation order in user data for the v2 B-tree 'record remove' callback */ |
937 | 0 | rm_udata.common.corder = attr_copy->shared->crt_idx; |
938 | | |
939 | | /* Remove the record from the creation order index v2 B-tree */ |
940 | 0 | if (H5B2_remove(bt2_corder, &rm_udata, NULL, NULL) < 0) |
941 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, |
942 | 0 | "unable to remove attribute from creation order index v2 B-tree"); |
943 | 0 | } |
944 | 0 | } |
945 | | |
946 | | /* Insert renamed attribute back into dense storage */ |
947 | | /* (Possibly making it shared) */ |
948 | 0 | if (H5A__dense_insert(f, ainfo, attr_copy) < 0) |
949 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to add to dense storage"); |
950 | | |
951 | | /* Was this attribute shared? */ |
952 | 0 | if ((shared_mesg = H5O_msg_is_shared(H5O_ATTR_ID, attr_copy)) > 0) { |
953 | 0 | hsize_t attr_rc; /* Attribute's ref count in shared message storage */ |
954 | | |
955 | | /* Retrieve ref count for shared attribute */ |
956 | 0 | if (H5SM_get_refcount(f, H5O_ATTR_ID, &attr_copy->sh_loc, &attr_rc) < 0) |
957 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't retrieve shared message ref count"); |
958 | | |
959 | | /* If the newly shared attribute needs to share "ownership" of the shared |
960 | | * components (ie. its reference count is 1), increment the reference |
961 | | * count on any shared components of the attribute, so that they won't |
962 | | * be removed from the file. (Essentially a "copy on write" operation). |
963 | | * |
964 | | * *ick* -QAK, 2007/01/08 |
965 | | */ |
966 | 0 | if (attr_rc == 1) { |
967 | | /* Increment reference count on attribute components */ |
968 | 0 | if (H5O__attr_link(f, NULL, attr_copy) < 0) |
969 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count"); |
970 | 0 | } /* end if */ |
971 | 0 | } /* end if */ |
972 | 0 | else if (shared_mesg == 0) { |
973 | | /* Increment reference count on attribute components */ |
974 | | /* (so that they aren't deleted when the attribute is removed shortly) */ |
975 | 0 | if (H5O__attr_link(f, NULL, attr_copy) < 0) |
976 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_LINKCOUNT, FAIL, "unable to adjust attribute link count"); |
977 | 0 | } /* end if */ |
978 | 0 | else if (shared_mesg < 0) |
979 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "error determining if message should be shared"); |
980 | | |
981 | | /* Deactivate the field so that H5A__dense_remove() won't delete the new renamed attribute |
982 | | that was just added to the creation order index v2 B-tree via H5A__dense_insert() */ |
983 | 0 | tainfo.corder_bt2_addr = HADDR_UNDEF; |
984 | | |
985 | | /* Only delete the old attribute (before rename) from the name index v2 B-tree */ |
986 | 0 | if (H5A__dense_remove(f, (const H5O_ainfo_t *)&tainfo, old_name) < 0) |
987 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage"); |
988 | | |
989 | 0 | done: |
990 | | /* Release resources */ |
991 | 0 | if (shared_fheap && H5HF_close(shared_fheap) < 0) |
992 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
993 | 0 | if (fheap && H5HF_close(fheap) < 0) |
994 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
995 | 0 | if (bt2_name && H5B2_close(bt2_name) < 0) |
996 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
997 | 0 | if (bt2_corder && H5B2_close(bt2_corder) < 0) |
998 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index"); |
999 | 0 | if (attr_copy) |
1000 | 0 | H5O_msg_free(H5O_ATTR_ID, attr_copy); |
1001 | |
|
1002 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1003 | 0 | } /* end H5A__dense_rename() */ |
1004 | | |
1005 | | /*------------------------------------------------------------------------- |
1006 | | * Function: H5A__dense_iterate_bt2_cb |
1007 | | * |
1008 | | * Purpose: v2 B-tree callback for dense attribute storage iterator |
1009 | | * |
1010 | | * Return: H5_ITER_ERROR/H5_ITER_CONT/H5_ITER_STOP |
1011 | | * |
1012 | | *------------------------------------------------------------------------- |
1013 | | */ |
1014 | | static int |
1015 | | H5A__dense_iterate_bt2_cb(const void *_record, void *_bt2_udata) |
1016 | 0 | { |
1017 | 0 | const H5A_dense_bt2_name_rec_t *record = |
1018 | 0 | (const H5A_dense_bt2_name_rec_t *)_record; /* Record from B-tree */ |
1019 | 0 | H5A_bt2_ud_it_t *bt2_udata = (H5A_bt2_ud_it_t *)_bt2_udata; /* User data for callback */ |
1020 | 0 | herr_t ret_value = H5_ITER_CONT; /* Return value */ |
1021 | |
|
1022 | 0 | FUNC_ENTER_PACKAGE |
1023 | | |
1024 | | /* Check for skipping attributes */ |
1025 | 0 | if (bt2_udata->skip > 0) |
1026 | 0 | --bt2_udata->skip; |
1027 | 0 | else { |
1028 | 0 | H5A_fh_ud_cp_t fh_udata; /* User data for fractal heap 'op' callback */ |
1029 | 0 | H5HF_t *fheap; /* Fractal heap handle for attribute storage */ |
1030 | | |
1031 | | /* Check for iterating over shared attribute */ |
1032 | 0 | if (record->flags & H5O_MSG_FLAG_SHARED) |
1033 | 0 | fheap = bt2_udata->shared_fheap; |
1034 | 0 | else |
1035 | 0 | fheap = bt2_udata->fheap; |
1036 | | |
1037 | | /* Prepare user data for callback */ |
1038 | | /* down */ |
1039 | 0 | fh_udata.f = bt2_udata->f; |
1040 | 0 | fh_udata.record = record; |
1041 | 0 | fh_udata.attr = NULL; |
1042 | | |
1043 | | /* Call fractal heap 'op' routine, to copy the attribute information */ |
1044 | 0 | if (H5HF_op(fheap, &record->id, H5A__dense_copy_fh_cb, &fh_udata) < 0) |
1045 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPERATE, H5_ITER_ERROR, "heap op callback failed"); |
1046 | | |
1047 | | /* Check which type of callback to make */ |
1048 | 0 | switch (bt2_udata->attr_op->op_type) { |
1049 | 0 | case H5A_ATTR_OP_APP2: { |
1050 | 0 | H5A_info_t ainfo; /* Info for attribute */ |
1051 | | |
1052 | | /* Get the attribute information */ |
1053 | 0 | if (H5A__get_info(fh_udata.attr, &ainfo) < 0) |
1054 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, H5_ITER_ERROR, "unable to get attribute info"); |
1055 | | |
1056 | | /* Prepare & restore library for user callback */ |
1057 | 0 | H5_BEFORE_USER_CB(H5_ITER_ERROR) |
1058 | 0 | { |
1059 | | /* Make the application callback */ |
1060 | 0 | ret_value = (bt2_udata->attr_op->u.app_op2)( |
1061 | 0 | bt2_udata->loc_id, fh_udata.attr->shared->name, &ainfo, bt2_udata->op_data); |
1062 | 0 | } |
1063 | 0 | H5_AFTER_USER_CB(H5_ITER_ERROR) |
1064 | 0 | break; |
1065 | 0 | } |
1066 | | |
1067 | | #ifndef H5_NO_DEPRECATED_SYMBOLS |
1068 | | case H5A_ATTR_OP_APP: |
1069 | | /* Prepare & restore library for user callback */ |
1070 | | H5_BEFORE_USER_CB(H5_ITER_ERROR) |
1071 | | { |
1072 | | /* Make the application callback */ |
1073 | | ret_value = (bt2_udata->attr_op->u.app_op)( |
1074 | | bt2_udata->loc_id, fh_udata.attr->shared->name, bt2_udata->op_data); |
1075 | | } |
1076 | | H5_AFTER_USER_CB(H5_ITER_ERROR) |
1077 | | break; |
1078 | | #endif /* H5_NO_DEPRECATED_SYMBOLS */ |
1079 | | |
1080 | 0 | case H5A_ATTR_OP_LIB: |
1081 | | /* Call the library's callback */ |
1082 | 0 | ret_value = (bt2_udata->attr_op->u.lib_op)(fh_udata.attr, bt2_udata->op_data); |
1083 | 0 | break; |
1084 | | |
1085 | 0 | default: |
1086 | 0 | assert("unknown attribute op type" && 0); |
1087 | 0 | #ifdef NDEBUG |
1088 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_UNSUPPORTED, FAIL, "unsupported attribute op type"); |
1089 | 0 | #endif /* NDEBUG */ |
1090 | 0 | } /* end switch */ |
1091 | | |
1092 | | /* Release the space allocated for the attribute */ |
1093 | 0 | H5O_msg_free(H5O_ATTR_ID, fh_udata.attr); |
1094 | 0 | } /* end else */ |
1095 | | |
1096 | | /* Increment the number of attributes passed through */ |
1097 | | /* (whether we skipped them or not) */ |
1098 | 0 | bt2_udata->count++; |
1099 | | |
1100 | | /* Check for callback failure and pass along return value */ |
1101 | 0 | if (ret_value < 0) |
1102 | 0 | HERROR(H5E_ATTR, H5E_CANTNEXT, "iteration operator failed"); |
1103 | |
|
1104 | 0 | done: |
1105 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1106 | 0 | } /* end H5A__dense_iterate_bt2_cb() */ |
1107 | | |
1108 | | /*------------------------------------------------------------------------- |
1109 | | * Function: H5A__dense_iterate |
1110 | | * |
1111 | | * Purpose: Iterate over attributes in dense storage structures for an object |
1112 | | * |
1113 | | * Return: SUCCEED/FAIL |
1114 | | * |
1115 | | *------------------------------------------------------------------------- |
1116 | | */ |
1117 | | herr_t |
1118 | | H5A__dense_iterate(H5F_t *f, hid_t loc_id, const H5O_ainfo_t *ainfo, H5_index_t idx_type, |
1119 | | H5_iter_order_t order, hsize_t skip, hsize_t *last_attr, const H5A_attr_iter_op_t *attr_op, |
1120 | | void *op_data) |
1121 | 0 | { |
1122 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
1123 | 0 | H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */ |
1124 | 0 | H5A_attr_table_t atable = {0, 0, NULL}; /* Table of attributes */ |
1125 | 0 | H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */ |
1126 | 0 | haddr_t bt2_addr; /* Address of v2 B-tree to use for lookup */ |
1127 | 0 | herr_t ret_value = FAIL; /* Return value */ |
1128 | |
|
1129 | 0 | FUNC_ENTER_PACKAGE |
1130 | | |
1131 | | /* Check arguments */ |
1132 | 0 | assert(f); |
1133 | 0 | assert(ainfo); |
1134 | 0 | assert(H5_addr_defined(ainfo->fheap_addr)); |
1135 | 0 | assert(H5_addr_defined(ainfo->name_bt2_addr)); |
1136 | 0 | assert(attr_op); |
1137 | | |
1138 | | /* Determine the address of the index to use */ |
1139 | 0 | if (idx_type == H5_INDEX_NAME) { |
1140 | | /* Check if "native" order is OK - since names are hashed, getting them |
1141 | | * in strictly increasing or decreasing order requires building a |
1142 | | * table and sorting it. |
1143 | | */ |
1144 | 0 | if (order == H5_ITER_NATIVE) { |
1145 | 0 | assert(H5_addr_defined(ainfo->name_bt2_addr)); |
1146 | 0 | bt2_addr = ainfo->name_bt2_addr; |
1147 | 0 | } /* end if */ |
1148 | 0 | else |
1149 | 0 | bt2_addr = HADDR_UNDEF; |
1150 | 0 | } /* end if */ |
1151 | 0 | else { |
1152 | 0 | assert(idx_type == H5_INDEX_CRT_ORDER); |
1153 | | |
1154 | | /* This address may not be defined if creation order is tracked, but |
1155 | | * there's no index on it. If there's no v2 B-tree that indexes |
1156 | | * the links, a table will be built. |
1157 | | */ |
1158 | 0 | bt2_addr = ainfo->corder_bt2_addr; |
1159 | 0 | } /* end else */ |
1160 | | |
1161 | | /* Check on iteration order */ |
1162 | 0 | if (order == H5_ITER_NATIVE && H5_addr_defined(bt2_addr)) { |
1163 | 0 | H5A_bt2_ud_it_t udata; /* User data for iterator callback */ |
1164 | 0 | htri_t attr_sharable; /* Flag indicating attributes are shareable */ |
1165 | | |
1166 | | /* Open the fractal heap */ |
1167 | 0 | if (NULL == (fheap = H5HF_open(f, ainfo->fheap_addr))) |
1168 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1169 | | |
1170 | | /* Check if attributes are shared in this file */ |
1171 | 0 | if ((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID)) < 0) |
1172 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared"); |
1173 | | |
1174 | | /* Get handle for shared message heap, if attributes are shareable */ |
1175 | 0 | if (attr_sharable) { |
1176 | 0 | haddr_t shared_fheap_addr; /* Address of fractal heap to use */ |
1177 | | |
1178 | | /* Retrieve the address of the shared message's fractal heap */ |
1179 | 0 | if (H5SM_get_fheap_addr(f, H5O_ATTR_ID, &shared_fheap_addr) < 0) |
1180 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address"); |
1181 | | |
1182 | | /* Check if there are any shared messages currently */ |
1183 | 0 | if (H5_addr_defined(shared_fheap_addr)) { |
1184 | | /* Open the fractal heap for shared header messages */ |
1185 | 0 | if (NULL == (shared_fheap = H5HF_open(f, shared_fheap_addr))) |
1186 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1187 | 0 | } /* end if */ |
1188 | 0 | } /* end if */ |
1189 | | |
1190 | | /* Open the index v2 B-tree */ |
1191 | 0 | if (NULL == (bt2 = H5B2_open(f, bt2_addr, NULL))) |
1192 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index"); |
1193 | | |
1194 | | /* Construct the user data for v2 B-tree iterator callback */ |
1195 | 0 | udata.f = f; |
1196 | 0 | udata.fheap = fheap; |
1197 | 0 | udata.shared_fheap = shared_fheap; |
1198 | 0 | udata.loc_id = loc_id; |
1199 | 0 | udata.skip = skip; |
1200 | 0 | udata.count = 0; |
1201 | 0 | udata.attr_op = attr_op; |
1202 | 0 | udata.op_data = op_data; |
1203 | | |
1204 | | /* Iterate over the records in the v2 B-tree's "native" order */ |
1205 | | /* (by hash of name) */ |
1206 | 0 | if ((ret_value = H5B2_iterate(bt2, H5A__dense_iterate_bt2_cb, &udata)) < 0) |
1207 | 0 | HERROR(H5E_ATTR, H5E_BADITER, "attribute iteration failed"); |
1208 | | |
1209 | | /* Update the last attribute examined, if requested */ |
1210 | 0 | if (last_attr) |
1211 | 0 | *last_attr = udata.count; |
1212 | 0 | } /* end if */ |
1213 | 0 | else { |
1214 | | /* Build the table of attributes for this object */ |
1215 | | /* (build table using the name index, but sort according to idx_type) */ |
1216 | 0 | if (H5A__dense_build_table(f, ainfo, idx_type, order, &atable) < 0) |
1217 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error building table of attributes"); |
1218 | | |
1219 | | /* Iterate over attributes in table */ |
1220 | 0 | if ((ret_value = H5A__attr_iterate_table(&atable, skip, last_attr, loc_id, attr_op, op_data)) < 0) |
1221 | 0 | HERROR(H5E_ATTR, H5E_CANTNEXT, "iteration operator failed"); |
1222 | 0 | } /* end else */ |
1223 | | |
1224 | 0 | done: |
1225 | | /* Release resources */ |
1226 | 0 | if (shared_fheap && H5HF_close(shared_fheap) < 0) |
1227 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1228 | 0 | if (fheap && H5HF_close(fheap) < 0) |
1229 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1230 | 0 | if (bt2 && H5B2_close(bt2) < 0) |
1231 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index"); |
1232 | 0 | if (atable.attrs && H5A__attr_release_table(&atable) < 0) |
1233 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table"); |
1234 | |
|
1235 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1236 | 0 | } /* end H5A__dense_iterate() */ |
1237 | | |
1238 | | /*------------------------------------------------------------------------- |
1239 | | * Function: H5A__dense_remove_bt2_cb |
1240 | | * |
1241 | | * Purpose: v2 B-tree callback for dense attribute storage record removal |
1242 | | * |
1243 | | * Return: SUCCEED/FAIL |
1244 | | * |
1245 | | *------------------------------------------------------------------------- |
1246 | | */ |
1247 | | static herr_t |
1248 | | H5A__dense_remove_bt2_cb(const void *_record, void *_udata) |
1249 | 0 | { |
1250 | 0 | const H5A_dense_bt2_name_rec_t *record = (const H5A_dense_bt2_name_rec_t *)_record; |
1251 | 0 | H5A_bt2_ud_rm_t *udata = (H5A_bt2_ud_rm_t *)_udata; /* User data for callback */ |
1252 | 0 | H5A_t *attr = *(H5A_t **)udata->common.found_op_data; /* Pointer to attribute to remove */ |
1253 | 0 | H5B2_t *bt2_corder = NULL; /* v2 B-tree handle for creation order index */ |
1254 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1255 | |
|
1256 | 0 | FUNC_ENTER_PACKAGE |
1257 | | |
1258 | | /* Check for removing the link from the creation order index */ |
1259 | 0 | if (H5_addr_defined(udata->corder_bt2_addr)) { |
1260 | | /* Open the creation order index v2 B-tree */ |
1261 | 0 | if (NULL == (bt2_corder = H5B2_open(udata->common.f, udata->corder_bt2_addr, NULL))) |
1262 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index"); |
1263 | | |
1264 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1265 | 0 | udata->common.corder = attr->shared->crt_idx; |
1266 | | |
1267 | | /* Remove the record from the creation order index v2 B-tree */ |
1268 | 0 | if (H5B2_remove(bt2_corder, udata, NULL, NULL) < 0) |
1269 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, |
1270 | 0 | "unable to remove attribute from creation order index v2 B-tree"); |
1271 | 0 | } /* end if */ |
1272 | | |
1273 | | /* Check for removing shared attribute */ |
1274 | 0 | if (record->flags & H5O_MSG_FLAG_SHARED) { |
1275 | | /* Decrement the reference count on the shared attribute message */ |
1276 | 0 | if (H5SM_delete(udata->common.f, NULL, &(attr->sh_loc)) < 0) |
1277 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to delete shared attribute"); |
1278 | 0 | } /* end if */ |
1279 | 0 | else { |
1280 | | /* Perform the deletion action on the attribute */ |
1281 | | /* (takes care of shared & committed datatype/dataspace components) */ |
1282 | 0 | if (H5O__attr_delete(udata->common.f, NULL, attr) < 0) |
1283 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute"); |
1284 | | |
1285 | | /* Remove record from fractal heap */ |
1286 | 0 | if (H5HF_remove(udata->common.fheap, &record->id) < 0) |
1287 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from fractal heap"); |
1288 | 0 | } /* end else */ |
1289 | | |
1290 | 0 | done: |
1291 | | /* Release resources */ |
1292 | 0 | if (bt2_corder && H5B2_close(bt2_corder) < 0) |
1293 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index"); |
1294 | |
|
1295 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1296 | 0 | } /* end H5A__dense_remove_bt2_cb() */ |
1297 | | |
1298 | | /*------------------------------------------------------------------------- |
1299 | | * Function: H5A__dense_remove |
1300 | | * |
1301 | | * Purpose: Remove an attribute from the dense storage of an object |
1302 | | * |
1303 | | * Return: SUCCEED/FAIL |
1304 | | * |
1305 | | *------------------------------------------------------------------------- |
1306 | | */ |
1307 | | herr_t |
1308 | | H5A__dense_remove(H5F_t *f, const H5O_ainfo_t *ainfo, const char *name) |
1309 | 0 | { |
1310 | 0 | H5A_bt2_ud_rm_t udata; /* User data for v2 B-tree record removal */ |
1311 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
1312 | 0 | H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */ |
1313 | 0 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */ |
1314 | 0 | H5A_t *attr_copy = NULL; /* Copy of attribute to remove */ |
1315 | 0 | htri_t attr_sharable; /* Flag indicating attributes are shareable */ |
1316 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1317 | |
|
1318 | 0 | FUNC_ENTER_PACKAGE |
1319 | | |
1320 | | /* Check arguments */ |
1321 | 0 | assert(f); |
1322 | 0 | assert(ainfo); |
1323 | 0 | assert(name && *name); |
1324 | | |
1325 | | /* Open the fractal heap */ |
1326 | 0 | if (NULL == (fheap = H5HF_open(f, ainfo->fheap_addr))) |
1327 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1328 | | |
1329 | | /* Check if attributes are shared in this file */ |
1330 | 0 | if ((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID)) < 0) |
1331 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared"); |
1332 | | |
1333 | | /* Get handle for shared message heap, if attributes are shareable */ |
1334 | 0 | if (attr_sharable) { |
1335 | 0 | haddr_t shared_fheap_addr; /* Address of fractal heap to use */ |
1336 | | |
1337 | | /* Retrieve the address of the shared message's fractal heap */ |
1338 | 0 | if (H5SM_get_fheap_addr(f, H5O_ATTR_ID, &shared_fheap_addr) < 0) |
1339 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address"); |
1340 | | |
1341 | | /* Check if there are any shared messages currently */ |
1342 | 0 | if (H5_addr_defined(shared_fheap_addr)) { |
1343 | | /* Open the fractal heap for shared header messages */ |
1344 | 0 | if (NULL == (shared_fheap = H5HF_open(f, shared_fheap_addr))) |
1345 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1346 | 0 | } /* end if */ |
1347 | 0 | } /* end if */ |
1348 | | |
1349 | | /* Open the name index v2 B-tree */ |
1350 | 0 | if (NULL == (bt2_name = H5B2_open(f, ainfo->name_bt2_addr, NULL))) |
1351 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index"); |
1352 | | |
1353 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1354 | 0 | udata.common.f = f; |
1355 | 0 | udata.common.fheap = fheap; |
1356 | 0 | udata.common.shared_fheap = shared_fheap; |
1357 | 0 | udata.common.name = name; |
1358 | 0 | udata.common.name_hash = H5_checksum_lookup3(name, strlen(name), 0); |
1359 | 0 | udata.common.found_op = H5A__dense_fnd_cb; /* v2 B-tree comparison callback */ |
1360 | 0 | udata.common.found_op_data = &attr_copy; |
1361 | 0 | udata.corder_bt2_addr = ainfo->corder_bt2_addr; |
1362 | | |
1363 | | /* Remove the record from the name index v2 B-tree */ |
1364 | 0 | if (H5B2_remove(bt2_name, &udata, H5A__dense_remove_bt2_cb, &udata) < 0) |
1365 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from name index v2 B-tree"); |
1366 | | |
1367 | 0 | done: |
1368 | | /* Release resources */ |
1369 | 0 | if (shared_fheap && H5HF_close(shared_fheap) < 0) |
1370 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1371 | 0 | if (fheap && H5HF_close(fheap) < 0) |
1372 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1373 | 0 | if (bt2_name && H5B2_close(bt2_name) < 0) |
1374 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
1375 | 0 | if (attr_copy) |
1376 | 0 | H5O_msg_free_real(H5O_MSG_ATTR, attr_copy); |
1377 | |
|
1378 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1379 | 0 | } /* end H5A__dense_remove() */ |
1380 | | |
1381 | | /*------------------------------------------------------------------------- |
1382 | | * Function: H5A__dense_remove_by_idx_bt2_cb |
1383 | | * |
1384 | | * Purpose: v2 B-tree callback for dense attribute storage record removal by index |
1385 | | * |
1386 | | * Return: SUCCEED/FAIL |
1387 | | * |
1388 | | *------------------------------------------------------------------------- |
1389 | | */ |
1390 | | static herr_t |
1391 | | H5A__dense_remove_by_idx_bt2_cb(const void *_record, void *_bt2_udata) |
1392 | 0 | { |
1393 | 0 | H5HF_t *fheap; /* Fractal heap handle */ |
1394 | 0 | H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */ |
1395 | 0 | const H5A_dense_bt2_name_rec_t *record = (const H5A_dense_bt2_name_rec_t *)_record; /* v2 B-tree record */ |
1396 | 0 | H5A_bt2_ud_rmbi_t *bt2_udata = (H5A_bt2_ud_rmbi_t *)_bt2_udata; /* User data for callback */ |
1397 | 0 | H5A_fh_ud_cp_t fh_udata; /* User data for fractal heap 'op' callback */ |
1398 | 0 | H5O_shared_t sh_loc; /* Shared message info for attribute */ |
1399 | 0 | bool use_sh_loc; /* Whether to use the attribute's shared location or the separate one */ |
1400 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1401 | |
|
1402 | 0 | FUNC_ENTER_PACKAGE |
1403 | | |
1404 | | /* Set up the user data for fractal heap 'op' callback */ |
1405 | 0 | fh_udata.f = bt2_udata->f; |
1406 | 0 | fh_udata.record = record; |
1407 | 0 | fh_udata.attr = NULL; |
1408 | | |
1409 | | /* Get correct fractal heap handle to use for operations */ |
1410 | 0 | if (record->flags & H5O_MSG_FLAG_SHARED) |
1411 | 0 | fheap = bt2_udata->shared_fheap; |
1412 | 0 | else |
1413 | 0 | fheap = bt2_udata->fheap; |
1414 | | |
1415 | | /* Check whether to make a copy of the attribute or just need the shared location info */ |
1416 | 0 | if (H5_addr_defined(bt2_udata->other_bt2_addr) || !(record->flags & H5O_MSG_FLAG_SHARED)) { |
1417 | | /* Call fractal heap 'op' routine, to make copy of attribute to remove */ |
1418 | 0 | if (H5HF_op(fheap, &record->id, H5A__dense_copy_fh_cb, &fh_udata) < 0) |
1419 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPERATE, FAIL, "attribute removal callback failed"); |
1420 | 0 | assert(fh_udata.attr); |
1421 | | |
1422 | | /* Use the attribute's shared location */ |
1423 | 0 | use_sh_loc = false; |
1424 | 0 | } /* end if */ |
1425 | 0 | else { |
1426 | | /* Create a shared message location from the heap ID for this record */ |
1427 | 0 | H5SM_reconstitute(&sh_loc, bt2_udata->f, H5O_ATTR_ID, record->id); |
1428 | | |
1429 | | /* Use the separate shared location */ |
1430 | 0 | use_sh_loc = true; |
1431 | 0 | } /* end else */ |
1432 | | |
1433 | | /* Check for removing the link from the "other" index (creation order, when name used and vice versa) */ |
1434 | 0 | if (H5_addr_defined(bt2_udata->other_bt2_addr)) { |
1435 | 0 | H5A_bt2_ud_common_t other_bt2_udata; /* Info for B-tree callbacks */ |
1436 | | |
1437 | | /* Determine the index being used */ |
1438 | 0 | if (bt2_udata->idx_type == H5_INDEX_NAME) { |
1439 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1440 | 0 | other_bt2_udata.corder = fh_udata.attr->shared->crt_idx; |
1441 | 0 | } /* end if */ |
1442 | 0 | else { |
1443 | 0 | assert(bt2_udata->idx_type == H5_INDEX_CRT_ORDER); |
1444 | | |
1445 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1446 | 0 | other_bt2_udata.f = bt2_udata->f; |
1447 | 0 | other_bt2_udata.fheap = bt2_udata->fheap; |
1448 | 0 | other_bt2_udata.shared_fheap = bt2_udata->shared_fheap; |
1449 | 0 | other_bt2_udata.name = fh_udata.attr->shared->name; |
1450 | 0 | other_bt2_udata.name_hash = |
1451 | 0 | H5_checksum_lookup3(fh_udata.attr->shared->name, strlen(fh_udata.attr->shared->name), 0); |
1452 | 0 | other_bt2_udata.found_op = NULL; |
1453 | 0 | other_bt2_udata.found_op_data = NULL; |
1454 | 0 | } /* end else */ |
1455 | | |
1456 | | /* Open the index v2 B-tree */ |
1457 | 0 | if (NULL == (bt2 = H5B2_open(bt2_udata->f, bt2_udata->other_bt2_addr, NULL))) |
1458 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index"); |
1459 | | |
1460 | | /* Set the common information for the v2 B-tree remove operation */ |
1461 | | |
1462 | | /* Remove the record from the "other" index v2 B-tree */ |
1463 | 0 | if (H5B2_remove(bt2, &other_bt2_udata, NULL, NULL) < 0) |
1464 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, |
1465 | 0 | "unable to remove record from 'other' index v2 B-tree"); |
1466 | 0 | } /* end if */ |
1467 | | |
1468 | | /* Check for removing shared attribute */ |
1469 | 0 | if (record->flags & H5O_MSG_FLAG_SHARED) { |
1470 | 0 | H5O_shared_t *sh_loc_ptr; /* Pointer to shared message info for attribute */ |
1471 | | |
1472 | | /* Set up pointer to correct shared location */ |
1473 | 0 | if (use_sh_loc) |
1474 | 0 | sh_loc_ptr = &sh_loc; |
1475 | 0 | else |
1476 | 0 | sh_loc_ptr = &(fh_udata.attr->sh_loc); |
1477 | | |
1478 | | /* Decrement the reference count on the shared attribute message */ |
1479 | 0 | if (H5SM_delete(bt2_udata->f, NULL, sh_loc_ptr) < 0) |
1480 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to delete shared attribute"); |
1481 | 0 | } /* end if */ |
1482 | 0 | else { |
1483 | | /* Perform the deletion action on the attribute */ |
1484 | | /* (takes care of shared & committed datatype/dataspace components) */ |
1485 | 0 | if (H5O__attr_delete(bt2_udata->f, NULL, fh_udata.attr) < 0) |
1486 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute"); |
1487 | | |
1488 | | /* Remove record from fractal heap */ |
1489 | 0 | if (H5HF_remove(fheap, &record->id) < 0) |
1490 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from fractal heap"); |
1491 | 0 | } /* end else */ |
1492 | | |
1493 | 0 | done: |
1494 | | /* Release resources */ |
1495 | 0 | if (bt2 && H5B2_close(bt2) < 0) |
1496 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index"); |
1497 | 0 | if (fh_udata.attr) |
1498 | 0 | H5O_msg_free(H5O_ATTR_ID, fh_udata.attr); |
1499 | |
|
1500 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1501 | 0 | } /* end H5A__dense_remove_by_idx_bt2_cb() */ |
1502 | | |
1503 | | /*------------------------------------------------------------------------- |
1504 | | * Function: H5A__dense_remove_by_idx |
1505 | | * |
1506 | | * Purpose: Remove an attribute from the dense storage of an object, |
1507 | | * according to the order within an index |
1508 | | * |
1509 | | * Return: SUCCEED/FAIL |
1510 | | * |
1511 | | *------------------------------------------------------------------------- |
1512 | | */ |
1513 | | herr_t |
1514 | | H5A__dense_remove_by_idx(H5F_t *f, const H5O_ainfo_t *ainfo, H5_index_t idx_type, H5_iter_order_t order, |
1515 | | hsize_t n) |
1516 | 0 | { |
1517 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
1518 | 0 | H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */ |
1519 | 0 | H5A_attr_table_t atable = {0, 0, NULL}; /* Table of attributes */ |
1520 | 0 | H5B2_t *bt2 = NULL; /* v2 B-tree handle for index */ |
1521 | 0 | haddr_t bt2_addr; /* Address of v2 B-tree to use for operation */ |
1522 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1523 | |
|
1524 | 0 | FUNC_ENTER_PACKAGE |
1525 | | |
1526 | | /* Check arguments */ |
1527 | 0 | assert(f); |
1528 | 0 | assert(ainfo); |
1529 | | |
1530 | | /* Determine the address of the index to use */ |
1531 | 0 | if (idx_type == H5_INDEX_NAME) { |
1532 | | /* Check if "native" order is OK - since names are hashed, getting them |
1533 | | * in strictly increasing or decreasing order requires building a |
1534 | | * table and sorting it. |
1535 | | */ |
1536 | 0 | if (order == H5_ITER_NATIVE) { |
1537 | 0 | bt2_addr = ainfo->name_bt2_addr; |
1538 | 0 | assert(H5_addr_defined(bt2_addr)); |
1539 | 0 | } /* end if */ |
1540 | 0 | else |
1541 | 0 | bt2_addr = HADDR_UNDEF; |
1542 | 0 | } /* end if */ |
1543 | 0 | else { |
1544 | 0 | assert(idx_type == H5_INDEX_CRT_ORDER); |
1545 | | |
1546 | | /* This address may not be defined if creation order is tracked, but |
1547 | | * there's no index on it. If there's no v2 B-tree that indexes |
1548 | | * the links, a table will be built. |
1549 | | */ |
1550 | 0 | bt2_addr = ainfo->corder_bt2_addr; |
1551 | 0 | } /* end else */ |
1552 | | |
1553 | | /* If there is an index defined for the field, use it */ |
1554 | 0 | if (H5_addr_defined(bt2_addr)) { |
1555 | 0 | H5A_bt2_ud_rmbi_t udata; /* User data for v2 B-tree record removal */ |
1556 | 0 | htri_t attr_sharable; /* Flag indicating attributes are shareable */ |
1557 | | |
1558 | | /* Open the fractal heap */ |
1559 | 0 | if (NULL == (fheap = H5HF_open(f, ainfo->fheap_addr))) |
1560 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1561 | | |
1562 | | /* Check if attributes are shared in this file */ |
1563 | 0 | if ((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID)) < 0) |
1564 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared"); |
1565 | | |
1566 | | /* Get handle for shared message heap, if attributes are shareable */ |
1567 | 0 | if (attr_sharable) { |
1568 | 0 | haddr_t shared_fheap_addr; /* Address of fractal heap to use */ |
1569 | | |
1570 | | /* Retrieve the address of the shared message's fractal heap */ |
1571 | 0 | if (H5SM_get_fheap_addr(f, H5O_ATTR_ID, &shared_fheap_addr) < 0) |
1572 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address"); |
1573 | | |
1574 | | /* Check if there are any shared messages currently */ |
1575 | 0 | if (H5_addr_defined(shared_fheap_addr)) { |
1576 | | /* Open the fractal heap for shared header messages */ |
1577 | 0 | if (NULL == (shared_fheap = H5HF_open(f, shared_fheap_addr))) |
1578 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1579 | 0 | } /* end if */ |
1580 | 0 | } /* end if */ |
1581 | | |
1582 | | /* Open the index v2 B-tree */ |
1583 | 0 | if (NULL == (bt2 = H5B2_open(f, bt2_addr, NULL))) |
1584 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index"); |
1585 | | |
1586 | | /* Set up the user data for the v2 B-tree 'record remove' callback */ |
1587 | 0 | udata.f = f; |
1588 | 0 | udata.fheap = fheap; |
1589 | 0 | udata.shared_fheap = shared_fheap; |
1590 | 0 | udata.idx_type = idx_type; |
1591 | 0 | udata.other_bt2_addr = idx_type == H5_INDEX_NAME ? ainfo->corder_bt2_addr : ainfo->name_bt2_addr; |
1592 | | |
1593 | | /* Remove the record from the name index v2 B-tree */ |
1594 | 0 | if (H5B2_remove_by_idx(bt2, order, n, H5A__dense_remove_by_idx_bt2_cb, &udata) < 0) |
1595 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTREMOVE, FAIL, "unable to remove attribute from v2 B-tree index"); |
1596 | 0 | } /* end if */ |
1597 | 0 | else { |
1598 | | /* Build the table of attributes for this object */ |
1599 | | /* (build table using the name index, but sort according to idx_type) */ |
1600 | 0 | if (H5A__dense_build_table(f, ainfo, idx_type, order, &atable) < 0) |
1601 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "error building table of attributes"); |
1602 | | |
1603 | | /* Check for skipping too many attributes */ |
1604 | 0 | if (n >= atable.num_attrs) |
1605 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index specified"); |
1606 | | |
1607 | | /* Delete appropriate attribute from dense storage */ |
1608 | 0 | if (H5A__dense_remove(f, ainfo, ((atable.attrs[n])->shared)->name) < 0) |
1609 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute in dense storage"); |
1610 | 0 | } /* end else */ |
1611 | | |
1612 | 0 | done: |
1613 | | /* Release resources */ |
1614 | 0 | if (shared_fheap && H5HF_close(shared_fheap) < 0) |
1615 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1616 | 0 | if (fheap && H5HF_close(fheap) < 0) |
1617 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1618 | 0 | if (bt2 && H5B2_close(bt2) < 0) |
1619 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index"); |
1620 | 0 | if (atable.attrs && H5A__attr_release_table(&atable) < 0) |
1621 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to release attribute table"); |
1622 | |
|
1623 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1624 | 0 | } /* end H5A__dense_remove_by_idx() */ |
1625 | | |
1626 | | /*------------------------------------------------------------------------- |
1627 | | * Function: H5A__dense_exists |
1628 | | * |
1629 | | * Purpose: Check if an attribute exists in dense storage structures for |
1630 | | * an object |
1631 | | * |
1632 | | * Return: SUCCEED/FAIL |
1633 | | * |
1634 | | *------------------------------------------------------------------------- |
1635 | | */ |
1636 | | herr_t |
1637 | | H5A__dense_exists(H5F_t *f, const H5O_ainfo_t *ainfo, const char *name, bool *attr_exists) |
1638 | 0 | { |
1639 | 0 | H5A_bt2_ud_common_t udata; /* User data for v2 B-tree modify */ |
1640 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
1641 | 0 | H5HF_t *shared_fheap = NULL; /* Fractal heap handle for shared header messages */ |
1642 | 0 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */ |
1643 | 0 | htri_t attr_sharable; /* Flag indicating attributes are shareable */ |
1644 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1645 | |
|
1646 | 0 | FUNC_ENTER_PACKAGE |
1647 | | |
1648 | | /* Check arguments */ |
1649 | 0 | assert(f); |
1650 | 0 | assert(ainfo); |
1651 | 0 | assert(name); |
1652 | 0 | assert(attr_exists); |
1653 | | |
1654 | | /* Open the fractal heap */ |
1655 | 0 | if (NULL == (fheap = H5HF_open(f, ainfo->fheap_addr))) |
1656 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1657 | | |
1658 | | /* Check if attributes are shared in this file */ |
1659 | 0 | if ((attr_sharable = H5SM_type_shared(f, H5O_ATTR_ID)) < 0) |
1660 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't determine if attributes are shared"); |
1661 | | |
1662 | | /* Get handle for shared message heap, if attributes are shareable */ |
1663 | 0 | if (attr_sharable) { |
1664 | 0 | haddr_t shared_fheap_addr; /* Address of fractal heap to use */ |
1665 | | |
1666 | | /* Retrieve the address of the shared message's fractal heap */ |
1667 | 0 | if (H5SM_get_fheap_addr(f, H5O_ATTR_ID, &shared_fheap_addr) < 0) |
1668 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, FAIL, "can't get shared message heap address"); |
1669 | | |
1670 | | /* Check if there are any shared messages currently */ |
1671 | 0 | if (H5_addr_defined(shared_fheap_addr)) { |
1672 | | /* Open the fractal heap for shared header messages */ |
1673 | 0 | if (NULL == (shared_fheap = H5HF_open(f, shared_fheap_addr))) |
1674 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1675 | 0 | } /* end if */ |
1676 | 0 | } /* end if */ |
1677 | | |
1678 | | /* Open the name index v2 B-tree */ |
1679 | 0 | if (NULL == (bt2_name = H5B2_open(f, ainfo->name_bt2_addr, NULL))) |
1680 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index"); |
1681 | | |
1682 | | /* Create the "udata" information for v2 B-tree record 'find' */ |
1683 | 0 | udata.f = f; |
1684 | 0 | udata.fheap = fheap; |
1685 | 0 | udata.shared_fheap = shared_fheap; |
1686 | 0 | udata.name = name; |
1687 | 0 | udata.name_hash = H5_checksum_lookup3(name, strlen(name), 0); |
1688 | 0 | udata.flags = 0; |
1689 | 0 | udata.corder = 0; |
1690 | 0 | udata.found_op = NULL; /* v2 B-tree comparison callback */ |
1691 | 0 | udata.found_op_data = NULL; |
1692 | | |
1693 | | /* Find the attribute in the 'name' index */ |
1694 | 0 | if (H5B2_find(bt2_name, &udata, attr_exists, NULL, NULL) < 0) |
1695 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_NOTFOUND, FAIL, "can't search for attribute in name index"); |
1696 | | |
1697 | 0 | done: |
1698 | | /* Release resources */ |
1699 | 0 | if (shared_fheap && H5HF_close(shared_fheap) < 0) |
1700 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1701 | 0 | if (fheap && H5HF_close(fheap) < 0) |
1702 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1703 | 0 | if (bt2_name && H5B2_close(bt2_name) < 0) |
1704 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
1705 | |
|
1706 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1707 | 0 | } /* end H5A__dense_exists() */ |
1708 | | |
1709 | | /*------------------------------------------------------------------------- |
1710 | | * Function: H5A__dense_delete_bt2_cb |
1711 | | * |
1712 | | * Purpose: v2 B-tree callback for dense attribute storage deletion |
1713 | | * |
1714 | | * Return: SUCCEED/FAIL |
1715 | | * |
1716 | | *------------------------------------------------------------------------- |
1717 | | */ |
1718 | | static herr_t |
1719 | | H5A__dense_delete_bt2_cb(const void *_record, void *_bt2_udata) |
1720 | 0 | { |
1721 | 0 | const H5A_dense_bt2_name_rec_t *record = |
1722 | 0 | (const H5A_dense_bt2_name_rec_t *)_record; /* Record from B-tree */ |
1723 | 0 | H5A_bt2_ud_common_t *bt2_udata = (H5A_bt2_ud_common_t *)_bt2_udata; /* User data for callback */ |
1724 | 0 | H5A_t *attr = NULL; /* Attribute being removed */ |
1725 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1726 | |
|
1727 | 0 | FUNC_ENTER_PACKAGE |
1728 | | |
1729 | | /* Check for shared attribute */ |
1730 | 0 | if (record->flags & H5O_MSG_FLAG_SHARED) { |
1731 | 0 | H5O_shared_t sh_mesg; /* Temporary shared message info */ |
1732 | | |
1733 | | /* "reconstitute" the shared message info for the attribute */ |
1734 | 0 | H5SM_reconstitute(&sh_mesg, bt2_udata->f, H5O_ATTR_ID, record->id); |
1735 | | |
1736 | | /* Decrement the reference count on the shared attribute message */ |
1737 | 0 | if (H5SM_delete(bt2_udata->f, NULL, &sh_mesg) < 0) |
1738 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTFREE, FAIL, "unable to delete shared attribute"); |
1739 | 0 | } /* end if */ |
1740 | 0 | else { |
1741 | 0 | H5A_fh_ud_cp_t fh_udata; /* User data for fractal heap 'op' callback */ |
1742 | | |
1743 | | /* Prepare user data for callback */ |
1744 | | /* down */ |
1745 | 0 | fh_udata.f = bt2_udata->f; |
1746 | 0 | fh_udata.record = record; |
1747 | | /* up */ |
1748 | 0 | fh_udata.attr = NULL; |
1749 | | |
1750 | | /* Call fractal heap 'op' routine, to copy the attribute information */ |
1751 | 0 | if (H5HF_op(bt2_udata->fheap, &record->id, H5A__dense_copy_fh_cb, &fh_udata) < 0) |
1752 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPERATE, FAIL, "heap op callback failed"); |
1753 | 0 | attr = fh_udata.attr; |
1754 | | |
1755 | | /* Perform the deletion action on the attribute */ |
1756 | | /* (takes care of shared/committed datatype & dataspace components) */ |
1757 | 0 | if (H5O__attr_delete(bt2_udata->f, NULL, fh_udata.attr) < 0) |
1758 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete attribute"); |
1759 | 0 | } /* end else */ |
1760 | | |
1761 | 0 | done: |
1762 | | /* Release resources */ |
1763 | 0 | if (attr) |
1764 | 0 | H5O_msg_free_real(H5O_MSG_ATTR, attr); |
1765 | |
|
1766 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1767 | 0 | } /* end H5A__dense_delete_bt2_cb() */ |
1768 | | |
1769 | | /*------------------------------------------------------------------------- |
1770 | | * Function: H5A__dense_delete |
1771 | | * |
1772 | | * Purpose: Delete all dense storage structures for attributes on an object |
1773 | | * |
1774 | | * Return: SUCCEED/FAIL |
1775 | | * |
1776 | | *------------------------------------------------------------------------- |
1777 | | */ |
1778 | | herr_t |
1779 | | H5A__dense_delete(H5F_t *f, H5O_ainfo_t *ainfo) |
1780 | 0 | { |
1781 | 0 | H5A_bt2_ud_common_t udata; /* v2 B-tree user data for deleting attributes */ |
1782 | 0 | H5HF_t *fheap = NULL; /* Fractal heap handle */ |
1783 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1784 | |
|
1785 | 0 | FUNC_ENTER_PACKAGE |
1786 | | |
1787 | | /* Check arguments */ |
1788 | 0 | assert(f); |
1789 | 0 | assert(ainfo); |
1790 | | |
1791 | | /* Open the fractal heap */ |
1792 | 0 | if (NULL == (fheap = H5HF_open(f, ainfo->fheap_addr))) |
1793 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap"); |
1794 | | |
1795 | | /* Create the "udata" information for v2 B-tree 'delete' */ |
1796 | 0 | udata.f = f; |
1797 | 0 | udata.fheap = fheap; |
1798 | 0 | udata.shared_fheap = NULL; |
1799 | 0 | udata.name = NULL; |
1800 | 0 | udata.name_hash = 0; |
1801 | 0 | udata.flags = 0; |
1802 | 0 | udata.found_op = NULL; /* v2 B-tree comparison callback */ |
1803 | 0 | udata.found_op_data = NULL; |
1804 | | |
1805 | | /* Delete name index v2 B-tree */ |
1806 | 0 | if (H5B2_delete(f, ainfo->name_bt2_addr, NULL, H5A__dense_delete_bt2_cb, &udata) < 0) |
1807 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for name index"); |
1808 | 0 | ainfo->name_bt2_addr = HADDR_UNDEF; |
1809 | | |
1810 | | /* Release resources */ |
1811 | 0 | if (H5HF_close(fheap) < 0) |
1812 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1813 | 0 | fheap = NULL; |
1814 | | |
1815 | | /* Check if we should delete the creation order index v2 B-tree */ |
1816 | 0 | if (H5_addr_defined(ainfo->corder_bt2_addr)) { |
1817 | | /* Delete the creation order index, without adjusting the ref. count on the attributes */ |
1818 | 0 | if (H5B2_delete(f, ainfo->corder_bt2_addr, NULL, NULL, NULL) < 0) |
1819 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, |
1820 | 0 | "unable to delete v2 B-tree for creation order index"); |
1821 | 0 | ainfo->corder_bt2_addr = HADDR_UNDEF; |
1822 | 0 | } /* end if */ |
1823 | | |
1824 | | /* Delete fractal heap */ |
1825 | 0 | if (H5HF_delete(f, ainfo->fheap_addr) < 0) |
1826 | 0 | HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete fractal heap"); |
1827 | 0 | ainfo->fheap_addr = HADDR_UNDEF; |
1828 | |
|
1829 | 0 | done: |
1830 | | /* Release resources */ |
1831 | 0 | if (fheap && H5HF_close(fheap) < 0) |
1832 | 0 | HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close fractal heap"); |
1833 | |
|
1834 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1835 | 0 | } /* end H5A__dense_delete() */ |