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://www.hdfgroup.org/licenses.               *
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:		H5HFdblock.c
17  *			Apr 10 2006
18  *			Quincey Koziol
19  *
20  * Purpose:		Direct block routines for fractal heaps.
21  *
22  *-------------------------------------------------------------------------
23  */
24 
25 /****************/
26 /* Module Setup */
27 /****************/
28 
29 #include "H5HFmodule.h" /* This source code file is part of the H5HF module */
30 
31 /***********/
32 /* Headers */
33 /***********/
34 #include "H5private.h"   /* Generic Functions			*/
35 #include "H5Eprivate.h"  /* Error handling		  	*/
36 #include "H5Fprivate.h"  /* File access				*/
37 #include "H5HFpkg.h"     /* Fractal heaps			*/
38 #include "H5MFprivate.h" /* File memory management		*/
39 #include "H5VMprivate.h" /* Vectors and arrays 			*/
40 
41 /****************/
42 /* Local Macros */
43 /****************/
44 
45 /******************/
46 /* Local Typedefs */
47 /******************/
48 
49 /********************/
50 /* Package Typedefs */
51 /********************/
52 
53 /********************/
54 /* Local Prototypes */
55 /********************/
56 
57 /*********************/
58 /* Package Variables */
59 /*********************/
60 
61 /* Declare a free list to manage the H5HF_direct_t struct */
62 H5FL_DEFINE(H5HF_direct_t);
63 
64 /*****************************/
65 /* Library Private Variables */
66 /*****************************/
67 
68 /*******************/
69 /* Local Variables */
70 /*******************/
71 
72 /*-------------------------------------------------------------------------
73  * Function:	H5HF__man_dblock_create
74  *
75  * Purpose:	Allocate & initialize a managed direct block
76  *
77  * Return:	Pointer to new direct block on success, NULL on failure
78  *
79  * Programmer:	Quincey Koziol
80  *		Feb 27 2006
81  *
82  *-------------------------------------------------------------------------
83  */
84 herr_t
H5HF__man_dblock_create(H5HF_hdr_t * hdr,H5HF_indirect_t * par_iblock,unsigned par_entry,haddr_t * addr_p,H5HF_free_section_t ** ret_sec_node)85 H5HF__man_dblock_create(H5HF_hdr_t *hdr, H5HF_indirect_t *par_iblock, unsigned par_entry, haddr_t *addr_p,
86                         H5HF_free_section_t **ret_sec_node)
87 {
88     H5HF_free_section_t *sec_node;            /* Pointer to free space section for block */
89     H5HF_direct_t *      dblock = NULL;       /* Pointer to direct block */
90     haddr_t              dblock_addr;         /* Direct block's address */
91     size_t               free_space;          /* Free space in new block */
92     herr_t               ret_value = SUCCEED; /* Return value */
93 
94     FUNC_ENTER_PACKAGE
95 
96     /*
97      * Check arguments.
98      */
99     HDassert(hdr);
100 
101     /*
102      * Allocate file and memory data structures.
103      */
104     if (NULL == (dblock = H5FL_MALLOC(H5HF_direct_t)))
105         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for fractal heap direct block")
106 
107     /* Reset the metadata cache info for the heap header */
108     HDmemset(&dblock->cache_info, 0, sizeof(H5AC_info_t));
109 
110     /* Share common heap information */
111     dblock->hdr = hdr;
112     if (H5HF__hdr_incr(hdr) < 0)
113         HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment reference count on shared heap header")
114 
115     /* Set info for direct block */
116     if (par_iblock) {
117         unsigned par_row = par_entry / hdr->man_dtable.cparam.width; /* Row for block */
118 
119         /* Compute offset & size, based on parent's information */
120         dblock->block_off = par_iblock->block_off;
121         dblock->block_off += hdr->man_dtable.row_block_off[par_row];
122         dblock->block_off +=
123             hdr->man_dtable.row_block_size[par_row] * (par_entry % hdr->man_dtable.cparam.width);
124         H5_CHECKED_ASSIGN(dblock->size, size_t, hdr->man_dtable.row_block_size[par_row], hsize_t);
125     } /* end if */
126     else {
127         /* Must be the root direct block */
128         dblock->block_off = 0;
129         dblock->size      = hdr->man_dtable.cparam.start_block_size;
130     } /* end else */
131     dblock->file_size = 0;
132     free_space        = dblock->size - H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr);
133 
134     /* Allocate buffer for block */
135     /* XXX: Change to using free-list factories */
136     if ((dblock->blk = H5FL_BLK_MALLOC(direct_block, dblock->size)) == NULL)
137         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
138     HDmemset(dblock->blk, 0, dblock->size);
139 
140     dblock->write_buf  = NULL;
141     dblock->write_size = 0;
142 
143     /* Allocate [temporary] space for the direct block on disk */
144     if (H5F_USE_TMP_SPACE(hdr->f)) {
145         if (HADDR_UNDEF == (dblock_addr = H5MF_alloc_tmp(hdr->f, (hsize_t)dblock->size)))
146             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
147                         "file allocation failed for fractal heap direct block")
148     } /* end if */
149     else {
150         if (HADDR_UNDEF == (dblock_addr = H5MF_alloc(hdr->f, H5FD_MEM_FHEAP_DBLOCK, (hsize_t)dblock->size)))
151             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
152                         "file allocation failed for fractal heap direct block")
153     } /* end else */
154 
155     /* Attach to parent indirect block, if there is one */
156     dblock->parent = par_iblock;
157     if (dblock->parent) {
158         if (H5HF__man_iblock_attach(dblock->parent, par_entry, dblock_addr) < 0)
159             HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't attach direct block to parent indirect block")
160         dblock->fd_parent = par_iblock;
161     } /* end if */
162     else
163         dblock->fd_parent = hdr;
164     dblock->par_entry = par_entry;
165 
166     /* Create a new 'single' section for the free space in the block */
167     if (NULL == (sec_node = H5HF__sect_single_new((dblock->block_off + H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr)),
168                                                   free_space, dblock->parent, dblock->par_entry)))
169         HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't create section for new direct block's free space")
170 
171     /* Check what to do with section node */
172     if (ret_sec_node)
173         /* Pass back the pointer to the section instead of adding it to the free list */
174         *ret_sec_node = sec_node;
175     else {
176         /* Add new free space to the heap's list of space */
177         if (H5HF__space_add(hdr, sec_node, 0) < 0)
178             HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add direct block free space to global list")
179     } /* end else */
180 
181     /* Cache the new fractal heap direct block */
182     if (H5AC_insert_entry(hdr->f, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, H5AC__NO_FLAGS_SET) < 0)
183         HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "can't add fractal heap direct block to cache")
184 
185     /* Increase the allocated heap size */
186     if (H5HF__hdr_inc_alloc(hdr, dblock->size) < 0)
187         HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't increase allocated heap size")
188 
189     /* Set the address of of direct block, if requested */
190     if (addr_p)
191         *addr_p = dblock_addr;
192 
193 done:
194     if (ret_value < 0)
195         if (dblock)
196             if (H5HF__man_dblock_dest(dblock) < 0)
197                 HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to destroy fractal heap direct block")
198 
199     FUNC_LEAVE_NOAPI(ret_value)
200 } /* end H5HF__man_dblock_create() */
201 
202 /*-------------------------------------------------------------------------
203  * Function:	H5HF__man_dblock_destroy
204  *
205  * Purpose:	Destroy a managed direct block
206  *
207  * Note:	This routine does _not_ insert a range section for the
208  *              destroyed direct block, that must be handled by the
209  *              caller.
210  *
211  * Return:	SUCCEED/FAIL
212  *
213  * Programmer:	Quincey Koziol
214  *		May 17 2006
215  *
216  *-------------------------------------------------------------------------
217  */
218 herr_t
H5HF__man_dblock_destroy(H5HF_hdr_t * hdr,H5HF_direct_t * dblock,haddr_t dblock_addr,hbool_t * parent_removed)219 H5HF__man_dblock_destroy(H5HF_hdr_t *hdr, H5HF_direct_t *dblock, haddr_t dblock_addr, hbool_t *parent_removed)
220 {
221     hsize_t  dblock_size;                      /* Size of direct block on disk */
222     unsigned cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting indirect block */
223     herr_t   ret_value   = SUCCEED;            /* Return value */
224 
225     FUNC_ENTER_PACKAGE
226 
227     /*
228      * Check arguments.
229      */
230     HDassert(hdr);
231     HDassert(dblock);
232 
233     /* Check for I/O filters on this heap */
234     if (hdr->filter_len > 0) {
235         /* Check for root direct block */
236         if (dblock->parent == NULL)
237             /* Get direct block's actual size */
238             dblock_size = (hsize_t)hdr->pline_root_direct_size;
239         else {
240             H5HF_indirect_t *par_iblock; /* Parent indirect block */
241             unsigned         par_entry;  /* Entry in parent indirect block */
242 
243             /* Get parent information */
244             par_iblock = dblock->parent;
245             par_entry  = dblock->par_entry;
246 
247             /* Get direct block's actual size */
248             dblock_size = (hsize_t)par_iblock->filt_ents[par_entry].size;
249         } /* end else */
250     }     /* end if */
251     else
252         dblock_size = (hsize_t)dblock->size;
253 
254     /* Reset the parent_removed flag */
255     if (parent_removed)
256         *parent_removed = FALSE;
257 
258     /* Check for root direct block */
259     if (hdr->man_dtable.curr_root_rows == 0) {
260         /* Sanity check */
261         HDassert(hdr->man_dtable.table_addr == dblock_addr);
262         HDassert(hdr->man_dtable.cparam.start_block_size == dblock->size);
263 
264         /* Sanity check block iterator */
265         HDassert(!H5HF__man_iter_ready(&hdr->next_block));
266 
267         /* Reset header information back to "empty heap" state */
268         if (H5HF__hdr_empty(hdr) < 0)
269             HGOTO_ERROR(H5E_HEAP, H5E_CANTSHRINK, FAIL, "can't make heap empty")
270     } /* end if */
271     else {
272         /* Adjust heap statistics */
273         hdr->man_alloc_size -= dblock->size;
274 
275         /* Check for this direct block being the highest in the heap */
276         if ((dblock->block_off + dblock->size) == hdr->man_iter_off)
277             /* Move 'next block' iterator backwards (may shrink heap) */
278             if (H5HF__hdr_reverse_iter(hdr, dblock_addr) < 0)
279                 HGOTO_ERROR(H5E_HEAP, H5E_CANTRELEASE, FAIL, "can't reverse 'next block' iterator")
280 
281         /* Detach from parent indirect block */
282         if (dblock->parent) {
283             /* Destroy flush dependency between direct block and parent */
284             if (H5AC_destroy_flush_dependency(dblock->fd_parent, dblock) < 0)
285                 HGOTO_ERROR(H5E_HEAP, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
286             dblock->fd_parent = NULL;
287 
288             /* If this is the last direct block for the indirect block, the
289              *  indirect block will be removed when this direct block is detached
290              */
291             if (parent_removed && 1 == dblock->parent->nchildren)
292                 *parent_removed = TRUE;
293 
294             if (H5HF__man_iblock_detach(dblock->parent, dblock->par_entry) < 0)
295                 HGOTO_ERROR(H5E_HEAP, H5E_CANTATTACH, FAIL, "can't detach from parent indirect block");
296             dblock->parent    = NULL;
297             dblock->par_entry = 0;
298         } /* end if */
299     }     /* end else */
300 
301     /* Indicate that the direct block should be deleted */
302     dblock->file_size = dblock_size;
303     cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG;
304 
305     /* If the dblock is in real file space, also tell the cache to free its file space */
306     if (!H5F_IS_TMP_ADDR(hdr->f, dblock_addr))
307         cache_flags |= H5AC__FREE_FILE_SPACE_FLAG;
308 
309 done:
310     /* Unprotect the indirect block, with appropriate flags */
311     if (H5AC_unprotect(hdr->f, H5AC_FHEAP_DBLOCK, dblock_addr, dblock, cache_flags) < 0)
312         HDONE_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap direct block")
313 
314     FUNC_LEAVE_NOAPI(ret_value)
315 } /* end H5HF__man_dblock_destroy() */
316 
317 /*-------------------------------------------------------------------------
318  * Function:	H5HF__man_dblock_new
319  *
320  * Purpose:	Create a direct block large enough to hold an object of
321  *              the requested size
322  *
323  * Return:	SUCCEED/FAIL
324  *
325  * Programmer:	Quincey Koziol
326  *		Mar 13 2006
327  *
328  *-------------------------------------------------------------------------
329  */
330 herr_t
H5HF__man_dblock_new(H5HF_hdr_t * hdr,size_t request,H5HF_free_section_t ** ret_sec_node)331 H5HF__man_dblock_new(H5HF_hdr_t *hdr, size_t request, H5HF_free_section_t **ret_sec_node)
332 {
333     haddr_t dblock_addr;         /* Address of new direct block */
334     size_t  min_dblock_size;     /* Min. size of direct block to allocate */
335     herr_t  ret_value = SUCCEED; /* Return value */
336 
337     FUNC_ENTER_PACKAGE
338 
339     /*
340      * Check arguments.
341      */
342     HDassert(hdr);
343     HDassert(request > 0);
344 
345     /* Compute the min. size of the direct block needed to fulfill the request */
346     if (request < hdr->man_dtable.cparam.start_block_size)
347         min_dblock_size = hdr->man_dtable.cparam.start_block_size;
348     else {
349         min_dblock_size = ((size_t)1) << (1 + H5VM_log2_gen((uint64_t)request));
350         HDassert(min_dblock_size <= hdr->man_dtable.cparam.max_direct_size);
351     } /* end else */
352 
353     /* Adjust the size of block needed to fulfill request, with overhead */
354     if (min_dblock_size < H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr) + request)
355         min_dblock_size *= 2;
356 
357     /* Check if this is the first block in the heap */
358     if (!H5F_addr_defined(hdr->man_dtable.table_addr) &&
359         min_dblock_size == hdr->man_dtable.cparam.start_block_size) {
360         /* Create new direct block at starting offset */
361         if (H5HF__man_dblock_create(hdr, NULL, 0, &dblock_addr, ret_sec_node) < 0)
362             HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block")
363 
364         /* Point root at new direct block */
365         hdr->man_dtable.curr_root_rows = 0;
366         hdr->man_dtable.table_addr     = dblock_addr;
367         if (hdr->filter_len > 0) {
368             hdr->pline_root_direct_size        = hdr->man_dtable.cparam.start_block_size;
369             hdr->pline_root_direct_filter_mask = 0;
370         } /* end if */
371 
372         /* Extend heap to cover new direct block */
373         if (H5HF__hdr_adjust_heap(hdr, (hsize_t)hdr->man_dtable.cparam.start_block_size,
374                                   (hssize_t)hdr->man_dtable.row_tot_dblock_free[0]) < 0)
375             HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "can't increase space to cover root direct block")
376     } /* end if */
377     /* Root entry already exists, allocate direct block from root indirect block */
378     else {
379         H5HF_indirect_t *iblock;     /* Pointer to indirect block to create */
380         unsigned         next_row;   /* Iterator's next block row */
381         unsigned         next_entry; /* Iterator's next block entry */
382         size_t           next_size;  /* Size of next direct block to create */
383 
384         /* Update iterator to reflect any previous increments as well as allow for requested direct block size
385          */
386         if (H5HF__hdr_update_iter(hdr, min_dblock_size) < 0)
387             HGOTO_ERROR(H5E_HEAP, H5E_CANTUPDATE, FAIL, "unable to update block iterator")
388 
389         /* Retrieve information about current iterator position */
390         if (H5HF__man_iter_curr(&hdr->next_block, &next_row, NULL, &next_entry, &iblock) < 0)
391             HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to retrieve current block iterator location")
392         HDassert(next_row < iblock->nrows);
393         H5_CHECKED_ASSIGN(next_size, size_t, hdr->man_dtable.row_block_size[next_row], hsize_t);
394 
395         /* Check for skipping over blocks */
396         if (min_dblock_size > next_size) {
397             HDfprintf(
398                 stderr,
399                 "%s: Skipping direct block sizes not supported, min_dblock_size = %zu, next_size = %zu\n",
400                 FUNC, min_dblock_size, next_size);
401             HGOTO_ERROR(H5E_HEAP, H5E_UNSUPPORTED, FAIL, "skipping direct block sizes not supported yet")
402         } /* end if */
403 
404         /* Advance "next block" iterator to next direct block entry */
405         if (H5HF__hdr_inc_iter(hdr, (hsize_t)next_size, 1) < 0)
406             HGOTO_ERROR(H5E_HEAP, H5E_CANTINC, FAIL, "can't increment 'next block' iterator")
407 
408         /* Create new direct block at current location*/
409         if (H5HF__man_dblock_create(hdr, iblock, next_entry, &dblock_addr, ret_sec_node) < 0)
410             HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap direct block")
411     } /* end else */
412 
413 done:
414     FUNC_LEAVE_NOAPI(ret_value)
415 } /* end H5HF__man_dblock_new() */
416 
417 /*-------------------------------------------------------------------------
418  * Function:	H5HF__man_dblock_protect
419  *
420  * Purpose:	Convenience wrapper around H5AC_protect on a direct block
421  *              (Use H5AC_unprotect to unprotect it for now)
422  *
423  * Return:	Pointer to direct block on success, NULL on failure
424  *
425  * Programmer:	Quincey Koziol
426  *		Apr 17 2006
427  *
428  *-------------------------------------------------------------------------
429  */
430 H5HF_direct_t *
H5HF__man_dblock_protect(H5HF_hdr_t * hdr,haddr_t dblock_addr,size_t dblock_size,H5HF_indirect_t * par_iblock,unsigned par_entry,unsigned flags)431 H5HF__man_dblock_protect(H5HF_hdr_t *hdr, haddr_t dblock_addr, size_t dblock_size,
432                          H5HF_indirect_t *par_iblock, unsigned par_entry, unsigned flags)
433 {
434     H5HF_direct_t *        dblock;           /* Direct block from cache */
435     H5HF_dblock_cache_ud_t udata;            /* parent and other infor for deserializing direct block */
436     H5HF_direct_t *        ret_value = NULL; /* Return value */
437 
438     FUNC_ENTER_PACKAGE
439 
440     /*
441      * Check arguments.
442      */
443     HDassert(hdr);
444     HDassert(H5F_addr_defined(dblock_addr));
445     HDassert(dblock_size > 0);
446 
447     /* only H5AC__READ_ONLY_FLAG may appear in flags */
448     HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
449 
450     /* Set up parent info */
451     udata.par_info.hdr    = hdr;
452     udata.par_info.iblock = par_iblock;
453     udata.par_info.entry  = par_entry;
454 
455     /* set up the file pointer in the user data */
456     udata.f = hdr->f;
457 
458     /* set up the direct block size */
459     udata.dblock_size = dblock_size;
460 
461     /* compute the on disk image size -- observe that odi_size and
462      * dblock_size will be identical if there is no filtering.
463      */
464     if (hdr->filter_len > 0) {
465         if (par_iblock == NULL) {
466             udata.odi_size    = hdr->pline_root_direct_size;
467             udata.filter_mask = hdr->pline_root_direct_filter_mask;
468         } /* end if */
469         else {
470             /* Sanity check */
471             HDassert(H5F_addr_eq(par_iblock->ents[par_entry].addr, dblock_addr));
472 
473             /* Set up parameters to read filtered direct block */
474             udata.odi_size    = par_iblock->filt_ents[par_entry].size;
475             udata.filter_mask = par_iblock->filt_ents[par_entry].filter_mask;
476         } /* end else */
477     }     /* end if */
478     else {
479         udata.odi_size    = dblock_size;
480         udata.filter_mask = 0;
481     } /* end else */
482 
483     /* Reset compression context info */
484     udata.decompressed = FALSE;
485     udata.dblk         = NULL;
486 
487     /* Protect the direct block */
488     if (NULL ==
489         (dblock = (H5HF_direct_t *)H5AC_protect(hdr->f, H5AC_FHEAP_DBLOCK, dblock_addr, &udata, flags)))
490         HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, NULL, "unable to protect fractal heap direct block")
491 
492     /* Set the return value */
493     ret_value = dblock;
494 
495 done:
496     FUNC_LEAVE_NOAPI(ret_value)
497 } /* end H5HF__man_dblock_protect() */
498 
499 /*-------------------------------------------------------------------------
500  * Function:	H5HF__man_dblock_locate
501  *
502  * Purpose:	Locate a direct block in a managed heap
503  *
504  * Return:	SUCCEED/FAIL
505  *
506  * Programmer:	Quincey Koziol
507  *		May  8 2006
508  *
509  *-------------------------------------------------------------------------
510  */
511 herr_t
H5HF__man_dblock_locate(H5HF_hdr_t * hdr,hsize_t obj_off,H5HF_indirect_t ** ret_iblock,unsigned * ret_entry,hbool_t * ret_did_protect,unsigned flags)512 H5HF__man_dblock_locate(H5HF_hdr_t *hdr, hsize_t obj_off, H5HF_indirect_t **ret_iblock, unsigned *ret_entry,
513                         hbool_t *ret_did_protect, unsigned flags)
514 {
515     haddr_t          iblock_addr;         /* Indirect block's address */
516     H5HF_indirect_t *iblock;              /* Pointer to indirect block */
517     hbool_t          did_protect;         /* Whether we protected the indirect block or not */
518     unsigned         row, col;            /* Row & column for object's block */
519     unsigned         entry;               /* Entry of block */
520     herr_t           ret_value = SUCCEED; /* Return value */
521 
522     FUNC_ENTER_PACKAGE
523 
524     /*
525      * Check arguments.
526      */
527     HDassert(hdr);
528     HDassert(hdr->man_dtable.curr_root_rows); /* Only works for heaps with indirect root block */
529     HDassert(ret_iblock);
530     HDassert(ret_did_protect);
531 
532     /* only H5AC__READ_ONLY_FLAG may appear in flags */
533     HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0);
534 
535     /* Look up row & column for object */
536     if (H5HF__dtable_lookup(&hdr->man_dtable, obj_off, &row, &col) < 0)
537         HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of object")
538 
539     /* Set initial indirect block info */
540     iblock_addr = hdr->man_dtable.table_addr;
541 
542     /* Lock root indirect block */
543     if (NULL == (iblock = H5HF__man_iblock_protect(hdr, iblock_addr, hdr->man_dtable.curr_root_rows, NULL, 0,
544                                                    FALSE, flags, &did_protect)))
545         HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
546 
547     /* Check for indirect block row */
548     while (row >= hdr->man_dtable.max_direct_rows) {
549         H5HF_indirect_t *new_iblock;      /* Pointer to new indirect block */
550         hbool_t          new_did_protect; /* Whether we protected the indirect block or not */
551         unsigned         nrows;           /* Number of rows in new indirect block */
552         unsigned         cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting parent indirect block */
553 
554         /* Compute # of rows in child indirect block */
555         nrows = (H5VM_log2_gen(hdr->man_dtable.row_block_size[row]) - hdr->man_dtable.first_row_bits) + 1;
556         HDassert(nrows < iblock->nrows); /* child must be smaller than parent */
557 
558         /* Compute indirect block's entry */
559         entry = (row * hdr->man_dtable.cparam.width) + col;
560 
561         /* Locate child indirect block */
562         iblock_addr = iblock->ents[entry].addr;
563 
564         /* Check if we need to (re-)create the child indirect block */
565         if (!H5F_addr_defined(iblock_addr)) {
566             if (H5HF__man_iblock_create(hdr, iblock, entry, nrows, nrows, &iblock_addr) < 0)
567                 HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, FAIL, "can't allocate fractal heap indirect block")
568 
569             /* Indicate that the parent indirect block was modified */
570             cache_flags |= H5AC__DIRTIED_FLAG;
571         } /* end if */
572 
573         /* Lock child indirect block */
574         if (NULL == (new_iblock = H5HF__man_iblock_protect(hdr, iblock_addr, nrows, iblock, entry, FALSE,
575                                                            flags, &new_did_protect)))
576             HGOTO_ERROR(H5E_HEAP, H5E_CANTPROTECT, FAIL, "unable to protect fractal heap indirect block")
577 
578         /* Release the current indirect block */
579         if (H5HF__man_iblock_unprotect(iblock, cache_flags, did_protect) < 0)
580             HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPROTECT, FAIL, "unable to release fractal heap indirect block")
581 
582         /* Switch variables to use new indirect block */
583         iblock      = new_iblock;
584         did_protect = new_did_protect;
585 
586         /* Look up row & column in new indirect block for object */
587         if (H5HF__dtable_lookup(&hdr->man_dtable, (obj_off - iblock->block_off), &row, &col) < 0)
588             HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPUTE, FAIL, "can't compute row & column of object")
589         HDassert(row < iblock->nrows); /* child must be smaller than parent */
590     }                                  /* end while */
591 
592     /* Set return parameters */
593     if (ret_entry)
594         *ret_entry = (row * hdr->man_dtable.cparam.width) + col;
595     *ret_iblock      = iblock;
596     *ret_did_protect = did_protect;
597 
598 done:
599     FUNC_LEAVE_NOAPI(ret_value)
600 } /* end H5HF__man_dblock_locate() */
601 
602 /*-------------------------------------------------------------------------
603  * Function:	H5HF__man_dblock_delete
604  *
605  * Purpose:	Delete a managed direct block
606  *
607  * Note:	This routine does _not_ modify any indirect block that points
608  *              to this direct block, it is assumed that the whole heap is
609  *              being deleted.  (H5HF__man_dblock_destroy modifies the indirect
610  *              block)
611  *
612  * Return:	SUCCEED/FAIL
613  *
614  * Programmer:	Quincey Koziol
615  *		Aug  7 2006
616  *
617  *-------------------------------------------------------------------------
618  */
619 herr_t
H5HF__man_dblock_delete(H5F_t * f,haddr_t dblock_addr,hsize_t dblock_size)620 H5HF__man_dblock_delete(H5F_t *f, haddr_t dblock_addr, hsize_t dblock_size)
621 {
622     unsigned dblock_status = 0;       /* Direct block's status in the metadata cache */
623     herr_t   ret_value     = SUCCEED; /* Return value */
624 
625     FUNC_ENTER_PACKAGE
626 
627     /*
628      * Check arguments.
629      */
630     HDassert(f);
631     HDassert(H5F_addr_defined(dblock_addr));
632     HDassert(dblock_size > 0);
633 
634     /* Check the direct block's status in the metadata cache */
635     if (H5AC_get_entry_status(f, dblock_addr, &dblock_status) < 0)
636         HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for direct block")
637 
638     /* If the direct block is in the cache, expunge it now */
639     if (dblock_status & H5AC_ES__IN_CACHE) {
640         /* Sanity checks on direct block */
641         HDassert(!(dblock_status & H5AC_ES__IS_PINNED));
642         HDassert(!(dblock_status & H5AC_ES__IS_PROTECTED));
643 
644         /* Evict the direct block from the metadata cache */
645         if (H5AC_expunge_entry(f, H5AC_FHEAP_DBLOCK, dblock_addr, H5AC__NO_FLAGS_SET) < 0)
646             HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "unable to remove direct block from cache")
647     } /* end if */
648 
649     /* Check if the direct block is NOT currently allocated in temp. file space */
650     /* (temp. file space does not need to be freed) */
651     if (!H5F_IS_TMP_ADDR(f, dblock_addr))
652         /* Release direct block's disk space */
653         /* (XXX: Under the best of circumstances, this block's space in the file
654          *          would be freed in the H5AC_expunge_entry() call above (and the
655          *          H5AC__FREE_FILE_SPACE_FLAG used there), but since the direct
656          *          block structure might have a different size on disk than in
657          *          the heap's 'abstract' address space, we would need to set the
658          *          "file_size" field for the direct block structure.  In order to
659          *          do that, we'd have to protect/unprotect the direct block and
660          *          that would add a bunch of unnecessary overhead to the process,
661          *          so we just release the file space here, directly.  -QAK)
662          */
663         if (H5MF_xfree(f, H5FD_MEM_FHEAP_DBLOCK, dblock_addr, dblock_size) < 0)
664             HGOTO_ERROR(H5E_HEAP, H5E_CANTFREE, FAIL, "unable to free fractal heap direct block file space")
665 
666 done:
667     FUNC_LEAVE_NOAPI(ret_value)
668 } /* end H5HF__man_dblock_delete() */
669 
670 /*-------------------------------------------------------------------------
671  * Function:	H5HF__man_dblock_dest
672  *
673  * Purpose:	Destroys a fractal heap direct block in memory.
674  *
675  * Return:	Non-negative on success/Negative on failure
676  *
677  * Programmer:	Quincey Koziol
678  *		Feb 27 2006
679  *
680  *-------------------------------------------------------------------------
681  */
682 herr_t
H5HF__man_dblock_dest(H5HF_direct_t * dblock)683 H5HF__man_dblock_dest(H5HF_direct_t *dblock)
684 {
685     herr_t ret_value = SUCCEED; /* Return value */
686 
687     FUNC_ENTER_PACKAGE
688 
689     /*
690      * Check arguments.
691      */
692     HDassert(dblock);
693 
694     /* Decrement reference count on shared fractal heap info */
695     HDassert(dblock->hdr != NULL);
696     if (H5HF__hdr_decr(dblock->hdr) < 0)
697         HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL, "can't decrement reference count on shared heap header")
698     if (dblock->parent)
699         if (H5HF__iblock_decr(dblock->parent) < 0)
700             HGOTO_ERROR(H5E_HEAP, H5E_CANTDEC, FAIL,
701                         "can't decrement reference count on shared indirect block")
702 
703     /* Free block's buffer */
704     dblock->blk = H5FL_BLK_FREE(direct_block, dblock->blk);
705 
706     /* Free fractal heap direct block info */
707     dblock = H5FL_FREE(H5HF_direct_t, dblock);
708 
709 done:
710     FUNC_LEAVE_NOAPI(ret_value)
711 } /* end H5HF__man_dblock_dest() */
712