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