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  * Created:		H5EAiblock.c
17  *			Sep  9 2008
18  *			Quincey Koziol <koziol@hdfgroup.org>
19  *
20  * Purpose:		Index block routines for extensible arrays.
21  *
22  *-------------------------------------------------------------------------
23  */
24 
25 /**********************/
26 /* Module Declaration */
27 /**********************/
28 
29 #include "H5EAmodule.h"         /* This source code file is part of the H5EA module */
30 
31 
32 /***********************/
33 /* Other Packages Used */
34 /***********************/
35 
36 
37 /***********/
38 /* Headers */
39 /***********/
40 #include "H5private.h"		/* Generic Functions			*/
41 #include "H5Eprivate.h"		/* Error handling		  	*/
42 #include "H5EApkg.h"		/* Extensible Arrays			*/
43 #include "H5FLprivate.h"	/* Free Lists                           */
44 #include "H5MFprivate.h"	/* File memory management		*/
45 #include "H5VMprivate.h"		/* Vectors and arrays 			*/
46 
47 
48 /****************/
49 /* Local Macros */
50 /****************/
51 
52 
53 /******************/
54 /* Local Typedefs */
55 /******************/
56 
57 
58 /********************/
59 /* Package Typedefs */
60 /********************/
61 
62 
63 /********************/
64 /* Local Prototypes */
65 /********************/
66 
67 
68 /*********************/
69 /* Package Variables */
70 /*********************/
71 
72 
73 /*****************************/
74 /* Library Private Variables */
75 /*****************************/
76 
77 
78 /*******************/
79 /* Local Variables */
80 /*******************/
81 
82 /* Declare a free list to manage the H5EA_iblock_t struct */
83 H5FL_DEFINE_STATIC(H5EA_iblock_t);
84 
85 /* Declare a free list to manage the index block elements */
86 H5FL_BLK_DEFINE_STATIC(idx_blk_elmt_buf);
87 
88 /* Declare a free list to manage the haddr_t sequence information */
89 H5FL_SEQ_DEFINE_STATIC(haddr_t);
90 
91 
92 
93 /*-------------------------------------------------------------------------
94  * Function:	H5EA__iblock_alloc
95  *
96  * Purpose:	Allocate extensible array index block
97  *
98  * Return:	Non-NULL pointer to index block on success/NULL on failure
99  *
100  * Programmer:	Quincey Koziol
101  *		koziol@hdfgroup.org
102  *		Sep  9 2008
103  *
104  *-------------------------------------------------------------------------
105  */
106 BEGIN_FUNC(PKG, ERR,
107 H5EA_iblock_t *, NULL, NULL,
108 H5EA__iblock_alloc(H5EA_hdr_t *hdr))
109 
110     /* Local variables */
111     H5EA_iblock_t *iblock = NULL;          /* Extensible array index block */
112 
113     /* Check arguments */
114     HDassert(hdr);
115 
116     /* Allocate memory for the index block */
117     if(NULL == (iblock = H5FL_CALLOC(H5EA_iblock_t)))
118 	H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array index block")
119 
120     /* Share common array information */
121     if(H5EA__hdr_incr(hdr) < 0)
122 	H5E_THROW(H5E_CANTINC, "can't increment reference count on shared array header")
123     iblock->hdr = hdr;
124 
125     /* Set non-zero internal fields */
126     iblock->addr = HADDR_UNDEF;
127 
128     /* Compute information */
129     iblock->nsblks = H5EA_SBLK_FIRST_IDX(hdr->cparam.sup_blk_min_data_ptrs);
130     iblock->ndblk_addrs = 2 * ((size_t)hdr->cparam.sup_blk_min_data_ptrs - 1);
131     iblock->nsblk_addrs = hdr->nsblks - iblock->nsblks;
132 #ifdef QAK
133 HDfprintf(stderr, "%s: iblock->nsblks = %u\n", FUNC, iblock->nsblks);
134 HDfprintf(stderr, "%s: iblock->ndblk_addrs = %Zu\n", FUNC, iblock->ndblk_addrs);
135 HDfprintf(stderr, "%s: iblock->nsblk_addrs = %Zu\n", FUNC, iblock->nsblk_addrs);
136 #endif /* QAK */
137 
138     /* Allocate buffer for elements in index block */
139     if(hdr->cparam.idx_blk_elmts > 0)
140         if(NULL == (iblock->elmts = H5FL_BLK_MALLOC(idx_blk_elmt_buf, (size_t)(hdr->cparam.idx_blk_elmts * hdr->cparam.cls->nat_elmt_size))))
141             H5E_THROW(H5E_CANTALLOC, "memory allocation failed for index block data element buffer")
142 
143     /* Allocate buffer for data block addresses in index block */
144     if(iblock->ndblk_addrs > 0)
145         if(NULL == (iblock->dblk_addrs = H5FL_SEQ_MALLOC(haddr_t, iblock->ndblk_addrs)))
146             H5E_THROW(H5E_CANTALLOC, "memory allocation failed for index block data block addresses")
147 
148     /* Allocate buffer for super block addresses in index block */
149     if(iblock->nsblk_addrs > 0)
150         if(NULL == (iblock->sblk_addrs = H5FL_SEQ_MALLOC(haddr_t, iblock->nsblk_addrs)))
151             H5E_THROW(H5E_CANTALLOC, "memory allocation failed for index block super block addresses")
152 
153     /* Set the return value */
154     ret_value = iblock;
155 
156 CATCH
157     if(!ret_value)
158         if(iblock && H5EA__iblock_dest(iblock) < 0)
159             H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array index block")
160 
161 END_FUNC(PKG)   /* end H5EA__iblock_alloc() */
162 
163 
164 /*-------------------------------------------------------------------------
165  * Function:	H5EA__iblock_create
166  *
167  * Purpose:	Creates a new extensible array index block in the file
168  *
169  * Return:	Valid file address on success/HADDR_UNDEF on failure
170  *
171  * Programmer:	Quincey Koziol
172  *		koziol@hdfgroup.org
173  *		Sep  9 2008
174  *
175  *-------------------------------------------------------------------------
176  */
177 BEGIN_FUNC(PKG, ERR,
178 haddr_t, HADDR_UNDEF, HADDR_UNDEF,
179 H5EA__iblock_create(H5EA_hdr_t *hdr, hbool_t *stats_changed))
180 
181     /* Local variables */
182     H5EA_iblock_t *iblock = NULL;       /* Extensible array index block */
183     haddr_t iblock_addr;                /* Extensible array index block address */
184     hbool_t inserted = FALSE;           /* Whether the header was inserted into cache */
185 
186 #ifdef QAK
187 HDfprintf(stderr, "%s: Called\n", FUNC);
188 #endif /* QAK */
189 
190     /* Sanity check */
191     HDassert(hdr);
192     HDassert(stats_changed);
193 
194     /* Allocate the index block */
195     if(NULL == (iblock = H5EA__iblock_alloc(hdr)))
196 	H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array index block")
197 
198     /* Set size of index block on disk */
199     iblock->size = H5EA_IBLOCK_SIZE(iblock);
200 #ifdef QAK
201 HDfprintf(stderr, "%s: iblock->size = %Zu\n", FUNC, iblock->size);
202 #endif /* QAK */
203 
204     /* Allocate space for the index block on disk */
205     if(HADDR_UNDEF == (iblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_EARRAY_IBLOCK, (hsize_t)iblock->size)))
206 	H5E_THROW(H5E_CANTALLOC, "file allocation failed for extensible array index block")
207     iblock->addr = iblock_addr;
208 
209     /* Clear any elements in index block to fill value */
210     if(hdr->cparam.idx_blk_elmts > 0) {
211         /* Call the class's 'fill' callback */
212         if((hdr->cparam.cls->fill)(iblock->elmts, (size_t)hdr->cparam.idx_blk_elmts) < 0)
213             H5E_THROW(H5E_CANTSET, "can't set extensible array index block elements to class's fill value")
214     } /* end if */
215 
216     /* Reset any data block addresses in the index block */
217     if(iblock->ndblk_addrs > 0) {
218         haddr_t tmp_addr = HADDR_UNDEF;         /* Address value to fill data block addresses with */
219 
220         /* Set all the data block addresses to "undefined" address value */
221         H5VM_array_fill(iblock->dblk_addrs, &tmp_addr, sizeof(haddr_t), iblock->ndblk_addrs);
222     } /* end if */
223 
224     /* Reset any super block addresses in the index block */
225     if(iblock->nsblk_addrs > 0) {
226         haddr_t tmp_addr = HADDR_UNDEF;         /* Address value to fill super block addresses with */
227 
228         /* Set all the super block addresses to "undefined" address value */
229         H5VM_array_fill(iblock->sblk_addrs, &tmp_addr, sizeof(haddr_t), iblock->nsblk_addrs);
230     } /* end if */
231 
232     /* Cache the new extensible array index block */
233     if(H5AC_insert_entry(hdr->f, H5AC_EARRAY_IBLOCK, iblock_addr, iblock, H5AC__NO_FLAGS_SET) < 0)
234 	H5E_THROW(H5E_CANTINSERT, "can't add extensible array index block to cache")
235     inserted = TRUE;
236 
237     /* Add index block as child of 'top' proxy */
238     if(hdr->top_proxy) {
239         if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, iblock) < 0)
240             H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
241         iblock->top_proxy = hdr->top_proxy;
242     } /* end if */
243 
244     /* Update extensible array index block statistics */
245     HDassert(0 == hdr->stats.computed.nindex_blks);
246     HDassert(0 == hdr->stats.computed.index_blk_size);
247     hdr->stats.computed.nindex_blks = 1;
248     hdr->stats.computed.index_blk_size = iblock->size;
249 
250     /* Increment count of elements "realized" */
251     hdr->stats.stored.nelmts += hdr->cparam.idx_blk_elmts;
252 
253     /* Mark the statistics as changed */
254     *stats_changed = TRUE;
255 
256     /* Set address of index block to return */
257     ret_value = iblock_addr;
258 
259 CATCH
260     if(!H5F_addr_defined(ret_value))
261         if(iblock) {
262             /* Remove from cache, if inserted */
263             if(inserted)
264                 if(H5AC_remove_entry(iblock) < 0)
265                     H5E_THROW(H5E_CANTREMOVE, "unable to remove extensible array index block from cache")
266 
267             /* Release index block's disk space */
268             if(H5F_addr_defined(iblock->addr) && H5MF_xfree(hdr->f, H5FD_MEM_EARRAY_IBLOCK, iblock->addr, (hsize_t)iblock->size) < 0)
269                 H5E_THROW(H5E_CANTFREE, "unable to release file space for extensible array index block")
270 
271             /* Destroy index block */
272             if(H5EA__iblock_dest(iblock) < 0)
273                 H5E_THROW(H5E_CANTFREE, "unable to destroy extensible array index block")
274         } /* end if */
275 
276 END_FUNC(PKG)   /* end H5EA__iblock_create() */
277 
278 
279 /*-------------------------------------------------------------------------
280  * Function:	H5EA__iblock_protect
281  *
282  * Purpose:	Convenience wrapper around protecting extensible array index block
283  *
284  * Return:	Non-NULL pointer to index block on success/NULL on failure
285  *
286  * Programmer:	Quincey Koziol
287  *		koziol@hdfgroup.org
288  *		Sep  9 2008
289  *
290  *-------------------------------------------------------------------------
291  */
292 BEGIN_FUNC(PKG, ERR,
293 H5EA_iblock_t *, NULL, NULL,
294 H5EA__iblock_protect(H5EA_hdr_t *hdr, unsigned flags))
295 
296     /* Local variables */
297     H5EA_iblock_t *iblock = NULL;       /* Pointer to index block */
298 
299 #ifdef QAK
300 HDfprintf(stderr, "%s: Called\n", FUNC);
301 #endif /* QAK */
302 
303     /* Sanity check */
304     HDassert(hdr);
305 
306     /* only the H5AC__READ_ONLY_FLAG may be set */
307     HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
308 
309     /* Protect the index block */
310     if(NULL == (iblock = (H5EA_iblock_t *)H5AC_protect(hdr->f, H5AC_EARRAY_IBLOCK, hdr->idx_blk_addr, hdr, flags)))
311         H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr)
312 
313     /* Create top proxy, if it doesn't exist */
314     if(hdr->top_proxy && NULL == iblock->top_proxy) {
315         /* Add index block as child of 'top' proxy */
316         if(H5AC_proxy_entry_add_child(hdr->top_proxy, hdr->f, iblock) < 0)
317             H5E_THROW(H5E_CANTSET, "unable to add extensible array entry as child of array proxy")
318         iblock->top_proxy = hdr->top_proxy;
319     } /* end if */
320 
321     /* Set return value */
322     ret_value = iblock;
323 
324 CATCH
325     /* Clean up on error */
326     if(!ret_value) {
327         /* Release the index block, if it was protected */
328         if(iblock && H5AC_unprotect(hdr->f, H5AC_EARRAY_IBLOCK, iblock->addr, iblock, H5AC__NO_FLAGS_SET) < 0)
329             H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array index block, address = %llu", (unsigned long long)iblock->addr)
330     } /* end if */
331 
332 END_FUNC(PKG)   /* end H5EA__iblock_protect() */
333 
334 
335 /*-------------------------------------------------------------------------
336  * Function:	H5EA__iblock_unprotect
337  *
338  * Purpose:	Convenience wrapper around unprotecting extensible array index block
339  *
340  * Return:	Non-negative on success/Negative on failure
341  *
342  * Programmer:	Quincey Koziol
343  *		koziol@hdfgroup.org
344  *		Sep  9 2008
345  *
346  *-------------------------------------------------------------------------
347  */
348 BEGIN_FUNC(PKG, ERR,
349 herr_t, SUCCEED, FAIL,
350 H5EA__iblock_unprotect(H5EA_iblock_t *iblock, unsigned cache_flags))
351 
352     /* Local variables */
353 
354 #ifdef QAK
355 HDfprintf(stderr, "%s: Called\n", FUNC);
356 #endif /* QAK */
357 
358     /* Sanity check */
359     HDassert(iblock);
360 
361     /* Unprotect the index block */
362     if(H5AC_unprotect(iblock->hdr->f, H5AC_EARRAY_IBLOCK, iblock->addr, iblock, cache_flags) < 0)
363         H5E_THROW(H5E_CANTUNPROTECT, "unable to unprotect extensible array index block, address = %llu", (unsigned long long)iblock->addr)
364 
365 CATCH
366 
367 END_FUNC(PKG)   /* end H5EA__iblock_unprotect() */
368 
369 
370 /*-------------------------------------------------------------------------
371  * Function:	H5EA__iblock_delete
372  *
373  * Purpose:	Delete index block
374  *
375  * Return:	SUCCEED/FAIL
376  *
377  * Programmer:	Quincey Koziol
378  *		koziol@hdfgroup.org
379  *		Sep  9 2008
380  *
381  *-------------------------------------------------------------------------
382  */
383 BEGIN_FUNC(PKG, ERR,
384 herr_t, SUCCEED, FAIL,
385 H5EA__iblock_delete(H5EA_hdr_t *hdr))
386 
387     /* Local variables */
388     H5EA_iblock_t *iblock = NULL;       /* Pointer to index block */
389 
390 #ifdef QAK
391 HDfprintf(stderr, "%s: Called\n", FUNC);
392 #endif /* QAK */
393 
394     /* Sanity check */
395     HDassert(hdr);
396     HDassert(H5F_addr_defined(hdr->idx_blk_addr));
397 
398     /* Protect index block */
399     if(NULL == (iblock = H5EA__iblock_protect(hdr, H5AC__NO_FLAGS_SET)))
400         H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr)
401 
402     /* Check for index block having data block pointers */
403     if(iblock->ndblk_addrs > 0) {
404         unsigned sblk_idx;      /* Current super block index */
405         unsigned dblk_idx;      /* Current data block index w/in super block */
406         size_t u;               /* Local index variable */
407 
408         /* Iterate over data blocks */
409         sblk_idx = dblk_idx = 0;
410         for(u = 0; u < iblock->ndblk_addrs; u++) {
411             /* Check for data block existing */
412             if(H5F_addr_defined(iblock->dblk_addrs[u])) {
413                 /* Delete data block */
414                 if(H5EA__dblock_delete(hdr, iblock, iblock->dblk_addrs[u], hdr->sblk_info[sblk_idx].dblk_nelmts) < 0)
415                     H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array data block")
416                 iblock->dblk_addrs[u] = HADDR_UNDEF;
417             } /* end if */
418 
419             /* Advance to next data block w/in super block */
420             dblk_idx++;
421 
422             /* Check for moving to next super block */
423             if(dblk_idx >= hdr->sblk_info[sblk_idx].ndblks) {
424                 sblk_idx++;
425                 dblk_idx = 0;
426             } /* end if */
427         } /* end for */
428     } /* end if */
429 
430     /* Check for index block having data block pointers (not yet) */
431     if(iblock->nsblk_addrs > 0) {
432         size_t u;               /* Local index variable */
433 
434         /* Iterate over super blocks */
435         for(u = 0; u < iblock->nsblk_addrs; u++) {
436             /* Check for data block existing */
437             if(H5F_addr_defined(iblock->sblk_addrs[u])) {
438                 /* Delete super block */
439                 if(H5EA__sblock_delete(hdr, iblock, iblock->sblk_addrs[u], (unsigned)(u + iblock->nsblks)) < 0)
440                     H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array super block")
441                 iblock->sblk_addrs[u] = HADDR_UNDEF;
442             } /* end if */
443         } /* end for */
444     } /* end if */
445 
446 CATCH
447     /* Finished deleting index block in metadata cache */
448     if(iblock && H5EA__iblock_unprotect(iblock, H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
449         H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array index block")
450 
451 END_FUNC(PKG)   /* end H5EA__iblock_delete() */
452 
453 
454 /*-------------------------------------------------------------------------
455  * Function:	H5EA__iblock_dest
456  *
457  * Purpose:	Destroys an extensible array index block in memory.
458  *
459  * Return:	Non-negative on success/Negative on failure
460  *
461  * Programmer:	Quincey Koziol
462  *		koziol@hdfgroup.org
463  *		Sep 11 2008
464  *
465  *-------------------------------------------------------------------------
466  */
467 BEGIN_FUNC(PKG, ERR,
468 herr_t, SUCCEED, FAIL,
469 H5EA__iblock_dest(H5EA_iblock_t *iblock))
470 
471     /* Sanity check */
472     HDassert(iblock);
473 
474     /* Check if shared header field has been initialized */
475     if(iblock->hdr) {
476         /* Check if we've got elements in the index block */
477         if(iblock->elmts) {
478             /* Free buffer for index block elements */
479             HDassert(iblock->hdr->cparam.idx_blk_elmts > 0);
480             iblock->elmts = H5FL_BLK_FREE(idx_blk_elmt_buf, iblock->elmts);
481         } /* end if */
482 
483         /* Check if we've got data block addresses in the index block */
484         if(iblock->dblk_addrs) {
485             /* Free buffer for index block data block addresses */
486             HDassert(iblock->ndblk_addrs > 0);
487             iblock->dblk_addrs = H5FL_SEQ_FREE(haddr_t, iblock->dblk_addrs);
488             iblock->ndblk_addrs = 0;
489         } /* end if */
490 
491         /* Check if we've got super block addresses in the index block */
492         if(iblock->sblk_addrs) {
493             /* Free buffer for index block super block addresses */
494             HDassert(iblock->nsblk_addrs > 0);
495             iblock->sblk_addrs = H5FL_SEQ_FREE(haddr_t, iblock->sblk_addrs);
496             iblock->nsblk_addrs = 0;
497         } /* end if */
498 
499         /* Decrement reference count on shared info */
500         if(H5EA__hdr_decr(iblock->hdr) < 0)
501             H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header")
502         iblock->hdr = NULL;
503     } /* end if */
504 
505     /* Sanity check */
506     HDassert(NULL == iblock->top_proxy);
507 
508     /* Free the index block itself */
509     iblock = H5FL_FREE(H5EA_iblock_t, iblock);
510 
511 CATCH
512 
513 END_FUNC(PKG)   /* end H5EA__iblock_dest() */
514 
515