/src/hdf5/src/H5Dbtree2.c
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 | | * Purpose: v2 B-tree indexing for chunked datasets with > 1 unlimited dimensions. |
16 | | * Each dataset chunk in the b-tree is identified by its dimensional offset. |
17 | | * |
18 | | */ |
19 | | |
20 | | /****************/ |
21 | | /* Module Setup */ |
22 | | /****************/ |
23 | | |
24 | | #include "H5Dmodule.h" /* This source code file is part of the H5D module */ |
25 | | |
26 | | /***********/ |
27 | | /* Headers */ |
28 | | /***********/ |
29 | | #include "H5private.h" /* Generic Functions */ |
30 | | #include "H5Dpkg.h" /* Datasets */ |
31 | | #include "H5FLprivate.h" /* Free Lists */ |
32 | | #include "H5MFprivate.h" /* File space management */ |
33 | | #include "H5MMprivate.h" /* Memory management */ |
34 | | #include "H5VMprivate.h" /* Vector and array functions */ |
35 | | |
36 | | /****************/ |
37 | | /* Local Macros */ |
38 | | /****************/ |
39 | | |
40 | 0 | #define H5D_BT2_IDX_IS_OPEN(idx_info) (NULL != (idx_info)->layout->storage.u.chunk.u.btree2.bt2) |
41 | | |
42 | | /* |
43 | | * Macro to compute the size required for encoding the size of a chunk. For version 4, this is the minimum |
44 | | * number of bytes required to encode the size of an unfiltered chunk plus an extra byte, in case the filter |
45 | | * makes the chunk larger. For versions after 4, this is simply the size of lengths for the file. For |
46 | | * unfiltered chunks, this is 0. |
47 | | */ |
48 | | #define H5D_BT2_COMPUTE_CHUNK_SIZE_LEN(chunk_size_len, idx_info) \ |
49 | 0 | do { \ |
50 | 0 | if ((idx_info)->pline->nused > 0) { \ |
51 | 0 | if ((idx_info)->layout->version > H5O_LAYOUT_VERSION_4) \ |
52 | 0 | (chunk_size_len) = H5F_SIZEOF_SIZE((idx_info)->f); \ |
53 | 0 | else { \ |
54 | 0 | (chunk_size_len) = \ |
55 | 0 | 1 + ((H5VM_log2_gen((uint64_t)(idx_info)->layout->u.chunk.size) + 8) / 8); \ |
56 | 0 | if ((chunk_size_len) > 8) \ |
57 | 0 | (chunk_size_len) = 8; \ |
58 | 0 | } \ |
59 | 0 | } \ |
60 | 0 | else \ |
61 | 0 | (chunk_size_len) = 0; \ |
62 | 0 | } while (0) |
63 | | |
64 | | /******************/ |
65 | | /* Local Typedefs */ |
66 | | /******************/ |
67 | | /* User data for creating callback context */ |
68 | | typedef struct H5D_bt2_ctx_ud_t { |
69 | | const H5F_t *f; /* Pointer to file info */ |
70 | | hsize_t chunk_size; /* Size of chunk (bytes; for filtered object) */ |
71 | | unsigned ndims; /* Number of dimensions */ |
72 | | size_t chunk_size_len; /* Size of chunk sizes in the file (bytes) */ |
73 | | hsize_t *dim; /* Size of chunk in elements */ |
74 | | } H5D_bt2_ctx_ud_t; |
75 | | |
76 | | /* The callback context */ |
77 | | typedef struct H5D_bt2_ctx_t { |
78 | | hsize_t chunk_size; /* Size of chunk (bytes; constant for unfiltered object) */ |
79 | | size_t sizeof_addr; /* Size of file addresses in the file (bytes) */ |
80 | | size_t chunk_size_len; /* Size of chunk sizes in the file (bytes) */ |
81 | | unsigned ndims; /* Number of dimensions in chunk */ |
82 | | hsize_t *dim; /* Size of chunk in elements */ |
83 | | } H5D_bt2_ctx_t; |
84 | | |
85 | | /* Callback info for iteration over chunks in v2 B-tree */ |
86 | | typedef struct H5D_bt2_it_ud_t { |
87 | | H5D_chunk_cb_func_t cb; /* Callback routine for the chunk */ |
88 | | void *udata; /* User data for the chunk's callback routine */ |
89 | | } H5D_bt2_it_ud_t; |
90 | | |
91 | | /* User data for compare callback */ |
92 | | typedef struct H5D_bt2_ud_t { |
93 | | H5D_chunk_rec_t rec; /* The record to search for */ |
94 | | unsigned ndims; /* Number of dimensions for the chunked dataset */ |
95 | | } H5D_bt2_ud_t; |
96 | | |
97 | | /********************/ |
98 | | /* Local Prototypes */ |
99 | | /********************/ |
100 | | |
101 | | /* Shared v2 B-tree methods for indexing filtered and non-filtered chunked datasets */ |
102 | | static void *H5D__bt2_crt_context(void *udata); |
103 | | static herr_t H5D__bt2_dst_context(void *ctx); |
104 | | static herr_t H5D__bt2_store(void *native, const void *udata); |
105 | | static herr_t H5D__bt2_compare(const void *rec1, const void *rec2, int *result); |
106 | | |
107 | | /* v2 B-tree class for indexing non-filtered chunked datasets */ |
108 | | static herr_t H5D__bt2_unfilt_encode(uint8_t *raw, const void *native, void *ctx); |
109 | | static herr_t H5D__bt2_unfilt_decode(const uint8_t *raw, void *native, void *ctx); |
110 | | static herr_t H5D__bt2_unfilt_debug(FILE *stream, int indent, int fwidth, const void *record, |
111 | | const void *u_ctx); |
112 | | |
113 | | /* v2 B-tree class for indexing filtered chunked datasets */ |
114 | | static herr_t H5D__bt2_filt_encode(uint8_t *raw, const void *native, void *ctx); |
115 | | static herr_t H5D__bt2_filt_decode(const uint8_t *raw, void *native, void *ctx); |
116 | | static herr_t H5D__bt2_filt_debug(FILE *stream, int indent, int fwidth, const void *record, |
117 | | const void *u_ctx); |
118 | | |
119 | | /* Helper routine */ |
120 | | static herr_t H5D__btree2_idx_depend(const H5D_chk_idx_info_t *idx_info); |
121 | | |
122 | | /* Callback for H5B2_iterate() which is called in H5D__bt2_idx_iterate() */ |
123 | | static int H5D__bt2_idx_iterate_cb(const void *_record, void *_udata); |
124 | | |
125 | | /* Callback for H5B2_find() which is called in H5D__bt2_idx_get_addr() */ |
126 | | static herr_t H5D__bt2_found_cb(const void *nrecord, void *op_data); |
127 | | |
128 | | /* |
129 | | * Callback for H5B2_remove() and H5B2_delete() which is called |
130 | | * in H5D__bt2_idx_remove() and H5D__bt2_idx_delete(). |
131 | | */ |
132 | | static herr_t H5D__bt2_remove_cb(const void *nrecord, void *_udata); |
133 | | |
134 | | /* Callback for H5B2_update() which is called in H5D__bt2_idx_insert() */ |
135 | | static herr_t H5D__bt2_mod_cb(void *_record, void *_op_data, bool *changed); |
136 | | |
137 | | /* Chunked layout indexing callbacks for v2 B-tree indexing */ |
138 | | static herr_t H5D__bt2_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t *space, |
139 | | haddr_t dset_ohdr_addr); |
140 | | static herr_t H5D__bt2_idx_create(const H5D_chk_idx_info_t *idx_info); |
141 | | static herr_t H5D__bt2_idx_open(const H5D_chk_idx_info_t *idx_info); |
142 | | static herr_t H5D__bt2_idx_close(const H5D_chk_idx_info_t *idx_info); |
143 | | static herr_t H5D__bt2_idx_is_open(const H5D_chk_idx_info_t *idx_info, bool *is_open); |
144 | | static bool H5D__bt2_idx_is_space_alloc(const H5O_storage_chunk_t *storage); |
145 | | static herr_t H5D__bt2_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata, |
146 | | const H5D_t *dset); |
147 | | static herr_t H5D__bt2_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata); |
148 | | static herr_t H5D__bt2_idx_load_metadata(const H5D_chk_idx_info_t *idx_info); |
149 | | static int H5D__bt2_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb, |
150 | | void *chunk_udata); |
151 | | static herr_t H5D__bt2_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata); |
152 | | static herr_t H5D__bt2_idx_delete(const H5D_chk_idx_info_t *idx_info); |
153 | | static herr_t H5D__bt2_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src, |
154 | | const H5D_chk_idx_info_t *idx_info_dst); |
155 | | static herr_t H5D__bt2_idx_copy_shutdown(H5O_storage_chunk_t *storage_src, H5O_storage_chunk_t *storage_dst); |
156 | | static herr_t H5D__bt2_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *size); |
157 | | static herr_t H5D__bt2_idx_reset(H5O_storage_chunk_t *storage, bool reset_addr); |
158 | | static herr_t H5D__bt2_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream); |
159 | | static herr_t H5D__bt2_idx_dest(const H5D_chk_idx_info_t *idx_info); |
160 | | |
161 | | /*********************/ |
162 | | /* Package Variables */ |
163 | | /*********************/ |
164 | | |
165 | | /* Chunked dataset I/O ops for v2 B-tree indexing */ |
166 | | const H5D_chunk_ops_t H5D_COPS_BT2[1] = {{ |
167 | | true, /* Fixed array indices support SWMR access */ |
168 | | H5D__bt2_idx_init, /* init */ |
169 | | H5D__bt2_idx_create, /* create */ |
170 | | H5D__bt2_idx_open, /* open */ |
171 | | H5D__bt2_idx_close, /* close */ |
172 | | H5D__bt2_idx_is_open, /* is_open */ |
173 | | H5D__bt2_idx_is_space_alloc, /* is_space_alloc */ |
174 | | H5D__bt2_idx_insert, /* insert */ |
175 | | H5D__bt2_idx_get_addr, /* get_addr */ |
176 | | H5D__bt2_idx_load_metadata, /* load_metadata */ |
177 | | NULL, /* resize */ |
178 | | H5D__bt2_idx_iterate, /* iterate */ |
179 | | H5D__bt2_idx_remove, /* remove */ |
180 | | H5D__bt2_idx_delete, /* delete */ |
181 | | H5D__bt2_idx_copy_setup, /* copy_setup */ |
182 | | H5D__bt2_idx_copy_shutdown, /* copy_shutdown */ |
183 | | H5D__bt2_idx_size, /* size */ |
184 | | H5D__bt2_idx_reset, /* reset */ |
185 | | H5D__bt2_idx_dump, /* dump */ |
186 | | H5D__bt2_idx_dest /* destroy */ |
187 | | }}; |
188 | | |
189 | | /*****************************/ |
190 | | /* Library Private Variables */ |
191 | | /*****************************/ |
192 | | |
193 | | /* v2 B-tree class for indexing non-filtered chunked datasets */ |
194 | | const H5B2_class_t H5D_BT2[1] = {{ |
195 | | /* B-tree class information */ |
196 | | H5B2_CDSET_ID, /* Type of B-tree */ |
197 | | "H5B2_CDSET_ID", /* Name of B-tree class */ |
198 | | sizeof(H5D_chunk_rec_t), /* Size of native record */ |
199 | | H5D__bt2_crt_context, /* Create client callback context */ |
200 | | H5D__bt2_dst_context, /* Destroy client callback context */ |
201 | | H5D__bt2_store, /* Record storage callback */ |
202 | | H5D__bt2_compare, /* Record comparison callback */ |
203 | | H5D__bt2_unfilt_encode, /* Record encoding callback */ |
204 | | H5D__bt2_unfilt_decode, /* Record decoding callback */ |
205 | | H5D__bt2_unfilt_debug /* Record debugging callback */ |
206 | | }}; |
207 | | |
208 | | /* v2 B-tree class for indexing filtered chunked datasets */ |
209 | | const H5B2_class_t H5D_BT2_FILT[1] = {{ |
210 | | /* B-tree class information */ |
211 | | H5B2_CDSET_FILT_ID, /* Type of B-tree */ |
212 | | "H5B2_CDSET_FILT_ID", /* Name of B-tree class */ |
213 | | sizeof(H5D_chunk_rec_t), /* Size of native record */ |
214 | | H5D__bt2_crt_context, /* Create client callback context */ |
215 | | H5D__bt2_dst_context, /* Destroy client callback context */ |
216 | | H5D__bt2_store, /* Record storage callback */ |
217 | | H5D__bt2_compare, /* Record comparison callback */ |
218 | | H5D__bt2_filt_encode, /* Record encoding callback */ |
219 | | H5D__bt2_filt_decode, /* Record decoding callback */ |
220 | | H5D__bt2_filt_debug /* Record debugging callback */ |
221 | | }}; |
222 | | |
223 | | /*******************/ |
224 | | /* Local Variables */ |
225 | | /*******************/ |
226 | | |
227 | | /* Declare a free list to manage the H5D_bt2_ctx_t struct */ |
228 | | H5FL_DEFINE_STATIC(H5D_bt2_ctx_t); |
229 | | |
230 | | /* Declare a free list to manage the page elements */ |
231 | | H5FL_ARR_DEFINE_STATIC(hsize_t, H5O_LAYOUT_NDIMS); |
232 | | |
233 | | /*------------------------------------------------------------------------- |
234 | | * Function: H5D__bt2_crt_context |
235 | | * |
236 | | * Purpose: Create client callback context |
237 | | * |
238 | | * Return: Success: non-NULL |
239 | | * Failure: NULL |
240 | | * |
241 | | *------------------------------------------------------------------------- |
242 | | */ |
243 | | static void * |
244 | | H5D__bt2_crt_context(void *_udata) |
245 | 0 | { |
246 | 0 | H5D_bt2_ctx_ud_t *udata = (H5D_bt2_ctx_ud_t *)_udata; /* User data for building callback context */ |
247 | 0 | H5D_bt2_ctx_t *ctx; /* Callback context structure */ |
248 | 0 | hsize_t *my_dim = NULL; /* Pointer to copy of chunk dimension size */ |
249 | 0 | void *ret_value = NULL; /* Return value */ |
250 | |
|
251 | 0 | FUNC_ENTER_PACKAGE |
252 | | |
253 | | /* Sanity check */ |
254 | 0 | assert(udata); |
255 | 0 | assert(udata->f); |
256 | 0 | assert(udata->ndims > 0 && udata->ndims < H5O_LAYOUT_NDIMS); |
257 | | |
258 | | /* Allocate callback context */ |
259 | 0 | if (NULL == (ctx = H5FL_MALLOC(H5D_bt2_ctx_t))) |
260 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate callback context"); |
261 | | |
262 | | /* Determine the size of addresses and set the chunk size, # of dimensions for the dataset, and bytes used |
263 | | * to encode the chunk size */ |
264 | 0 | ctx->sizeof_addr = H5F_SIZEOF_ADDR(udata->f); |
265 | 0 | ctx->chunk_size = udata->chunk_size; |
266 | 0 | ctx->ndims = udata->ndims; |
267 | 0 | ctx->chunk_size_len = udata->chunk_size_len; |
268 | | |
269 | | /* Set up the "local" information for this dataset's chunk dimension sizes */ |
270 | 0 | if (NULL == (my_dim = (hsize_t *)H5FL_ARR_MALLOC(hsize_t, H5O_LAYOUT_NDIMS))) |
271 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, NULL, "can't allocate chunk dims"); |
272 | 0 | H5MM_memcpy(my_dim, udata->dim, H5O_LAYOUT_NDIMS * sizeof(hsize_t)); |
273 | 0 | ctx->dim = my_dim; |
274 | | |
275 | | /* Set return value */ |
276 | 0 | ret_value = ctx; |
277 | |
|
278 | 0 | done: |
279 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
280 | 0 | } /* H5D__bt2_crt_context() */ |
281 | | |
282 | | /*------------------------------------------------------------------------- |
283 | | * Function: H5D__bt2_dst_context |
284 | | * |
285 | | * Purpose: Destroy client callback context |
286 | | * |
287 | | * Return: Success: non-negative |
288 | | * Failure: negative |
289 | | * |
290 | | *------------------------------------------------------------------------- |
291 | | */ |
292 | | static herr_t |
293 | | H5D__bt2_dst_context(void *_ctx) |
294 | 0 | { |
295 | 0 | H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */ |
296 | |
|
297 | 0 | FUNC_ENTER_PACKAGE_NOERR |
298 | | |
299 | | /* Sanity check */ |
300 | 0 | assert(ctx); |
301 | | |
302 | | /* Free array for chunk dimension sizes */ |
303 | 0 | if (ctx->dim) |
304 | 0 | H5FL_ARR_FREE(hsize_t, ctx->dim); |
305 | | /* Release callback context */ |
306 | 0 | ctx = H5FL_FREE(H5D_bt2_ctx_t, ctx); |
307 | |
|
308 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
309 | 0 | } /* H5D__bt2_dst_context() */ |
310 | | |
311 | | /*------------------------------------------------------------------------- |
312 | | * Function: H5D__bt2_store |
313 | | * |
314 | | * Purpose: Store native information into record for v2 B-tree |
315 | | * (non-filtered) |
316 | | * |
317 | | * Return: Success: non-negative |
318 | | * Failure: negative |
319 | | * |
320 | | *------------------------------------------------------------------------- |
321 | | */ |
322 | | static herr_t |
323 | | H5D__bt2_store(void *record, const void *_udata) |
324 | 0 | { |
325 | 0 | const H5D_bt2_ud_t *udata = (const H5D_bt2_ud_t *)_udata; /* User data */ |
326 | |
|
327 | 0 | FUNC_ENTER_PACKAGE_NOERR |
328 | |
|
329 | 0 | *(H5D_chunk_rec_t *)record = udata->rec; |
330 | |
|
331 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
332 | 0 | } /* H5D__bt2_store() */ |
333 | | |
334 | | /*------------------------------------------------------------------------- |
335 | | * Function: H5D__bt2_compare |
336 | | * |
337 | | * Purpose: Compare two native information records, according to some |
338 | | * key (non-filtered) |
339 | | * |
340 | | * Return: <0 if rec1 < rec2 |
341 | | * =0 if rec1 == rec2 |
342 | | * >0 if rec1 > rec2 |
343 | | * |
344 | | *------------------------------------------------------------------------- |
345 | | */ |
346 | | static herr_t |
347 | | H5D__bt2_compare(const void *_udata, const void *_rec2, int *result) |
348 | 0 | { |
349 | 0 | const H5D_bt2_ud_t *udata = (const H5D_bt2_ud_t *)_udata; /* User data */ |
350 | 0 | const H5D_chunk_rec_t *rec1 = &(udata->rec); /* The search record */ |
351 | 0 | const H5D_chunk_rec_t *rec2 = (const H5D_chunk_rec_t *)_rec2; /* The native record */ |
352 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
353 | |
|
354 | 0 | FUNC_ENTER_PACKAGE_NOERR |
355 | | |
356 | | /* Sanity checks */ |
357 | 0 | assert(rec1); |
358 | 0 | assert(rec2); |
359 | | |
360 | | /* Compare the offsets but ignore the other fields */ |
361 | 0 | *result = H5VM_vector_cmp_u(udata->ndims, rec1->scaled, rec2->scaled); |
362 | |
|
363 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
364 | 0 | } /* H5D__bt2_compare() */ |
365 | | |
366 | | /*------------------------------------------------------------------------- |
367 | | * Function: H5D__bt2_unfilt_encode |
368 | | * |
369 | | * Purpose: Encode native information into raw form for storing on disk |
370 | | * (non-filtered) |
371 | | * |
372 | | * Return: Success: non-negative |
373 | | * Failure: negative |
374 | | * |
375 | | *------------------------------------------------------------------------- |
376 | | */ |
377 | | static herr_t |
378 | | H5D__bt2_unfilt_encode(uint8_t *raw, const void *_record, void *_ctx) |
379 | 0 | { |
380 | 0 | H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */ |
381 | 0 | const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */ |
382 | 0 | unsigned u; /* Local index variable */ |
383 | |
|
384 | 0 | FUNC_ENTER_PACKAGE_NOERR |
385 | | |
386 | | /* Sanity check */ |
387 | 0 | assert(ctx); |
388 | | |
389 | | /* Encode the record's fields */ |
390 | 0 | H5F_addr_encode_len(ctx->sizeof_addr, &raw, record->chunk_addr); |
391 | | /* (Don't encode the chunk size & filter mask for non-filtered B-tree records) */ |
392 | 0 | for (u = 0; u < ctx->ndims; u++) |
393 | 0 | UINT64ENCODE(raw, record->scaled[u]); |
394 | |
|
395 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
396 | 0 | } /* H5D__bt2_unfilt_encode() */ |
397 | | |
398 | | /*------------------------------------------------------------------------- |
399 | | * Function: H5D__bt2_unfilt_decode |
400 | | * |
401 | | * Purpose: Decode raw disk form of record into native form |
402 | | * (non-filtered) |
403 | | * |
404 | | * Return: Success: non-negative |
405 | | * Failure: negative |
406 | | * |
407 | | *------------------------------------------------------------------------- |
408 | | */ |
409 | | static herr_t |
410 | | H5D__bt2_unfilt_decode(const uint8_t *raw, void *_record, void *_ctx) |
411 | 0 | { |
412 | 0 | H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */ |
413 | 0 | H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* The native record */ |
414 | 0 | unsigned u; /* Local index variable */ |
415 | |
|
416 | 0 | FUNC_ENTER_PACKAGE_NOERR |
417 | | |
418 | | /* Sanity check */ |
419 | 0 | assert(ctx); |
420 | | |
421 | | /* Decode the record's fields */ |
422 | 0 | H5F_addr_decode_len(ctx->sizeof_addr, &raw, &record->chunk_addr); |
423 | 0 | record->nbytes = ctx->chunk_size; |
424 | 0 | record->filter_mask = 0; |
425 | 0 | for (u = 0; u < ctx->ndims; u++) |
426 | 0 | UINT64DECODE(raw, record->scaled[u]); |
427 | |
|
428 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
429 | 0 | } /* H5D__bt2_unfilt_decode() */ |
430 | | |
431 | | /*------------------------------------------------------------------------- |
432 | | * Function: H5D__bt2_unfilt_debug |
433 | | * |
434 | | * Purpose: Debug native form of record (non-filtered) |
435 | | * |
436 | | * Return: Success: non-negative |
437 | | * Failure: negative |
438 | | * |
439 | | *------------------------------------------------------------------------- |
440 | | */ |
441 | | static herr_t |
442 | | H5D__bt2_unfilt_debug(FILE *stream, int indent, int fwidth, const void *_record, const void *_ctx) |
443 | 0 | { |
444 | 0 | const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */ |
445 | 0 | const H5D_bt2_ctx_t *ctx = (const H5D_bt2_ctx_t *)_ctx; /* Callback context */ |
446 | 0 | unsigned u; /* Local index variable */ |
447 | |
|
448 | 0 | FUNC_ENTER_PACKAGE_NOERR |
449 | | |
450 | | /* Sanity checks */ |
451 | 0 | assert(record); |
452 | 0 | assert(ctx->chunk_size == record->nbytes); |
453 | 0 | assert(0 == record->filter_mask); |
454 | |
|
455 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth, "Chunk address:", record->chunk_addr); |
456 | |
|
457 | 0 | fprintf(stream, "%*s%-*s {", indent, "", fwidth, "Logical offset:"); |
458 | 0 | for (u = 0; u < ctx->ndims; u++) |
459 | 0 | fprintf(stream, "%s%" PRIuHSIZE, u ? ", " : "", record->scaled[u] * ctx->dim[u]); |
460 | 0 | fputs("}\n", stream); |
461 | |
|
462 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
463 | 0 | } /* H5D__bt2_unfilt_debug() */ |
464 | | |
465 | | /*------------------------------------------------------------------------- |
466 | | * Function: H5D__bt2_filt_encode |
467 | | * |
468 | | * Purpose: Encode native information into raw form for storing on disk |
469 | | * (filtered) |
470 | | * |
471 | | * Return: Success: non-negative |
472 | | * Failure: negative |
473 | | * |
474 | | *------------------------------------------------------------------------- |
475 | | */ |
476 | | static herr_t |
477 | | H5D__bt2_filt_encode(uint8_t *raw, const void *_record, void *_ctx) |
478 | 0 | { |
479 | 0 | H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */ |
480 | 0 | const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */ |
481 | 0 | unsigned u; /* Local index variable */ |
482 | |
|
483 | 0 | FUNC_ENTER_PACKAGE_NOERR |
484 | | |
485 | | /* Sanity check */ |
486 | 0 | assert(ctx); |
487 | 0 | assert(record); |
488 | 0 | assert(H5_addr_defined(record->chunk_addr)); |
489 | 0 | assert(0 != record->nbytes); |
490 | | |
491 | | /* Encode the record's fields */ |
492 | 0 | H5F_addr_encode_len(ctx->sizeof_addr, &raw, record->chunk_addr); |
493 | 0 | UINT64ENCODE_VAR(raw, record->nbytes, ctx->chunk_size_len); |
494 | 0 | UINT32ENCODE(raw, record->filter_mask); |
495 | 0 | for (u = 0; u < ctx->ndims; u++) |
496 | 0 | UINT64ENCODE(raw, record->scaled[u]); |
497 | |
|
498 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
499 | 0 | } /* H5D__bt2_filt_encode() */ |
500 | | |
501 | | /*------------------------------------------------------------------------- |
502 | | * Function: H5D__bt2_filt_decode |
503 | | * |
504 | | * Purpose: Decode raw disk form of record into native form |
505 | | * (filtered) |
506 | | * |
507 | | * Return: Success: non-negative |
508 | | * Failure: negative |
509 | | * |
510 | | *------------------------------------------------------------------------- |
511 | | */ |
512 | | static herr_t |
513 | | H5D__bt2_filt_decode(const uint8_t *raw, void *_record, void *_ctx) |
514 | 0 | { |
515 | 0 | H5D_bt2_ctx_t *ctx = (H5D_bt2_ctx_t *)_ctx; /* Callback context structure */ |
516 | 0 | H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* The native record */ |
517 | 0 | unsigned u; /* Local index variable */ |
518 | |
|
519 | 0 | FUNC_ENTER_PACKAGE_NOERR |
520 | | |
521 | | /* Sanity check */ |
522 | 0 | assert(ctx); |
523 | 0 | assert(record); |
524 | | |
525 | | /* Decode the record's fields */ |
526 | 0 | H5F_addr_decode_len(ctx->sizeof_addr, &raw, &record->chunk_addr); |
527 | 0 | UINT64DECODE_VAR(raw, record->nbytes, ctx->chunk_size_len); |
528 | 0 | UINT32DECODE(raw, record->filter_mask); |
529 | 0 | for (u = 0; u < ctx->ndims; u++) |
530 | 0 | UINT64DECODE(raw, record->scaled[u]); |
531 | | |
532 | | /* Sanity checks */ |
533 | 0 | assert(H5_addr_defined(record->chunk_addr)); |
534 | 0 | assert(0 != record->nbytes); |
535 | |
|
536 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
537 | 0 | } /* H5D__bt2_filt_decode() */ |
538 | | |
539 | | /*------------------------------------------------------------------------- |
540 | | * Function: H5D__bt2_filt_debug |
541 | | * |
542 | | * Purpose: Debug native form of record (filtered) |
543 | | * |
544 | | * Return: Success: non-negative |
545 | | * Failure: negative |
546 | | * |
547 | | *------------------------------------------------------------------------- |
548 | | */ |
549 | | static herr_t |
550 | | H5D__bt2_filt_debug(FILE *stream, int indent, int fwidth, const void *_record, const void *_ctx) |
551 | 0 | { |
552 | 0 | const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */ |
553 | 0 | const H5D_bt2_ctx_t *ctx = (const H5D_bt2_ctx_t *)_ctx; /* Callback context */ |
554 | 0 | unsigned u; /* Local index variable */ |
555 | |
|
556 | 0 | FUNC_ENTER_PACKAGE_NOERR |
557 | | |
558 | | /* Sanity checks */ |
559 | 0 | assert(record); |
560 | 0 | assert(H5_addr_defined(record->chunk_addr)); |
561 | 0 | assert(0 != record->nbytes); |
562 | |
|
563 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth, "Chunk address:", record->chunk_addr); |
564 | 0 | fprintf(stream, "%*s%-*s %" PRIuHSIZE " bytes\n", indent, "", fwidth, "Chunk size:", record->nbytes); |
565 | 0 | fprintf(stream, "%*s%-*s 0x%08x\n", indent, "", fwidth, "Filter mask:", record->filter_mask); |
566 | |
|
567 | 0 | fprintf(stream, "%*s%-*s {", indent, "", fwidth, "Logical offset:"); |
568 | 0 | for (u = 0; u < ctx->ndims; u++) |
569 | 0 | fprintf(stream, "%s%" PRIuHSIZE, u ? ", " : "", record->scaled[u] * ctx->dim[u]); |
570 | 0 | fputs("}\n", stream); |
571 | |
|
572 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
573 | 0 | } /* H5D__bt2_filt_debug() */ |
574 | | |
575 | | /*------------------------------------------------------------------------- |
576 | | * Function: H5D__bt2_idx_init |
577 | | * |
578 | | * Purpose: Initialize the indexing information for a dataset. |
579 | | * |
580 | | * Return: Non-negative on success/Negative on failure |
581 | | * |
582 | | *------------------------------------------------------------------------- |
583 | | */ |
584 | | static herr_t |
585 | | H5D__bt2_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t H5_ATTR_UNUSED *space, |
586 | | haddr_t dset_ohdr_addr) |
587 | 0 | { |
588 | 0 | FUNC_ENTER_PACKAGE_NOERR |
589 | | |
590 | | /* Check args */ |
591 | 0 | assert(H5_addr_defined(dset_ohdr_addr)); |
592 | |
|
593 | 0 | idx_info->layout->storage.u.chunk.u.btree2.dset_ohdr_addr = dset_ohdr_addr; |
594 | |
|
595 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
596 | 0 | } /* end H5D__bt2_idx_init() */ |
597 | | |
598 | | /*------------------------------------------------------------------------- |
599 | | * Function: H5D__btree2_idx_depend |
600 | | * |
601 | | * Purpose: Create flush dependency between v2 B-tree and dataset's |
602 | | * object header. |
603 | | * |
604 | | * Return: Success: non-negative |
605 | | * Failure: negative |
606 | | * |
607 | | *------------------------------------------------------------------------- |
608 | | */ |
609 | | static herr_t |
610 | | H5D__btree2_idx_depend(const H5D_chk_idx_info_t *idx_info) |
611 | 0 | { |
612 | 0 | H5O_t *oh = NULL; /* Object header */ |
613 | 0 | H5O_loc_t oloc; /* Temporary object header location for dataset */ |
614 | 0 | H5AC_proxy_entry_t *oh_proxy; /* Dataset's object header proxy */ |
615 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
616 | |
|
617 | 0 | FUNC_ENTER_PACKAGE |
618 | | |
619 | | /* Check args */ |
620 | 0 | assert(idx_info); |
621 | 0 | assert(idx_info->f); |
622 | 0 | assert(H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE); |
623 | 0 | assert(idx_info->pline); |
624 | 0 | assert(idx_info->layout); |
625 | 0 | assert(H5D_CHUNK_IDX_BT2 == idx_info->layout->u.chunk.idx_type); |
626 | 0 | assert(H5D_CHUNK_IDX_BT2 == idx_info->layout->storage.u.chunk.idx_type); |
627 | 0 | assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)); |
628 | 0 | assert(idx_info->layout->storage.u.chunk.u.btree2.bt2); |
629 | | |
630 | | /* Set up object header location for dataset */ |
631 | 0 | H5O_loc_reset(&oloc); |
632 | 0 | oloc.file = idx_info->f; |
633 | 0 | oloc.addr = idx_info->layout->storage.u.chunk.u.btree.dset_ohdr_addr; |
634 | | |
635 | | /* Get header */ |
636 | 0 | if (NULL == (oh = H5O_protect(&oloc, H5AC__READ_ONLY_FLAG, true))) |
637 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTPROTECT, FAIL, "unable to protect object header"); |
638 | | |
639 | | /* Retrieve the dataset's object header proxy */ |
640 | 0 | if (NULL == (oh_proxy = H5O_get_proxy(oh))) |
641 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get dataset object header proxy"); |
642 | | |
643 | | /* Make the v2 B-tree a child flush dependency of the dataset's object header proxy */ |
644 | 0 | if (H5B2_depend(idx_info->layout->storage.u.chunk.u.btree2.bt2, oh_proxy) < 0) |
645 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, |
646 | 0 | "unable to create flush dependency on object header proxy"); |
647 | | |
648 | 0 | done: |
649 | | /* Release the object header from the cache */ |
650 | 0 | if (oh && H5O_unprotect(&oloc, oh, H5AC__NO_FLAGS_SET) < 0) |
651 | 0 | HDONE_ERROR(H5E_DATASET, H5E_CANTUNPROTECT, FAIL, "unable to release object header"); |
652 | |
|
653 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
654 | 0 | } /* end H5D__btree2_idx_depend() */ |
655 | | |
656 | | /*------------------------------------------------------------------------- |
657 | | * Function: H5D__bt2_idx_create |
658 | | * |
659 | | * Purpose: Create the v2 B-tree for tracking dataset chunks |
660 | | * |
661 | | * Return: SUCCEED/FAIL |
662 | | * |
663 | | *------------------------------------------------------------------------- |
664 | | */ |
665 | | static herr_t |
666 | | H5D__bt2_idx_create(const H5D_chk_idx_info_t *idx_info) |
667 | 0 | { |
668 | 0 | H5B2_create_t bt2_cparam; /* v2 B-tree creation parameters */ |
669 | 0 | H5D_bt2_ctx_ud_t u_ctx; /* data for context call */ |
670 | 0 | unsigned chunk_size_len = 0; /* Size of encoded chunk size */ |
671 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
672 | |
|
673 | 0 | FUNC_ENTER_PACKAGE |
674 | | |
675 | | /* Check args */ |
676 | 0 | assert(idx_info); |
677 | 0 | assert(idx_info->f); |
678 | 0 | assert(idx_info->pline); |
679 | 0 | assert(idx_info->layout); |
680 | 0 | assert(!H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)); |
681 | | |
682 | | /* Compute number of bytes used to encode the chunk size */ |
683 | 0 | H5D_BT2_COMPUTE_CHUNK_SIZE_LEN(chunk_size_len, idx_info); |
684 | | |
685 | | /* Set up b-tree creation parameters */ |
686 | 0 | bt2_cparam.rrec_size = |
687 | 0 | H5F_SIZEOF_ADDR(idx_info->f) /* Address of chunk */ |
688 | 0 | + (idx_info->layout->u.chunk.ndims - 1) * 8; /* # of dimensions x 64-bit chunk offsets */ |
689 | | |
690 | | /* General parameters */ |
691 | 0 | if (idx_info->pline->nused > 0) { |
692 | 0 | bt2_cparam.rrec_size += chunk_size_len + 4; /* Size of encoded chunk size & filter mask */ |
693 | 0 | bt2_cparam.cls = H5D_BT2_FILT; |
694 | 0 | } /* end if */ |
695 | 0 | else |
696 | 0 | bt2_cparam.cls = H5D_BT2; |
697 | |
|
698 | 0 | bt2_cparam.node_size = idx_info->layout->u.chunk.u.btree2.cparam.node_size; |
699 | 0 | bt2_cparam.split_percent = idx_info->layout->u.chunk.u.btree2.cparam.split_percent; |
700 | 0 | bt2_cparam.merge_percent = idx_info->layout->u.chunk.u.btree2.cparam.merge_percent; |
701 | | |
702 | | /* Set up client context */ |
703 | 0 | u_ctx.f = idx_info->f; |
704 | 0 | u_ctx.ndims = idx_info->layout->u.chunk.ndims - 1; |
705 | 0 | u_ctx.chunk_size = idx_info->layout->u.chunk.size; |
706 | 0 | u_ctx.dim = idx_info->layout->u.chunk.dim; |
707 | 0 | u_ctx.chunk_size_len = (size_t)chunk_size_len; |
708 | | |
709 | | /* Create the v2 B-tree for the chunked dataset */ |
710 | 0 | if (NULL == |
711 | 0 | (idx_info->layout->storage.u.chunk.u.btree2.bt2 = H5B2_create(idx_info->f, &bt2_cparam, &u_ctx))) |
712 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create v2 B-tree for tracking chunked dataset"); |
713 | | |
714 | | /* Retrieve the v2 B-tree's address in the file */ |
715 | 0 | if (H5B2_get_addr(idx_info->layout->storage.u.chunk.u.btree2.bt2, |
716 | 0 | &(idx_info->layout->storage.u.chunk.idx_addr)) < 0) |
717 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, |
718 | 0 | "can't get v2 B-tree address for tracking chunked dataset"); |
719 | | |
720 | | /* Check for SWMR writes to the file */ |
721 | 0 | if (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) |
722 | 0 | if (H5D__btree2_idx_depend(idx_info) < 0) |
723 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, |
724 | 0 | "unable to create flush dependency on object header"); |
725 | | |
726 | 0 | done: |
727 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
728 | 0 | } /* end H5D__bt2_idx_create() */ |
729 | | |
730 | | /*------------------------------------------------------------------------- |
731 | | * Function: H5D__bt2_idx_open() |
732 | | * |
733 | | * Purpose: Opens an existing v2 B-tree. |
734 | | * |
735 | | * Note: This information is passively initialized from each index |
736 | | * operation callback because those abstract chunk index |
737 | | * operations are designed to work with the v2 B-tree chunk |
738 | | * indices also, which don't require an 'open' for the data |
739 | | * structure. |
740 | | * |
741 | | * Return: Success: non-negative |
742 | | * Failure: negative |
743 | | * |
744 | | *------------------------------------------------------------------------- |
745 | | */ |
746 | | static herr_t |
747 | | H5D__bt2_idx_open(const H5D_chk_idx_info_t *idx_info) |
748 | 0 | { |
749 | 0 | H5D_bt2_ctx_ud_t u_ctx; /* user data for creating context */ |
750 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
751 | |
|
752 | 0 | FUNC_ENTER_PACKAGE |
753 | | |
754 | | /* Check args */ |
755 | 0 | assert(idx_info); |
756 | 0 | assert(idx_info->f); |
757 | 0 | assert(idx_info->pline); |
758 | 0 | assert(idx_info->layout); |
759 | 0 | assert(H5D_CHUNK_IDX_BT2 == idx_info->layout->u.chunk.idx_type); |
760 | 0 | assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)); |
761 | 0 | assert(NULL == idx_info->layout->storage.u.chunk.u.btree2.bt2); |
762 | | |
763 | | /* Set up the user data */ |
764 | 0 | u_ctx.f = idx_info->f; |
765 | 0 | u_ctx.ndims = idx_info->layout->u.chunk.ndims - 1; |
766 | 0 | u_ctx.chunk_size = idx_info->layout->u.chunk.size; |
767 | 0 | u_ctx.dim = idx_info->layout->u.chunk.dim; |
768 | | |
769 | | /* Compute number of bytes used to encode the chunk size */ |
770 | 0 | H5D_BT2_COMPUTE_CHUNK_SIZE_LEN(u_ctx.chunk_size_len, idx_info); |
771 | | |
772 | | /* Open v2 B-tree for the chunk index */ |
773 | 0 | if (NULL == (idx_info->layout->storage.u.chunk.u.btree2.bt2 = |
774 | 0 | H5B2_open(idx_info->f, idx_info->layout->storage.u.chunk.idx_addr, &u_ctx))) |
775 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't open v2 B-tree for tracking chunked dataset"); |
776 | | |
777 | | /* Check for SWMR writes to the file */ |
778 | 0 | if (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) |
779 | 0 | if (H5D__btree2_idx_depend(idx_info) < 0) |
780 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTDEPEND, FAIL, |
781 | 0 | "unable to create flush dependency on object header"); |
782 | | |
783 | 0 | done: |
784 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
785 | 0 | } /* end H5D__bt2_idx_open() */ |
786 | | |
787 | | /*------------------------------------------------------------------------- |
788 | | * Function: H5D__bt2_idx_close() |
789 | | * |
790 | | * Purpose: Closes an existing v2 B-tree. |
791 | | * |
792 | | * Return: Success: non-negative |
793 | | * Failure: negative |
794 | | * |
795 | | *------------------------------------------------------------------------- |
796 | | */ |
797 | | static herr_t |
798 | | H5D__bt2_idx_close(const H5D_chk_idx_info_t *idx_info) |
799 | 0 | { |
800 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
801 | |
|
802 | 0 | FUNC_ENTER_PACKAGE |
803 | |
|
804 | 0 | assert(idx_info); |
805 | 0 | assert(idx_info->layout); |
806 | 0 | assert(H5D_CHUNK_IDX_BT2 == idx_info->layout->storage.u.chunk.idx_type); |
807 | 0 | assert(idx_info->layout->storage.u.chunk.u.btree2.bt2); |
808 | |
|
809 | 0 | if (H5B2_close(idx_info->layout->storage.u.chunk.u.btree2.bt2) < 0) |
810 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close v2 B-tree"); |
811 | 0 | idx_info->layout->storage.u.chunk.u.btree2.bt2 = NULL; |
812 | |
|
813 | 0 | done: |
814 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
815 | 0 | } /* end H5D__bt2_idx_close() */ |
816 | | |
817 | | /*------------------------------------------------------------------------- |
818 | | * Function: H5D__bt2_idx_is_open |
819 | | * |
820 | | * Purpose: Query if the index is opened or not |
821 | | * |
822 | | * Return: SUCCEED (can't fail) |
823 | | * |
824 | | *------------------------------------------------------------------------- |
825 | | */ |
826 | | static herr_t |
827 | | H5D__bt2_idx_is_open(const H5D_chk_idx_info_t *idx_info, bool *is_open) |
828 | 0 | { |
829 | 0 | FUNC_ENTER_PACKAGE_NOERR |
830 | |
|
831 | 0 | assert(idx_info); |
832 | 0 | assert(idx_info->layout); |
833 | 0 | assert(H5D_CHUNK_IDX_BT2 == idx_info->layout->storage.u.chunk.idx_type); |
834 | 0 | assert(is_open); |
835 | |
|
836 | 0 | *is_open = H5D_BT2_IDX_IS_OPEN(idx_info); |
837 | |
|
838 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
839 | 0 | } /* end H5D__bt2_idx_is_open() */ |
840 | | |
841 | | /*------------------------------------------------------------------------- |
842 | | * Function: H5D__bt2_idx_is_space_alloc |
843 | | * |
844 | | * Purpose: Query if space is allocated for index method |
845 | | * |
846 | | * Return: true/false |
847 | | * |
848 | | *------------------------------------------------------------------------- |
849 | | */ |
850 | | static bool |
851 | | H5D__bt2_idx_is_space_alloc(const H5O_storage_chunk_t *storage) |
852 | 0 | { |
853 | 0 | FUNC_ENTER_PACKAGE_NOERR |
854 | | |
855 | | /* Check args */ |
856 | 0 | assert(storage); |
857 | |
|
858 | 0 | FUNC_LEAVE_NOAPI((bool)H5_addr_defined(storage->idx_addr)) |
859 | 0 | } /* end H5D__bt2_idx_is_space_alloc() */ |
860 | | |
861 | | /*------------------------------------------------------------------------- |
862 | | * Function: H5D__bt2_mod_cb |
863 | | * |
864 | | * Purpose: Modify record for dataset chunk when it is found in a v2 |
865 | | * B-tree. This is the callback for H5B2_update() which is |
866 | | * called in H5D__bt2_idx_insert(). |
867 | | * |
868 | | * Return: Success: non-negative |
869 | | * Failure: negative |
870 | | * |
871 | | *------------------------------------------------------------------------- |
872 | | */ |
873 | | static herr_t |
874 | | H5D__bt2_mod_cb(void *_record, void *_op_data, bool *changed) |
875 | 0 | { |
876 | 0 | H5D_bt2_ud_t *op_data = (H5D_bt2_ud_t *)_op_data; /* User data for v2 B-tree calls */ |
877 | 0 | H5D_chunk_rec_t *record = (H5D_chunk_rec_t *)_record; /* Chunk record */ |
878 | |
|
879 | 0 | FUNC_ENTER_PACKAGE_NOERR |
880 | | |
881 | | /* Sanity check */ |
882 | | #ifndef NDEBUG |
883 | | { |
884 | | unsigned u; /* Local index variable */ |
885 | | |
886 | | for (u = 0; u < op_data->ndims; u++) |
887 | | assert(record->scaled[u] == op_data->rec.scaled[u]); |
888 | | } |
889 | | #endif /* NDEBUG */ |
890 | | |
891 | | /* Modify record */ |
892 | 0 | *record = op_data->rec; |
893 | | |
894 | | /* Note that the record changed */ |
895 | 0 | *changed = true; |
896 | |
|
897 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
898 | 0 | } /* end H5D__bt2_mod_cb() */ |
899 | | |
900 | | /*------------------------------------------------------------------------- |
901 | | * Function: H5D__bt2_idx_insert |
902 | | * |
903 | | * Purpose: Insert chunk address into the indexing structure. |
904 | | * A non-filtered chunk: |
905 | | * Should not exist |
906 | | * Allocate the chunk and pass chunk address back up |
907 | | * A filtered chunk: |
908 | | * If it was not found, create the chunk and pass chunk |
909 | | * address back up |
910 | | * If it was found but its size changed, reallocate the chunk |
911 | | * and pass chunk address back up |
912 | | * If it was found but its size was the same, pass chunk |
913 | | * address back up |
914 | | * |
915 | | * Return: Non-negative on success/Negative on failure |
916 | | * |
917 | | *------------------------------------------------------------------------- |
918 | | */ |
919 | | static herr_t |
920 | | H5D__bt2_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata, |
921 | | const H5D_t H5_ATTR_UNUSED *dset) |
922 | 0 | { |
923 | 0 | H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */ |
924 | 0 | H5D_bt2_ud_t bt2_udata; /* User data for v2 B-tree calls */ |
925 | 0 | unsigned u; /* Local index variable */ |
926 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
927 | |
|
928 | 0 | FUNC_ENTER_PACKAGE |
929 | | |
930 | | /* Sanity checks */ |
931 | 0 | assert(idx_info); |
932 | 0 | assert(idx_info->f); |
933 | 0 | assert(idx_info->pline); |
934 | 0 | assert(idx_info->layout); |
935 | 0 | assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)); |
936 | 0 | assert(udata); |
937 | 0 | assert(H5_addr_defined(udata->chunk_block.offset)); |
938 | | |
939 | | /* Check if the v2 B-tree is open yet */ |
940 | 0 | if (!H5D_BT2_IDX_IS_OPEN(idx_info)) { |
941 | | /* Open existing v2 B-tree */ |
942 | 0 | if (H5D__bt2_idx_open(idx_info) < 0) |
943 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree"); |
944 | 0 | } /* end if */ |
945 | 0 | else /* Patch the top level file pointer contained in bt2 if needed */ |
946 | 0 | if (H5B2_patch_file(idx_info->layout->storage.u.chunk.u.btree2.bt2, idx_info->f) < 0) |
947 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer"); |
948 | | |
949 | | /* Set convenience pointer to v2 B-tree structure */ |
950 | 0 | bt2 = idx_info->layout->storage.u.chunk.u.btree2.bt2; |
951 | | |
952 | | /* Set up callback info */ |
953 | 0 | bt2_udata.ndims = idx_info->layout->u.chunk.ndims - 1; |
954 | 0 | bt2_udata.rec.chunk_addr = udata->chunk_block.offset; |
955 | 0 | if (idx_info->pline->nused > 0) { /* filtered chunk */ |
956 | 0 | bt2_udata.rec.nbytes = udata->chunk_block.length; |
957 | 0 | bt2_udata.rec.filter_mask = udata->filter_mask; |
958 | 0 | } /* end if */ |
959 | 0 | else { /* non-filtered chunk */ |
960 | 0 | bt2_udata.rec.nbytes = idx_info->layout->u.chunk.size; |
961 | 0 | bt2_udata.rec.filter_mask = 0; |
962 | 0 | } /* end else */ |
963 | 0 | for (u = 0; u < (idx_info->layout->u.chunk.ndims - 1); u++) |
964 | 0 | bt2_udata.rec.scaled[u] = udata->common.scaled[u]; |
965 | | |
966 | | /* Update record for v2 B-tree (could be insert or modify) */ |
967 | 0 | if (H5B2_update(bt2, &bt2_udata, H5D__bt2_mod_cb, &bt2_udata) < 0) |
968 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTUPDATE, FAIL, "unable to update record in v2 B-tree"); |
969 | | |
970 | 0 | done: |
971 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
972 | 0 | } /* H5D__bt2_idx_insert() */ |
973 | | |
974 | | /*------------------------------------------------------------------------- |
975 | | * Function: H5D__bt2_found_cb |
976 | | * |
977 | | * Purpose: Retrieve record for dataset chunk when it is found in a v2 |
978 | | * B-tree. This is the callback for H5B2_find() which is called |
979 | | * in H5D__bt2_idx_get_addr() and H5D__bt2_idx_insert(). |
980 | | * |
981 | | * Return: Success: non-negative |
982 | | * Failure: negative |
983 | | * |
984 | | *------------------------------------------------------------------------- |
985 | | */ |
986 | | static herr_t |
987 | | H5D__bt2_found_cb(const void *nrecord, void *op_data) |
988 | 0 | { |
989 | 0 | FUNC_ENTER_PACKAGE_NOERR |
990 | |
|
991 | 0 | *(H5D_chunk_rec_t *)op_data = *(const H5D_chunk_rec_t *)nrecord; |
992 | |
|
993 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
994 | 0 | } /* H5D__bt2_found_cb() */ |
995 | | |
996 | | /*------------------------------------------------------------------------- |
997 | | * Function: H5D__bt2_idx_get_addr |
998 | | * |
999 | | * Purpose: Get the file address of a chunk if file space has been |
1000 | | * assigned. Save the retrieved information in the udata |
1001 | | * supplied. |
1002 | | * |
1003 | | * Return: Non-negative on success/Negative on failure |
1004 | | * |
1005 | | *------------------------------------------------------------------------- |
1006 | | */ |
1007 | | static herr_t |
1008 | | H5D__bt2_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata) |
1009 | 0 | { |
1010 | 0 | H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */ |
1011 | 0 | H5D_bt2_ud_t bt2_udata; /* User data for v2 B-tree calls */ |
1012 | 0 | H5D_chunk_rec_t found_rec; /* Record found from searching for object */ |
1013 | 0 | unsigned u; /* Local index variable */ |
1014 | 0 | bool found; /* Whether chunk was found */ |
1015 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1016 | |
|
1017 | 0 | FUNC_ENTER_PACKAGE |
1018 | | |
1019 | | /* Sanity checks */ |
1020 | 0 | assert(idx_info); |
1021 | 0 | assert(idx_info->f); |
1022 | 0 | assert(idx_info->pline); |
1023 | 0 | assert(idx_info->layout); |
1024 | 0 | assert(idx_info->layout->u.chunk.ndims > 0); |
1025 | 0 | assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)); |
1026 | 0 | assert(udata); |
1027 | | |
1028 | | /* Check if the v2 B-tree is open yet */ |
1029 | 0 | if (!H5D_BT2_IDX_IS_OPEN(idx_info)) { |
1030 | | /* Open existing v2 B-tree */ |
1031 | 0 | if (H5D__bt2_idx_open(idx_info) < 0) |
1032 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree"); |
1033 | 0 | } /* end if */ |
1034 | 0 | else /* Patch the top level file pointer contained in bt2 if needed */ |
1035 | 0 | if (H5B2_patch_file(idx_info->layout->storage.u.chunk.u.btree2.bt2, idx_info->f) < 0) |
1036 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer"); |
1037 | | |
1038 | | /* Set convenience pointer to v2 B-tree structure */ |
1039 | 0 | bt2 = idx_info->layout->storage.u.chunk.u.btree2.bt2; |
1040 | | |
1041 | | /* Clear the found record */ |
1042 | 0 | found_rec.chunk_addr = HADDR_UNDEF; |
1043 | 0 | found_rec.nbytes = 0; |
1044 | 0 | found_rec.filter_mask = 0; |
1045 | | |
1046 | | /* Prepare user data for compare callback */ |
1047 | 0 | bt2_udata.rec.chunk_addr = HADDR_UNDEF; |
1048 | 0 | bt2_udata.ndims = idx_info->layout->u.chunk.ndims - 1; |
1049 | | |
1050 | | /* Set the chunk offset to be searched for */ |
1051 | 0 | for (u = 0; u < (idx_info->layout->u.chunk.ndims - 1); u++) |
1052 | 0 | bt2_udata.rec.scaled[u] = udata->common.scaled[u]; |
1053 | | |
1054 | | /* Go get chunk information from v2 B-tree */ |
1055 | 0 | found = false; |
1056 | 0 | if (H5B2_find(bt2, &bt2_udata, &found, H5D__bt2_found_cb, &found_rec) < 0) |
1057 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTFIND, FAIL, "can't check for chunk in v2 B-tree"); |
1058 | | |
1059 | | /* Check if chunk was found */ |
1060 | 0 | if (found) { |
1061 | | /* Sanity check */ |
1062 | 0 | assert(0 != found_rec.nbytes); |
1063 | | |
1064 | | /* Set common info for the chunk */ |
1065 | 0 | udata->chunk_block.offset = found_rec.chunk_addr; |
1066 | | |
1067 | | /* Set other info for the chunk */ |
1068 | 0 | if (idx_info->pline->nused > 0) { /* filtered chunk */ |
1069 | 0 | udata->chunk_block.length = found_rec.nbytes; |
1070 | 0 | udata->filter_mask = found_rec.filter_mask; |
1071 | 0 | } /* end if */ |
1072 | 0 | else { /* non-filtered chunk */ |
1073 | 0 | udata->chunk_block.length = idx_info->layout->u.chunk.size; |
1074 | 0 | udata->filter_mask = 0; |
1075 | 0 | } /* end else */ |
1076 | 0 | } /* end if */ |
1077 | 0 | else { |
1078 | 0 | udata->chunk_block.offset = HADDR_UNDEF; |
1079 | 0 | udata->chunk_block.length = 0; |
1080 | 0 | udata->filter_mask = 0; |
1081 | 0 | } /* end else */ |
1082 | |
|
1083 | 0 | done: |
1084 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1085 | 0 | } /* H5D__bt2_idx_get_addr() */ |
1086 | | |
1087 | | /*------------------------------------------------------------------------- |
1088 | | * Function: H5D__bt2_idx_load_metadata |
1089 | | * |
1090 | | * Purpose: Load additional chunk index metadata beyond the chunk index |
1091 | | * itself. |
1092 | | * |
1093 | | * Return: Non-negative on success/Negative on failure |
1094 | | * |
1095 | | *------------------------------------------------------------------------- |
1096 | | */ |
1097 | | static herr_t |
1098 | | H5D__bt2_idx_load_metadata(const H5D_chk_idx_info_t *idx_info) |
1099 | 0 | { |
1100 | 0 | H5D_chunk_ud_t chunk_ud; |
1101 | 0 | hsize_t scaled[H5O_LAYOUT_NDIMS] = {0}; |
1102 | 0 | herr_t ret_value = SUCCEED; |
1103 | |
|
1104 | 0 | FUNC_ENTER_PACKAGE |
1105 | | |
1106 | | /* |
1107 | | * After opening a dataset that uses a v2 Btree, the root |
1108 | | * node will generally not be read in until an element is |
1109 | | * looked up for the first time. Since there isn't currently |
1110 | | * a good way of controlling that explicitly, perform a fake |
1111 | | * lookup of a chunk to cause it to be read in. |
1112 | | */ |
1113 | 0 | chunk_ud.common.layout = &idx_info->layout->u.chunk; |
1114 | 0 | chunk_ud.common.storage = &idx_info->layout->storage.u.chunk; |
1115 | 0 | chunk_ud.common.scaled = scaled; |
1116 | |
|
1117 | 0 | chunk_ud.chunk_block.offset = HADDR_UNDEF; |
1118 | 0 | chunk_ud.chunk_block.length = 0; |
1119 | 0 | chunk_ud.filter_mask = 0; |
1120 | 0 | chunk_ud.new_unfilt_chunk = false; |
1121 | 0 | chunk_ud.idx_hint = UINT_MAX; |
1122 | |
|
1123 | 0 | if (H5D__bt2_idx_get_addr(idx_info, &chunk_ud) < 0) |
1124 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't load v2 B-tree root node"); |
1125 | | |
1126 | 0 | done: |
1127 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1128 | 0 | } /* H5D__bt2_idx_load_metadata() */ |
1129 | | |
1130 | | /*------------------------------------------------------------------------- |
1131 | | * Function: H5D__bt2_idx_iterate_cb |
1132 | | * |
1133 | | * Purpose: Translate the B-tree specific chunk record into a generic |
1134 | | * form and make the callback to the generic chunk callback |
1135 | | * routine. |
1136 | | * This is the callback for H5B2_iterate() which is called in |
1137 | | * H5D__bt2_idx_iterate(). |
1138 | | * |
1139 | | * Return: Success: Non-negative |
1140 | | * Failure: Negative |
1141 | | * |
1142 | | *------------------------------------------------------------------------- |
1143 | | */ |
1144 | | static int |
1145 | | H5D__bt2_idx_iterate_cb(const void *_record, void *_udata) |
1146 | 0 | { |
1147 | 0 | H5D_bt2_it_ud_t *udata = (H5D_bt2_it_ud_t *)_udata; /* User data */ |
1148 | 0 | const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* Native record */ |
1149 | 0 | int ret_value = -1; /* Return value */ |
1150 | |
|
1151 | 0 | FUNC_ENTER_PACKAGE_NOERR |
1152 | | |
1153 | | /* Make "generic chunk" callback */ |
1154 | 0 | if ((ret_value = (udata->cb)(record, udata->udata)) < 0) |
1155 | 0 | HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback"); |
1156 | |
|
1157 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1158 | 0 | } /* H5D__bt2_idx_iterate_cb() */ |
1159 | | |
1160 | | /*------------------------------------------------------------------------- |
1161 | | * Function: H5D__bt2_idx_iterate |
1162 | | * |
1163 | | * Purpose: Iterate over the chunks in an index, making a callback |
1164 | | * for each one. |
1165 | | * |
1166 | | * Return: Non-negative on success/Negative on failure |
1167 | | * |
1168 | | *------------------------------------------------------------------------- |
1169 | | */ |
1170 | | static int |
1171 | | H5D__bt2_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb, void *chunk_udata) |
1172 | 0 | { |
1173 | 0 | H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */ |
1174 | 0 | H5D_bt2_it_ud_t udata; /* User data for B-tree iterator callback */ |
1175 | 0 | int ret_value = FAIL; /* Return value */ |
1176 | |
|
1177 | 0 | FUNC_ENTER_PACKAGE |
1178 | | |
1179 | | /* Sanity checks */ |
1180 | 0 | assert(idx_info); |
1181 | 0 | assert(idx_info->f); |
1182 | 0 | assert(idx_info->pline); |
1183 | 0 | assert(idx_info->layout); |
1184 | 0 | assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)); |
1185 | 0 | assert(chunk_cb); |
1186 | 0 | assert(chunk_udata); |
1187 | | |
1188 | | /* Check if the v2 B-tree is open yet */ |
1189 | 0 | if (!H5D_BT2_IDX_IS_OPEN(idx_info)) { |
1190 | | /* Open existing v2 B-tree */ |
1191 | 0 | if (H5D__bt2_idx_open(idx_info) < 0) |
1192 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree"); |
1193 | 0 | } /* end if */ |
1194 | 0 | else /* Patch the top level file pointer contained in bt2 if needed */ |
1195 | 0 | if (H5B2_patch_file(idx_info->layout->storage.u.chunk.u.btree2.bt2, idx_info->f) < 0) |
1196 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer"); |
1197 | | |
1198 | | /* Set convenience pointer to v2 B-tree structure */ |
1199 | 0 | bt2 = idx_info->layout->storage.u.chunk.u.btree2.bt2; |
1200 | | |
1201 | | /* Prepare user data for iterate callback */ |
1202 | 0 | udata.cb = chunk_cb; |
1203 | 0 | udata.udata = chunk_udata; |
1204 | | |
1205 | | /* Iterate over the records in the v2 B-tree */ |
1206 | 0 | if ((ret_value = H5B2_iterate(bt2, H5D__bt2_idx_iterate_cb, &udata)) < 0) |
1207 | 0 | HERROR(H5E_DATASET, H5E_BADITER, "unable to iterate over chunk v2 B-tree"); |
1208 | |
|
1209 | 0 | done: |
1210 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1211 | 0 | } /* end H5D__bt2_idx_iterate() */ |
1212 | | |
1213 | | /*------------------------------------------------------------------------- |
1214 | | * Function: H5D__bt2_remove_cb() |
1215 | | * |
1216 | | * Purpose: Free space for 'dataset chunk' object as v2 B-tree |
1217 | | * is being deleted or v2 B-tree node is removed. |
1218 | | * This is the callback for H5B2_remove() and H5B2_delete() |
1219 | | * which are called in H5D__bt2_idx_remove() and |
1220 | | * H5D__bt2_idx_delete(). |
1221 | | * |
1222 | | * Return: Success: non-negative |
1223 | | * Failure: negative |
1224 | | * |
1225 | | *------------------------------------------------------------------------- |
1226 | | */ |
1227 | | static herr_t |
1228 | | H5D__bt2_remove_cb(const void *_record, void *_udata) |
1229 | 0 | { |
1230 | 0 | const H5D_chunk_rec_t *record = (const H5D_chunk_rec_t *)_record; /* The native record */ |
1231 | 0 | H5F_t *f = (H5F_t *)_udata; /* User data for removal callback */ |
1232 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1233 | |
|
1234 | 0 | FUNC_ENTER_PACKAGE |
1235 | | |
1236 | | /* Sanity checks */ |
1237 | 0 | assert(f); |
1238 | | |
1239 | | /* Free the space in the file for the object being removed */ |
1240 | 0 | if (H5MF_xfree(f, H5FD_MEM_DRAW, record->chunk_addr, record->nbytes) < 0) |
1241 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free chunk"); |
1242 | | |
1243 | 0 | done: |
1244 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1245 | 0 | } /* H5D__bt2_remove_cb() */ |
1246 | | |
1247 | | /*------------------------------------------------------------------------- |
1248 | | * Function: H5D__bt2_idx_remove |
1249 | | * |
1250 | | * Purpose: Remove chunk from index. |
1251 | | * |
1252 | | * Return: Non-negative on success/Negative on failure |
1253 | | * |
1254 | | *------------------------------------------------------------------------- |
1255 | | */ |
1256 | | static herr_t |
1257 | | H5D__bt2_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata) |
1258 | 0 | { |
1259 | 0 | H5B2_t *bt2; /* v2 B-tree handle for indexing chunks */ |
1260 | 0 | H5D_bt2_ud_t bt2_udata; /* User data for v2 B-tree find call */ |
1261 | 0 | unsigned u; /* Local index variable */ |
1262 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1263 | |
|
1264 | 0 | FUNC_ENTER_PACKAGE |
1265 | | |
1266 | | /* Sanity checks */ |
1267 | 0 | assert(idx_info); |
1268 | 0 | assert(idx_info->f); |
1269 | 0 | assert(idx_info->pline); |
1270 | 0 | assert(idx_info->layout); |
1271 | 0 | assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)); |
1272 | 0 | assert(udata); |
1273 | | |
1274 | | /* Check if the v2 B-tree is open yet */ |
1275 | 0 | if (!H5D_BT2_IDX_IS_OPEN(idx_info)) { |
1276 | | /* Open existing v2 B-tree */ |
1277 | 0 | if (H5D__bt2_idx_open(idx_info) < 0) |
1278 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree"); |
1279 | 0 | } /* end if */ |
1280 | 0 | else /* Patch the top level file pointer contained in bt2 if needed */ |
1281 | 0 | if (H5B2_patch_file(idx_info->layout->storage.u.chunk.u.btree2.bt2, idx_info->f) < 0) |
1282 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer"); |
1283 | | |
1284 | | /* Set convenience pointer to v2 B-tree structure */ |
1285 | 0 | bt2 = idx_info->layout->storage.u.chunk.u.btree2.bt2; |
1286 | | |
1287 | | /* Prepare user data for compare callback */ |
1288 | 0 | bt2_udata.ndims = idx_info->layout->u.chunk.ndims - 1; |
1289 | | |
1290 | | /* Initialize the record to search for */ |
1291 | 0 | for (u = 0; u < (idx_info->layout->u.chunk.ndims - 1); u++) |
1292 | 0 | bt2_udata.rec.scaled[u] = udata->scaled[u]; |
1293 | | |
1294 | | /* Remove the record for the "dataset chunk" object from the v2 B-tree */ |
1295 | | /* (space in the file for the object is freed in the 'remove' callback) */ |
1296 | 0 | if (H5B2_remove(bt2, &bt2_udata, |
1297 | 0 | (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) ? NULL : H5D__bt2_remove_cb, |
1298 | 0 | idx_info->f) < 0) |
1299 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTREMOVE, FAIL, "can't remove object from B-tree"); |
1300 | | |
1301 | 0 | done: |
1302 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1303 | 0 | } /* H5D__bt2_idx_remove() */ |
1304 | | |
1305 | | /*------------------------------------------------------------------------- |
1306 | | * Function: H5D__bt2_idx_delete |
1307 | | * |
1308 | | * Purpose: Delete index and raw data storage for entire dataset |
1309 | | * (i.e. all chunks) |
1310 | | * |
1311 | | * Return: Success: Non-negative |
1312 | | * Failure: negative |
1313 | | * |
1314 | | *------------------------------------------------------------------------- |
1315 | | */ |
1316 | | static herr_t |
1317 | | H5D__bt2_idx_delete(const H5D_chk_idx_info_t *idx_info) |
1318 | 0 | { |
1319 | 0 | H5B2_remove_t remove_op; /* The removal callback */ |
1320 | 0 | H5D_bt2_ctx_ud_t u_ctx; /* data for context call */ |
1321 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1322 | |
|
1323 | 0 | FUNC_ENTER_PACKAGE |
1324 | | |
1325 | | /* Sanity checks */ |
1326 | 0 | assert(idx_info); |
1327 | 0 | assert(idx_info->f); |
1328 | 0 | assert(idx_info->pline); |
1329 | 0 | assert(idx_info->layout); |
1330 | | |
1331 | | /* Check if the index data structure has been allocated */ |
1332 | 0 | if (H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)) { |
1333 | | /* Set up user data for creating context */ |
1334 | 0 | u_ctx.f = idx_info->f; |
1335 | 0 | u_ctx.ndims = idx_info->layout->u.chunk.ndims - 1; |
1336 | 0 | u_ctx.chunk_size = idx_info->layout->u.chunk.size; |
1337 | 0 | u_ctx.dim = idx_info->layout->u.chunk.dim; |
1338 | | |
1339 | | /* Compute number of bytes used to encode the chunk size */ |
1340 | 0 | H5D_BT2_COMPUTE_CHUNK_SIZE_LEN(u_ctx.chunk_size_len, idx_info); |
1341 | | |
1342 | | /* Set remove operation. Do not remove chunks in SWMR_WRITE mode */ |
1343 | 0 | if (H5F_INTENT(idx_info->f) & H5F_ACC_SWMR_WRITE) |
1344 | 0 | remove_op = NULL; |
1345 | 0 | else |
1346 | 0 | remove_op = H5D__bt2_remove_cb; |
1347 | | |
1348 | | /* Delete the v2 B-tree */ |
1349 | | /*(space in the file for each object is freed in the 'remove' callback) */ |
1350 | 0 | if (H5B2_delete(idx_info->f, idx_info->layout->storage.u.chunk.idx_addr, &u_ctx, remove_op, |
1351 | 0 | idx_info->f) < 0) |
1352 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTDELETE, FAIL, "can't delete v2 B-tree"); |
1353 | | |
1354 | 0 | idx_info->layout->storage.u.chunk.idx_addr = HADDR_UNDEF; |
1355 | 0 | } /* end if */ |
1356 | | |
1357 | 0 | done: |
1358 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1359 | 0 | } /* end H5D__bt2_idx_delete() */ |
1360 | | |
1361 | | /*------------------------------------------------------------------------- |
1362 | | * Function: H5D__bt2_idx_copy_setup |
1363 | | * |
1364 | | * Purpose: Set up any necessary information for copying chunks |
1365 | | * |
1366 | | * Return: Non-negative on success/Negative on failure |
1367 | | * |
1368 | | *------------------------------------------------------------------------- |
1369 | | */ |
1370 | | static herr_t |
1371 | | H5D__bt2_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src, const H5D_chk_idx_info_t *idx_info_dst) |
1372 | 0 | { |
1373 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1374 | |
|
1375 | 0 | FUNC_ENTER_PACKAGE |
1376 | | |
1377 | | /* Source file */ |
1378 | 0 | assert(idx_info_src); |
1379 | 0 | assert(idx_info_src->f); |
1380 | 0 | assert(idx_info_src->pline); |
1381 | 0 | assert(idx_info_src->layout); |
1382 | | |
1383 | | /* Destination file */ |
1384 | 0 | assert(idx_info_dst); |
1385 | 0 | assert(idx_info_dst->f); |
1386 | 0 | assert(idx_info_dst->pline); |
1387 | 0 | assert(idx_info_dst->layout); |
1388 | 0 | assert(!H5_addr_defined(idx_info_dst->layout->storage.u.chunk.idx_addr)); |
1389 | | |
1390 | | /* Check if the source v2 B-tree is open yet */ |
1391 | 0 | if (!H5D_BT2_IDX_IS_OPEN(idx_info_src)) |
1392 | 0 | if (H5D__bt2_idx_open(idx_info_src) < 0) |
1393 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree"); |
1394 | | |
1395 | | /* Set copied metadata tag */ |
1396 | 0 | H5_BEGIN_TAG(H5AC__COPIED_TAG) |
1397 | | |
1398 | | /* Create v2 B-tree that describes the chunked dataset in the destination file */ |
1399 | 0 | if (H5D__bt2_idx_create(idx_info_dst) < 0) |
1400 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunked storage"); |
1401 | 0 | assert(H5_addr_defined(idx_info_dst->layout->storage.u.chunk.idx_addr)); |
1402 | | |
1403 | | /* Reset metadata tag */ |
1404 | 0 | H5_END_TAG |
1405 | | |
1406 | 0 | done: |
1407 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1408 | 0 | } /* end H5D__bt2_idx_copy_setup() */ |
1409 | | |
1410 | | /*------------------------------------------------------------------------- |
1411 | | * Function: H5D__bt2_idx_copy_shutdown |
1412 | | * |
1413 | | * Purpose: Shutdown any information from copying chunks |
1414 | | * |
1415 | | * Return: Non-negative on success/Negative on failure |
1416 | | * |
1417 | | *------------------------------------------------------------------------- |
1418 | | */ |
1419 | | static herr_t |
1420 | | H5D__bt2_idx_copy_shutdown(H5O_storage_chunk_t *storage_src, H5O_storage_chunk_t *storage_dst) |
1421 | 0 | { |
1422 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1423 | |
|
1424 | 0 | FUNC_ENTER_PACKAGE |
1425 | | |
1426 | | /* Check args */ |
1427 | 0 | assert(storage_src); |
1428 | 0 | assert(storage_src->u.btree2.bt2); |
1429 | 0 | assert(storage_dst); |
1430 | 0 | assert(storage_dst->u.btree2.bt2); |
1431 | | |
1432 | | /* Close v2 B-tree for source file */ |
1433 | 0 | if (H5B2_close(storage_src->u.btree2.bt2) < 0) |
1434 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close v2 B-tree"); |
1435 | 0 | storage_src->u.btree2.bt2 = NULL; |
1436 | | |
1437 | | /* Close v2 B-tree for destination file */ |
1438 | 0 | if (H5B2_close(storage_dst->u.btree2.bt2) < 0) |
1439 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to close v2 B-tree"); |
1440 | 0 | storage_dst->u.btree2.bt2 = NULL; |
1441 | |
|
1442 | 0 | done: |
1443 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1444 | 0 | } /* end H5D__bt2_idx_copy_shutdown() */ |
1445 | | |
1446 | | /*------------------------------------------------------------------------- |
1447 | | * Function: H5D__bt2_idx_size |
1448 | | * |
1449 | | * Purpose: Retrieve the amount of index storage for chunked dataset |
1450 | | * |
1451 | | * Return: Success: Non-negative |
1452 | | * Failure: negative |
1453 | | * |
1454 | | *------------------------------------------------------------------------- |
1455 | | */ |
1456 | | static herr_t |
1457 | | H5D__bt2_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *index_size) |
1458 | 0 | { |
1459 | 0 | H5B2_t *bt2_cdset = NULL; /* Pointer to v2 B-tree structure */ |
1460 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1461 | |
|
1462 | 0 | FUNC_ENTER_PACKAGE |
1463 | | |
1464 | | /* Check args */ |
1465 | 0 | assert(idx_info); |
1466 | 0 | assert(idx_info->f); |
1467 | 0 | assert(idx_info->pline); |
1468 | 0 | assert(idx_info->layout); |
1469 | 0 | assert(H5_addr_defined(idx_info->layout->storage.u.chunk.idx_addr)); |
1470 | 0 | assert(index_size); |
1471 | | |
1472 | | /* Open v2 B-tree */ |
1473 | 0 | if (H5D__bt2_idx_open(idx_info) < 0) |
1474 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't open v2 B-tree"); |
1475 | | |
1476 | | /* Set convenience pointer to v2 B-tree structure */ |
1477 | 0 | bt2_cdset = idx_info->layout->storage.u.chunk.u.btree2.bt2; |
1478 | | |
1479 | | /* Get v2 B-tree size for indexing chunked dataset */ |
1480 | 0 | if (H5B2_size(bt2_cdset, index_size) < 0) |
1481 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, |
1482 | 0 | "can't retrieve v2 B-tree storage info for chunked dataset"); |
1483 | | |
1484 | 0 | done: |
1485 | | /* Close v2 B-tree index */ |
1486 | 0 | if (H5D__bt2_idx_close(idx_info) < 0) |
1487 | 0 | HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for tracking chunked dataset"); |
1488 | |
|
1489 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1490 | 0 | } /* end H5D__bt2_idx_size() */ |
1491 | | |
1492 | | /*------------------------------------------------------------------------- |
1493 | | * Function: H5D__bt2_idx_reset |
1494 | | * |
1495 | | * Purpose: Reset indexing information. |
1496 | | * |
1497 | | * Return: Non-negative on success/Negative on failure |
1498 | | * |
1499 | | *------------------------------------------------------------------------- |
1500 | | */ |
1501 | | static herr_t |
1502 | | H5D__bt2_idx_reset(H5O_storage_chunk_t *storage, bool reset_addr) |
1503 | 0 | { |
1504 | 0 | FUNC_ENTER_PACKAGE_NOERR |
1505 | | |
1506 | | /* Sanity checks */ |
1507 | 0 | assert(storage); |
1508 | | |
1509 | | /* Reset index info */ |
1510 | 0 | if (reset_addr) |
1511 | 0 | storage->idx_addr = HADDR_UNDEF; |
1512 | 0 | storage->u.btree2.bt2 = NULL; |
1513 | |
|
1514 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
1515 | 0 | } /* end H5D__bt2_idx_reset() */ |
1516 | | |
1517 | | /*------------------------------------------------------------------------- |
1518 | | * Function: H5D__bt2_idx_dump |
1519 | | * |
1520 | | * Purpose: Dump indexing information to a stream. |
1521 | | * |
1522 | | * Return: Non-negative on success/Negative on failure |
1523 | | * |
1524 | | *------------------------------------------------------------------------- |
1525 | | */ |
1526 | | static herr_t |
1527 | | H5D__bt2_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream) |
1528 | 0 | { |
1529 | 0 | FUNC_ENTER_PACKAGE_NOERR |
1530 | | |
1531 | | /* Sanity checks */ |
1532 | 0 | assert(storage); |
1533 | 0 | assert(stream); |
1534 | |
|
1535 | 0 | fprintf(stream, " Address: %" PRIuHADDR "\n", storage->idx_addr); |
1536 | |
|
1537 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
1538 | 0 | } /* end H5D__bt2_idx_dump() */ |
1539 | | |
1540 | | /*------------------------------------------------------------------------- |
1541 | | * Function: H5D__bt2_idx_dest |
1542 | | * |
1543 | | * Purpose: Release indexing information in memory. |
1544 | | * |
1545 | | * Return: Non-negative on success/Negative on failure |
1546 | | * |
1547 | | *------------------------------------------------------------------------- |
1548 | | */ |
1549 | | static herr_t |
1550 | | H5D__bt2_idx_dest(const H5D_chk_idx_info_t *idx_info) |
1551 | 0 | { |
1552 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1553 | |
|
1554 | 0 | FUNC_ENTER_PACKAGE |
1555 | | |
1556 | | /* Check args */ |
1557 | 0 | assert(idx_info); |
1558 | 0 | assert(idx_info->f); |
1559 | 0 | assert(idx_info->layout); |
1560 | | |
1561 | | /* Check if the v2-btree is open */ |
1562 | 0 | if (H5D_BT2_IDX_IS_OPEN(idx_info)) { |
1563 | | /* Patch the top level file pointer contained in bt2 if needed */ |
1564 | 0 | if (H5B2_patch_file(idx_info->layout->storage.u.chunk.u.btree2.bt2, idx_info->f) < 0) |
1565 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "can't patch v2 B-tree file pointer"); |
1566 | | |
1567 | | /* Close v2 B-tree */ |
1568 | 0 | if (H5D__bt2_idx_close(idx_info) < 0) |
1569 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree"); |
1570 | 0 | } /* end if */ |
1571 | | |
1572 | 0 | done: |
1573 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1574 | 0 | } /* end H5D__bt2_idx_dest() */ |