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 files COPYING and Copyright.html. COPYING can be found at the root *
9 * of the source code distribution tree; Copyright.html can be found at the *
10 * root level of an installed copy of the electronic HDF5 document set and *
11 * is linked from the top-level documents page. It can also be found at *
12 * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
13 * access to either file, you may request a copy from help@hdfgroup.org. *
14 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /*
17 * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
18 * Tuesday, May 2, 2006
19 *
20 * Purpose: Free space tracking functions.
21 *
22 * Note: (Used to be in the H5HFflist.c file, prior to the date above)
23 *
24 */
25
26 /****************/
27 /* Module Setup */
28 /****************/
29
30 #define H5FS_PACKAGE /*suppress error about including H5FSpkg */
31
32 /***********/
33 /* Headers */
34 /***********/
35 #include "H5private.h" /* Generic Functions */
36 #include "H5ACprivate.h" /* Metadata cache */
37 #include "H5Eprivate.h" /* Error handling */
38 #include "H5FSpkg.h" /* File free space */
39 #include "H5MFprivate.h" /* File memory management */
40
41 /****************/
42 /* Local Macros */
43 /****************/
44
45
46 /******************/
47 /* Local Typedefs */
48 /******************/
49
50
51 /********************/
52 /* Package Typedefs */
53 /********************/
54
55
56 /********************/
57 /* Local Prototypes */
58 /********************/
59
60 /* Section info routines */
61 static herr_t H5FS_sinfo_free_sect_cb(void *item, void *key, void *op_data);
62 static herr_t H5FS_sinfo_free_node_cb(void *item, void *key, void *op_data);
63
64
65 /*********************/
66 /* Package Variables */
67 /*********************/
68
69 /* Declare a free list to manage the H5FS_section_class_t sequence information */
70 H5FL_SEQ_DEFINE(H5FS_section_class_t);
71
72 /* Declare a free list to manage the H5FS_t struct */
73 H5FL_DEFINE(H5FS_t);
74
75
76 /*****************************/
77 /* Library Private Variables */
78 /*****************************/
79
80
81 /*******************/
82 /* Local Variables */
83 /*******************/
84
85
86
87 /*-------------------------------------------------------------------------
88 * Function: H5FS_create
89 *
90 * Purpose: Allocate & initialize file free space info
91 *
92 * Return: Success: Pointer to free space structure
93 *
94 * Failure: NULL
95 *
96 * Programmer: Quincey Koziol
97 * Tuesday, March 7, 2006
98 *
99 * Modifications:
100 * Vailin Choi, July 29th, 2008
101 * Add two more parameters for handling alignment: alignment & threshhold
102 *
103 *-------------------------------------------------------------------------
104 */
105 H5FS_t *
H5FS_create(H5F_t * f,hid_t dxpl_id,haddr_t * fs_addr,const H5FS_create_t * fs_create,size_t nclasses,const H5FS_section_class_t * classes[],void * cls_init_udata,hsize_t alignment,hsize_t threshold)106 H5FS_create(H5F_t *f, hid_t dxpl_id, haddr_t *fs_addr, const H5FS_create_t *fs_create,
107 size_t nclasses, const H5FS_section_class_t *classes[], void *cls_init_udata, hsize_t alignment, hsize_t threshold)
108 {
109 H5FS_t *fspace = NULL; /* New free space structure */
110 H5FS_t *ret_value; /* Return value */
111
112 FUNC_ENTER_NOAPI(NULL)
113 #ifdef H5FS_DEBUG
114 HDfprintf(stderr, "%s: Creating free space manager, nclasses = %Zu\n", FUNC, nclasses);
115 #endif /* H5FS_DEBUG */
116
117 /* Check arguments. */
118 HDassert(fs_create->shrink_percent);
119 HDassert(fs_create->shrink_percent < fs_create->expand_percent);
120 HDassert(fs_create->max_sect_size);
121 HDassert(nclasses == 0 || classes);
122
123 /*
124 * Allocate free space structure
125 */
126 if(NULL == (fspace = H5FS_new(f, nclasses, classes, cls_init_udata)))
127 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space free list")
128
129 /* Initialize creation information for free space manager */
130 fspace->client = fs_create->client;
131 fspace->shrink_percent = fs_create->shrink_percent;
132 fspace->expand_percent = fs_create->expand_percent;
133 fspace->max_sect_addr = fs_create->max_sect_addr;
134 fspace->max_sect_size = fs_create->max_sect_size;
135
136 fspace->alignment = alignment;
137 fspace->threshold = threshold;
138
139 /* Check if the free space tracker is supposed to be persistant */
140 if(fs_addr) {
141 /* Allocate space for the free space header */
142 if(HADDR_UNDEF == (fspace->addr = H5MF_alloc(f, H5FD_MEM_FSPACE_HDR, dxpl_id, (hsize_t)fspace->hdr_size)))
143 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "file allocation failed for free space header")
144
145 /* Cache the new free space header (pinned) */
146 if(H5AC_insert_entry(f, dxpl_id, H5AC_FSPACE_HDR, fspace->addr, fspace, H5AC__PIN_ENTRY_FLAG) < 0)
147 HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, NULL, "can't add free space header to cache")
148
149 /* Return free space header address to caller, if desired */
150 *fs_addr = fspace->addr;
151 } /* end if */
152
153 /* Set the reference count to 1, since we inserted the entry in the cache pinned */
154 fspace->rc = 1;
155
156 /* Set the return value */
157 ret_value = fspace;
158 #ifdef H5FS_DEBUG
159 HDfprintf(stderr, "%s: fspace = %p, fspace->addr = %a\n", FUNC, fspace, fspace->addr);
160 #endif /* H5FS_DEBUG */
161
162 done:
163 if(!ret_value && fspace)
164 if(H5FS_hdr_dest(fspace) < 0)
165 HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, NULL, "unable to destroy free space header")
166
167 #ifdef H5FS_DEBUG
168 HDfprintf(stderr, "%s: Leaving, ret_value = %d\n", FUNC, ret_value);
169 #endif /* H5FS_DEBUG */
170 FUNC_LEAVE_NOAPI(ret_value)
171 } /* H5FS_create() */
172
173
174 /*-------------------------------------------------------------------------
175 * Function: H5FS_open
176 *
177 * Purpose: Open an existing file free space info structure on disk
178 *
179 * Return: Success: Pointer to free space structure
180 *
181 * Failure: NULL
182 *
183 * Programmer: Quincey Koziol
184 * Tuesday, May 2, 2006
185 *
186 * Modfications:
187 *
188 * Vailin Choi, July 29th, 2008
189 * Add two more parameters for handling alignment: alignment & threshhold
190 *
191 *-------------------------------------------------------------------------
192 */
193 H5FS_t *
H5FS_open(H5F_t * f,hid_t dxpl_id,haddr_t fs_addr,size_t nclasses,const H5FS_section_class_t * classes[],void * cls_init_udata,hsize_t alignment,hsize_t threshold)194 H5FS_open(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr, size_t nclasses,
195 const H5FS_section_class_t *classes[], void *cls_init_udata, hsize_t alignment, hsize_t threshold)
196 {
197 H5FS_t *fspace = NULL; /* New free space structure */
198 H5FS_hdr_cache_ud_t cache_udata; /* User-data for metadata cache callback */
199 H5FS_t *ret_value; /* Return value */
200
201 FUNC_ENTER_NOAPI(NULL)
202 #ifdef H5FS_DEBUG
203 HDfprintf(stderr, "%s: Opening free space manager, fs_addr = %a, nclasses = %Zu\n", FUNC, fs_addr, nclasses);
204 #endif /* H5FS_DEBUG */
205
206 /* Check arguments. */
207 HDassert(H5F_addr_defined(fs_addr));
208 HDassert(nclasses);
209 HDassert(classes);
210
211 /* Initialize user data for protecting the free space manager */
212 cache_udata.f = f;
213 cache_udata.nclasses = nclasses;
214 cache_udata.classes = classes;
215 cache_udata.cls_init_udata = cls_init_udata;
216 cache_udata.addr = fs_addr;
217
218 /* Protect the free space header */
219 if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC_READ)))
220 HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, NULL, "unable to load free space header")
221 #ifdef H5FS_DEBUG
222 HDfprintf(stderr, "%s: fspace->sect_addr = %a\n", FUNC, fspace->sect_addr);
223 HDfprintf(stderr, "%s: fspace->sect_size = %Hu\n", FUNC, fspace->sect_size);
224 HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu\n", FUNC, fspace->alloc_sect_size);
225 HDfprintf(stderr, "%s: fspace->sinfo = %p\n", FUNC, fspace->sinfo);
226 HDfprintf(stderr, "%s: fspace->rc = %u\n", FUNC, fspace->rc);
227 #endif /* H5FS_DEBUG */
228
229 /* Increment the reference count on the free space manager header */
230 HDassert(fspace->rc <= 1);
231 if(H5FS_incr(fspace) < 0)
232 HGOTO_ERROR(H5E_FSPACE, H5E_CANTINC, NULL, "unable to increment ref. count on free space header")
233
234 fspace->alignment = alignment;
235 fspace->threshold = threshold;
236
237 /* Unlock free space header */
238 if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, fspace, H5AC__NO_FLAGS_SET) < 0)
239 HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, NULL, "unable to release free space header")
240
241 /* Set return value */
242 ret_value = fspace;
243
244 done:
245 FUNC_LEAVE_NOAPI(ret_value)
246 } /* H5FS_open() */
247
248
249 /*-------------------------------------------------------------------------
250 * Function: H5FS_delete
251 *
252 * Purpose: Delete a free space manager on disk
253 *
254 * Return: Success: non-negative
255 *
256 * Failure: negative
257 *
258 * Programmer: Quincey Koziol
259 * Tuesday, May 30, 2006
260 *
261 *-------------------------------------------------------------------------
262 */
263 herr_t
H5FS_delete(H5F_t * f,hid_t dxpl_id,haddr_t fs_addr)264 H5FS_delete(H5F_t *f, hid_t dxpl_id, haddr_t fs_addr)
265 {
266 H5FS_t *fspace = NULL; /* Free space header loaded from file */
267 H5FS_hdr_cache_ud_t cache_udata; /* User-data for metadata cache callback */
268 herr_t ret_value = SUCCEED; /* Return value */
269
270 FUNC_ENTER_NOAPI(FAIL)
271 #ifdef H5FS_DEBUG
272 HDfprintf(stderr, "%s: Deleting free space manager, fs_addr = %a\n", FUNC, fs_addr);
273 #endif /* H5FS_DEBUG */
274
275 /* Check arguments. */
276 HDassert(f);
277 HDassert(H5F_addr_defined(fs_addr));
278
279 /* Initialize user data for protecting the free space manager */
280 /* (no class information necessary for delete) */
281 cache_udata.f = f;
282 cache_udata.nclasses = 0;
283 cache_udata.classes = NULL;
284 cache_udata.cls_init_udata = NULL;
285 cache_udata.addr = fs_addr;
286
287 /* Protect the free space header */
288 if(NULL == (fspace = (H5FS_t *)H5AC_protect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, &cache_udata, H5AC_WRITE)))
289 HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, FAIL, "unable to protect free space header")
290
291 /* Sanity check */
292 HDassert(fspace->sinfo == NULL);
293
294 /* Delete serialized section storage, if there are any */
295 #ifdef H5FS_DEBUG
296 HDfprintf(stderr, "%s: fspace->sect_addr = %a\n", FUNC, fspace->sect_addr);
297 #endif /* H5FS_DEBUG */
298 if(fspace->serial_sect_count > 0) {
299 unsigned sinfo_status = 0; /* Free space section info's status in the metadata cache */
300
301 /* Sanity check */
302 HDassert(H5F_addr_defined(fspace->sect_addr));
303 HDassert(fspace->alloc_sect_size > 0);
304
305 /* Check the free space section info's status in the metadata cache */
306 if(H5AC_get_entry_status(f, fspace->sect_addr, &sinfo_status) < 0)
307 HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "unable to check metadata cache status for free space section info")
308
309 /* If the free space section info is in the cache, expunge it now */
310 if(sinfo_status & H5AC_ES__IN_CACHE) {
311 /* Sanity checks on direct block */
312 HDassert(!(sinfo_status & H5AC_ES__IS_PINNED));
313 HDassert(!(sinfo_status & H5AC_ES__IS_PROTECTED));
314
315 #ifdef H5FS_DEBUG
316 HDfprintf(stderr, "%s: Expunging free space section info from cache\n", FUNC);
317 #endif /* H5FS_DEBUG */
318 /* Evict the free space section info from the metadata cache */
319 /* (Free file space) */
320 if(H5AC_expunge_entry(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, H5AC__FREE_FILE_SPACE_FLAG) < 0)
321 HGOTO_ERROR(H5E_HEAP, H5E_CANTREMOVE, FAIL, "unable to remove free space section info from cache")
322 #ifdef H5FS_DEBUG
323 HDfprintf(stderr, "%s: Done expunging free space section info from cache\n", FUNC);
324 #endif /* H5FS_DEBUG */
325 } /* end if */
326 else {
327 /* Release the space in the file */
328 if(H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_addr, fspace->alloc_sect_size) < 0)
329 HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to release free space sections")
330 } /* end else */
331 } /* end if */
332
333 done:
334 if(fspace && H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_HDR, fs_addr, fspace, H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
335 HDONE_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, FAIL, "unable to release free space header")
336
337 FUNC_LEAVE_NOAPI(ret_value)
338 } /* H5FS_delete() */
339
340
341 /*-------------------------------------------------------------------------
342 * Function: H5FS_close
343 *
344 * Purpose: Destroy & deallocate free list structure, serializing sections
345 * in the bins
346 *
347 * Return: Success: non-negative
348 *
349 * Failure: negative
350 *
351 * Programmer: Quincey Koziol
352 * Tuesday, March 7, 2006
353 *
354 *-------------------------------------------------------------------------
355 */
356 herr_t
H5FS_close(H5F_t * f,hid_t dxpl_id,H5FS_t * fspace)357 H5FS_close(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace)
358 {
359 herr_t ret_value = SUCCEED; /* Return value */
360
361 FUNC_ENTER_NOAPI(FAIL)
362
363 /* Check arguments. */
364 HDassert(f);
365 HDassert(fspace);
366 #ifdef H5FS_DEBUG
367 HDfprintf(stderr, "%s: Entering, fspace = %p, fspace->addr = %a, fspace->sinfo = %p\n", FUNC, fspace, fspace->addr, fspace->sinfo);
368 #endif /* H5FS_DEBUG */
369
370 /* Check if section info is valid */
371 /* (i.e. the header "owns" the section info and it's not in the cache) */
372 if(fspace->sinfo) {
373 #ifdef H5FS_DEBUG
374 HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu, fspace->serial_sect_count = %Hu, fspace->sect_addr = %a, fspace->rc = %u\n", FUNC, fspace->tot_sect_count, fspace->serial_sect_count, fspace->sect_addr, fspace->rc);
375 HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu, fspace->sect_size = %Hu\n", FUNC, fspace->alloc_sect_size, fspace->sect_size);
376 #endif /* H5FS_DEBUG */
377 /* If there are sections to serialize, update them */
378 /* (if the free space manager is persistant) */
379 if(fspace->serial_sect_count > 0 && H5F_addr_defined(fspace->addr)) {
380 #ifdef H5FS_DEBUG
381 HDfprintf(stderr, "%s: Real sections to store in file\n", FUNC);
382 #endif /* H5FS_DEBUG */
383 if(fspace->sinfo->dirty) {
384 /* Check if the section info is "floating" */
385 if(!H5F_addr_defined(fspace->sect_addr)) {
386 /* Sanity check */
387 HDassert(fspace->sect_size > 0);
388
389 /* Allocate space for the section info in file */
390 if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_size)))
391 HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections")
392 fspace->alloc_sect_size = (size_t)fspace->sect_size;
393
394 /* Mark free space header as dirty */
395 if(H5AC_mark_entry_dirty(fspace) < 0)
396 HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
397 } /* end if */
398 } /* end if */
399 else
400 /* Sanity check that section info has address */
401 HDassert(H5F_addr_defined(fspace->sect_addr));
402
403 /* Cache the free space section info */
404 if(H5AC_insert_entry(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo, H5AC__NO_FLAGS_SET) < 0)
405 HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sections to cache")
406 } /* end if */
407 else {
408 #ifdef H5FS_DEBUG
409 HDfprintf(stderr, "%s: NOT storing section info in file\n", FUNC);
410 #endif /* H5FS_DEBUG */
411 /* Check if space for the section info is allocated */
412 if(H5F_addr_defined(fspace->sect_addr)) {
413 /* Sanity check */
414 /* (section info should only be in the file if the header is */
415 HDassert(H5F_addr_defined(fspace->addr));
416
417 #ifdef H5FS_DEBUG
418 HDfprintf(stderr, "%s: Section info allocated though\n", FUNC);
419 #endif /* H5FS_DEBUG */
420 /* Check if the section info is for the free space in the file */
421 /* (NOTE: This is the "bootstrapping" special case for the
422 * free space manager, to avoid freeing the space for the
423 * section info and re-creating it as a section in the
424 * manager. -QAK)
425 */
426 if(fspace->client == H5FS_CLIENT_FILE_ID) {
427 htri_t status; /* "can absorb" status for section into */
428
429 #ifdef H5FS_DEBUG
430 HDfprintf(stderr, "%s: Section info is for file free space\n", FUNC);
431 #endif /* H5FS_DEBUG */
432 /* Try to shrink the file or absorb the section info into a block aggregator */
433 if((status = H5MF_try_shrink(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->sect_addr, fspace->alloc_sect_size)) < 0)
434 HGOTO_ERROR(H5E_FSPACE, H5E_CANTMERGE, FAIL, "can't check for absorbing section info")
435 else if(status == FALSE) {
436 /* Section info can't "go away", but it's free. Allow
437 * header to record it
438 */
439 #ifdef H5FS_DEBUG
440 HDfprintf(stderr, "%s: Section info can't 'go away', header will own it\n", FUNC);
441 #endif /* H5FS_DEBUG */
442 } /* end if */
443 else {
444 #ifdef H5FS_DEBUG
445 HDfprintf(stderr, "%s: Section info went 'go away'\n", FUNC);
446 #endif /* H5FS_DEBUG */
447 /* Reset section info in header */
448 fspace->sect_addr = HADDR_UNDEF;
449 fspace->alloc_sect_size = 0;
450
451 /* Mark free space header as dirty */
452 if(H5AC_mark_entry_dirty(fspace) < 0)
453 HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
454 } /* end else */
455 } /* end if */
456 else {
457 haddr_t old_sect_addr = fspace->sect_addr; /* Previous location of section info in file */
458 hsize_t old_alloc_sect_size = fspace->alloc_sect_size; /* Previous size of section info in file */
459
460 #ifdef H5FS_DEBUG
461 HDfprintf(stderr, "%s: Section info is NOT for file free space\n", FUNC);
462 #endif /* H5FS_DEBUG */
463 /* Reset section info in header */
464 fspace->sect_addr = HADDR_UNDEF;
465 fspace->alloc_sect_size = 0;
466
467 /* Mark free space header as dirty */
468 if(H5AC_mark_entry_dirty(fspace) < 0)
469 HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
470
471 /* Free previous serialized sections disk space */
472 if(H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, old_sect_addr, old_alloc_sect_size) < 0)
473 HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections")
474 } /* end if */
475 } /* end else */
476
477 /* Destroy section info */
478 if(H5FS_sinfo_dest(fspace->sinfo) < 0)
479 HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "unable to destroy free space section info")
480 } /* end else */
481
482 /* Reset the header's pointer to the section info */
483 fspace->sinfo = NULL;
484 } /* end if */
485 else {
486 /* Just sanity checks... */
487 if(fspace->serial_sect_count > 0)
488 /* Sanity check that section info has address */
489 HDassert(H5F_addr_defined(fspace->sect_addr));
490 else
491 /* Sanity check that section info doesn't have address */
492 HDassert(!H5F_addr_defined(fspace->sect_addr));
493 } /* end else */
494
495 /* Decrement the reference count on the free space manager header */
496 if(H5FS_decr(fspace) < 0)
497 HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEC, FAIL, "unable to decrement ref. count on free space header")
498
499 done:
500 #ifdef H5FS_DEBUG
501 HDfprintf(stderr, "%s: Leaving, ret_value = %d, fspace->rc = %u\n", FUNC, ret_value, fspace->rc);
502 #endif /* H5FS_DEBUG */
503 FUNC_LEAVE_NOAPI(ret_value)
504 } /* H5FS_close() */
505
506
507 /*-------------------------------------------------------------------------
508 * Function: H5FS_new
509 *
510 * Purpose: Create new free space manager structure
511 *
512 * Return: Success: non-NULL, pointer to new free space manager struct
513 * Failure: NULL
514 *
515 * Programmer: Quincey Koziol
516 * Monday, July 31, 2006
517 *
518 *-------------------------------------------------------------------------
519 */
520 H5FS_t *
H5FS_new(const H5F_t * f,size_t nclasses,const H5FS_section_class_t * classes[],void * cls_init_udata)521 H5FS_new(const H5F_t *f, size_t nclasses, const H5FS_section_class_t *classes[],
522 void *cls_init_udata)
523 {
524 H5FS_t *fspace = NULL; /* Free space manager */
525 size_t u; /* Local index variable */
526 H5FS_t *ret_value; /* Return value */
527
528 FUNC_ENTER_NOAPI_NOINIT
529
530 /* Check arguments. */
531 HDassert(nclasses == 0 || (nclasses > 0 && classes));
532
533 /*
534 * Allocate free space structure
535 */
536 if(NULL == (fspace = H5FL_CALLOC(H5FS_t)))
537 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space free list")
538
539 /* Set immutable free list parameters */
540 fspace->nclasses = nclasses;
541 if(nclasses > 0) {
542 if(NULL == (fspace->sect_cls = H5FL_SEQ_MALLOC(H5FS_section_class_t, nclasses)))
543 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for free space section class array")
544
545 /* Initialize the section classes for this free space list */
546 for(u = 0; u < nclasses; u++) {
547 /* Make certain that section class type can be used as an array index into this array */
548 HDassert(u == classes[u]->type);
549
550 /* Copy the class information into the free space manager */
551 HDmemcpy(&fspace->sect_cls[u], classes[u], sizeof(H5FS_section_class_t));
552
553 /* Call the class initialization routine, if there is one */
554 if(fspace->sect_cls[u].init_cls)
555 if((fspace->sect_cls[u].init_cls)(&fspace->sect_cls[u], cls_init_udata) < 0)
556 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "unable to initialize section class")
557
558 /* Determine maximum class-specific serialization size for each section */
559 if(fspace->sect_cls[u].serial_size > fspace->max_cls_serial_size)
560 fspace->max_cls_serial_size = fspace->sect_cls[u].serial_size;
561 } /* end for */
562 } /* end if */
563
564 /* Initialize non-zero information for new free space manager */
565 fspace->addr = HADDR_UNDEF;
566 fspace->hdr_size = H5FS_HEADER_SIZE(f);
567 fspace->sect_addr = HADDR_UNDEF;
568
569 /* Set return value */
570 ret_value = fspace;
571
572 done:
573 if(!ret_value)
574 if(fspace) {
575 /* Should probably call the class 'term' callback for all classes
576 * that have had their 'init' callback called... -QAK
577 */
578 if(fspace->sect_cls)
579 fspace->sect_cls = (H5FS_section_class_t *)H5FL_SEQ_FREE(H5FS_section_class_t, fspace->sect_cls);
580 fspace = H5FL_FREE(H5FS_t, fspace);
581 } /* end if */
582
583 FUNC_LEAVE_NOAPI(ret_value)
584 } /* H5FS_new() */
585
586
587 /*-------------------------------------------------------------------------
588 * Function: H5FS_size
589 *
590 * Purpose: Collect meta storage info used by the free space manager
591 *
592 * Return: Success: non-negative
593 * Failure: negative
594 *
595 * Programmer: Vailin Choi
596 * June 19, 2007
597 *
598 *-------------------------------------------------------------------------
599 */
600 herr_t
H5FS_size(const H5F_t * f,const H5FS_t * fspace,hsize_t * meta_size)601 H5FS_size(const H5F_t *f, const H5FS_t *fspace, hsize_t *meta_size)
602 {
603 FUNC_ENTER_NOAPI_NOINIT_NOERR
604
605 /*
606 * Check arguments.
607 */
608 HDassert(f);
609 HDassert(fspace);
610 HDassert(meta_size);
611
612 /* Get the free space size info */
613 *meta_size += fspace->hdr_size + (fspace->sinfo ? fspace->sect_size : fspace->alloc_sect_size);
614
615 FUNC_LEAVE_NOAPI(SUCCEED)
616 } /* end H5FS_size() */
617
618
619 /*-------------------------------------------------------------------------
620 * Function: H5FS_incr
621 *
622 * Purpose: Increment reference count on free space header
623 *
624 * Return: Success: non-negative
625 * Failure: negative
626 *
627 * Programmer: Quincey Koziol
628 * February 7, 2008
629 *
630 *-------------------------------------------------------------------------
631 */
632 herr_t
H5FS_incr(H5FS_t * fspace)633 H5FS_incr(H5FS_t *fspace)
634 {
635 herr_t ret_value = SUCCEED; /* Return value */
636
637 FUNC_ENTER_NOAPI(FAIL)
638 #ifdef H5FS_DEBUG
639 HDfprintf(stderr, "%s: Entering, fpace->addr = %a, fspace->rc = %u\n", FUNC, fspace->addr, fspace->rc);
640 #endif /* H5FS_DEBUG */
641
642 /*
643 * Check arguments.
644 */
645 HDassert(fspace);
646
647 /* Check if we should pin the header in the cache */
648 if(fspace->rc == 0 && H5F_addr_defined(fspace->addr))
649 if(H5AC_pin_protected_entry(fspace) < 0)
650 HGOTO_ERROR(H5E_FSPACE, H5E_CANTPIN, FAIL, "unable to pin free space header")
651
652 /* Increment reference count on header */
653 fspace->rc++;
654
655 done:
656 FUNC_LEAVE_NOAPI(ret_value)
657 } /* end H5FS_incr() */
658
659
660 /*-------------------------------------------------------------------------
661 * Function: H5FS_decr
662 *
663 * Purpose: Decrement reference count on free space header
664 *
665 * Return: Success: non-negative
666 * Failure: negative
667 *
668 * Programmer: Quincey Koziol
669 * February 7, 2008
670 *
671 *-------------------------------------------------------------------------
672 */
673 herr_t
H5FS_decr(H5FS_t * fspace)674 H5FS_decr(H5FS_t *fspace)
675 {
676 herr_t ret_value = SUCCEED; /* Return value */
677
678 FUNC_ENTER_NOAPI(FAIL)
679 #ifdef H5FS_DEBUG
680 HDfprintf(stderr, "%s: Entering, fpace->addr = %a, fspace->rc = %u\n", FUNC, fspace->addr, fspace->rc);
681 #endif /* H5FS_DEBUG */
682
683 /*
684 * Check arguments.
685 */
686 HDassert(fspace);
687
688 /* Decrement reference count on header */
689 fspace->rc--;
690
691 /* Check if we should unpin the header in the cache */
692 if(fspace->rc == 0) {
693 if(H5F_addr_defined(fspace->addr)) {
694 if(H5AC_unpin_entry(fspace) < 0)
695 HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPIN, FAIL, "unable to unpin free space header")
696 } /* end if */
697 else {
698 if(H5FS_hdr_dest(fspace) < 0)
699 HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "unable to destroy free space header")
700 } /* end else */
701 } /* end if */
702
703 done:
704 FUNC_LEAVE_NOAPI(ret_value)
705 } /* end H5FS_decr() */
706
707
708 /*-------------------------------------------------------------------------
709 * Function: H5FS_dirty
710 *
711 * Purpose: Mark free space header as dirty
712 *
713 * Return: Non-negative on success/Negative on failure
714 *
715 * Programmer: Quincey Koziol
716 * koziol@hdfgroup.org
717 * Feb 14 2008
718 *
719 *-------------------------------------------------------------------------
720 */
721 herr_t
H5FS_dirty(H5FS_t * fspace)722 H5FS_dirty(H5FS_t *fspace)
723 {
724 herr_t ret_value = SUCCEED; /* Return value */
725
726 FUNC_ENTER_NOAPI_NOINIT
727 #ifdef QAK
728 HDfprintf(stderr, "%s: Marking free space header as dirty\n", FUNC);
729 #endif /* QAK */
730
731 /* Sanity check */
732 HDassert(fspace);
733
734 /* Check if the free space manager is persistant */
735 if(H5F_addr_defined(fspace->addr))
736 /* Mark header as dirty in cache */
737 if(H5AC_mark_entry_dirty(fspace) < 0)
738 HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
739
740 done:
741 FUNC_LEAVE_NOAPI(ret_value)
742 } /* end H5FS_dirty() */
743
744
745 /*-------------------------------------------------------------------------
746 * Function: H5FS_hdr_dest
747 *
748 * Purpose: Destroys a free space header in memory.
749 *
750 * Return: Non-negative on success/Negative on failure
751 *
752 * Programmer: Quincey Koziol
753 * koziol@ncsa.uiuc.edu
754 * May 2 2006
755 *
756 *-------------------------------------------------------------------------
757 */
758 herr_t
H5FS_hdr_dest(H5FS_t * fspace)759 H5FS_hdr_dest(H5FS_t *fspace)
760 {
761 unsigned u; /* Local index variable */
762 herr_t ret_value = SUCCEED; /* Return value */
763
764 FUNC_ENTER_NOAPI_NOINIT
765
766 /*
767 * Check arguments.
768 */
769 HDassert(fspace);
770
771 /* Terminate the section classes for this free space list */
772 for(u = 0; u < fspace->nclasses ; u++) {
773 /* Call the class termination routine, if there is one */
774 if(fspace->sect_cls[u].term_cls)
775 if((fspace->sect_cls[u].term_cls)(&fspace->sect_cls[u]) < 0)
776 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "unable to finalize section class")
777 } /* end for */
778
779 /* Release the memory for the free space section classes */
780 if(fspace->sect_cls)
781 fspace->sect_cls = (H5FS_section_class_t *)H5FL_SEQ_FREE(H5FS_section_class_t, fspace->sect_cls);
782
783 /* Free free space info */
784 fspace = H5FL_FREE(H5FS_t, fspace);
785
786 done:
787 FUNC_LEAVE_NOAPI(ret_value)
788 } /* end H5FS_hdr_dest() */
789
790
791 /*-------------------------------------------------------------------------
792 * Function: H5FS_sinfo_free_sect_cb
793 *
794 * Purpose: Free a size-tracking node for a bin
795 *
796 * Return: Success: non-negative
797 * Failure: negative
798 *
799 * Programmer: Quincey Koziol
800 * Saturday, March 11, 2006
801 *
802 *-------------------------------------------------------------------------
803 */
804 static herr_t
H5FS_sinfo_free_sect_cb(void * _sect,void UNUSED * key,void * op_data)805 H5FS_sinfo_free_sect_cb(void *_sect, void UNUSED *key, void *op_data)
806 {
807 H5FS_section_info_t *sect = (H5FS_section_info_t *)_sect; /* Section to free */
808 const H5FS_sinfo_t *sinfo = (const H5FS_sinfo_t *)op_data; /* Free space manager for section */
809
810 FUNC_ENTER_NOAPI_NOINIT_NOERR
811
812 HDassert(sect);
813 HDassert(sinfo);
814
815 /* Call the section's class 'free' method on the section */
816 (*sinfo->fspace->sect_cls[sect->type].free)(sect);
817
818 FUNC_LEAVE_NOAPI(0)
819 } /* H5FS_sinfo_free_sect_cb() */
820
821
822 /*-------------------------------------------------------------------------
823 * Function: H5FS_sinfo_free_node_cb
824 *
825 * Purpose: Free a size-tracking node for a bin
826 *
827 * Return: Success: non-negative
828 *
829 * Failure: negative
830 *
831 * Programmer: Quincey Koziol
832 * Saturday, March 11, 2006
833 *
834 *-------------------------------------------------------------------------
835 */
836 static herr_t
H5FS_sinfo_free_node_cb(void * item,void UNUSED * key,void * op_data)837 H5FS_sinfo_free_node_cb(void *item, void UNUSED *key, void *op_data)
838 {
839 H5FS_node_t *fspace_node = (H5FS_node_t *)item; /* Temporary pointer to free space list node */
840
841 FUNC_ENTER_NOAPI_NOINIT_NOERR
842
843 HDassert(fspace_node);
844 HDassert(op_data);
845
846 /* Release the skip list for sections of this size */
847 H5SL_destroy(fspace_node->sect_list, H5FS_sinfo_free_sect_cb, op_data);
848
849 /* Release free space list node */
850 fspace_node = H5FL_FREE(H5FS_node_t, fspace_node);
851
852 FUNC_LEAVE_NOAPI(0)
853 } /* H5FS_sinfo_free_node_cb() */
854
855
856 /*-------------------------------------------------------------------------
857 * Function: H5FS_sinfo_dest
858 *
859 * Purpose: Destroys a free space section info in memory.
860 *
861 * Return: Non-negative on success/Negative on failure
862 *
863 * Programmer: Quincey Koziol
864 * koziol@ncsa.uiuc.edu
865 * July 31 2006
866 *
867 *-------------------------------------------------------------------------
868 */
869 herr_t
H5FS_sinfo_dest(H5FS_sinfo_t * sinfo)870 H5FS_sinfo_dest(H5FS_sinfo_t *sinfo)
871 {
872 unsigned u; /* Local index variable */
873 herr_t ret_value = SUCCEED; /* Return value */
874
875 FUNC_ENTER_NOAPI_NOINIT
876
877 /*
878 * Check arguments.
879 */
880 HDassert(sinfo);
881 HDassert(sinfo->fspace);
882 HDassert(sinfo->bins);
883
884 /* Clear out lists of nodes */
885 for(u = 0; u < sinfo->nbins; u++)
886 if(sinfo->bins[u].bin_list) {
887 H5SL_destroy(sinfo->bins[u].bin_list, H5FS_sinfo_free_node_cb, sinfo);
888 sinfo->bins[u].bin_list = NULL;
889 } /* end if */
890
891 /* Release bins for skip lists */
892 sinfo->bins = H5FL_SEQ_FREE(H5FS_bin_t, sinfo->bins);
893
894 /* Release skip list for merging sections */
895 if(sinfo->merge_list)
896 if(H5SL_close(sinfo->merge_list) < 0)
897 HGOTO_ERROR(H5E_FSPACE, H5E_CANTCLOSEOBJ, FAIL, "can't destroy section merging skip list")
898
899 /* Decrement the reference count on free space header */
900 /* (make certain this is last action with section info, to allow for header
901 * disappearing immediately)
902 */
903 sinfo->fspace->sinfo = NULL;
904 if(H5FS_decr(sinfo->fspace) < 0)
905 HGOTO_ERROR(H5E_FSPACE, H5E_CANTDEC, FAIL, "unable to decrement ref. count on free space header")
906 sinfo->fspace = NULL;
907
908 /* Release free space section info */
909 sinfo = H5FL_FREE(H5FS_sinfo_t, sinfo);
910
911 done:
912 FUNC_LEAVE_NOAPI(ret_value)
913 } /* end H5FS_sinfo_dest() */
914
915 #ifdef H5FS_DEBUG_ASSERT
916
917 /*-------------------------------------------------------------------------
918 * Function: H5FS_assert
919 *
920 * Purpose: Verify that the free space manager is mostly sane
921 *
922 * Return: Non-negative on success, negative on failure
923 *
924 * Programmer: Quincey Koziol
925 * koziol@hdfgroup.org
926 * Jul 17 2006
927 *
928 *-------------------------------------------------------------------------
929 */
930 herr_t
H5FS_assert(const H5FS_t * fspace)931 H5FS_assert(const H5FS_t *fspace)
932 {
933 FUNC_ENTER_NOAPI_NOINIT_NOERR
934 #ifndef QAK
935 HDfprintf(stderr, "%s: fspace->tot_sect_count = %Hu\n", "H5FS_assert", fspace->tot_sect_count);
936 #endif /* QAK */
937
938 /* Checks for section info, if it's available */
939 if(fspace->sinfo) {
940 /* Sanity check sections */
941 H5FS_sect_assert(fspace);
942
943 /* General assumptions about the section size counts */
944 HDassert(fspace->sinfo->tot_size_count >= fspace->sinfo->serial_size_count);
945 HDassert(fspace->sinfo->tot_size_count >= fspace->sinfo->ghost_size_count);
946 } /* end if */
947
948 /* General assumptions about the section counts */
949 HDassert(fspace->tot_sect_count >= fspace->serial_sect_count);
950 HDassert(fspace->tot_sect_count >= fspace->ghost_sect_count);
951 HDassert(fspace->tot_sect_count == (fspace->serial_sect_count + fspace->ghost_sect_count));
952 #ifdef QAK
953 HDassert(fspace->serial_sect_count > 0 || fspace->ghost_sect_count == 0);
954 #endif /* QAK */
955
956 FUNC_LEAVE_NOAPI(SUCCEED)
957 } /* end H5FS_assert() */
958 #endif /* H5FS_DEBUG_ASSERT */
959