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