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 *
18 * Created: H5Oalloc.c
19 * Nov 17 2006
20 * Quincey Koziol <koziol@hdfgroup.org>
21 *
22 * Purpose: Object header allocation routines.
23 *
24 *-------------------------------------------------------------------------
25 */
26
27 /****************/
28 /* Module Setup */
29 /****************/
30
31 #define H5O_PACKAGE /*suppress error about including H5Opkg */
32
33 /***********/
34 /* Headers */
35 /***********/
36 #include "H5private.h" /* Generic Functions */
37 #include "H5Eprivate.h" /* Error handling */
38 #include "H5FLprivate.h" /* Free lists */
39 #include "H5MFprivate.h" /* File memory management */
40 #include "H5Opkg.h" /* Object headers */
41
42 /****************/
43 /* Local Macros */
44 /****************/
45
46
47 /******************/
48 /* Local Typedefs */
49 /******************/
50
51
52 /********************/
53 /* Package Typedefs */
54 /********************/
55
56
57 /********************/
58 /* Local Prototypes */
59 /********************/
60
61 static herr_t H5O_add_gap(H5F_t *f, H5O_t *oh, unsigned chunkno,
62 hbool_t *chk_dirtied, size_t idx, uint8_t *new_gap_loc, size_t new_gap_size);
63 static herr_t H5O_eliminate_gap(H5O_t *oh, hbool_t *chk_dirtied,
64 H5O_mesg_t *mesg, uint8_t *new_gap_loc, size_t new_gap_size);
65 static herr_t H5O_alloc_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t null_idx,
66 const H5O_msg_class_t *new_type, void *new_native, size_t new_size);
67 static htri_t H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
68 unsigned chunkno, size_t size, size_t *msg_idx);
69 static herr_t H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size,
70 size_t *new_idx);
71 static htri_t H5O_move_cont(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned cont_u);
72 static htri_t H5O_move_msgs_forward(H5F_t *f, hid_t dxpl_id, H5O_t *oh);
73 static htri_t H5O_merge_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh);
74 static htri_t H5O_remove_empty_chunks(H5F_t *f, hid_t dxpl_id, H5O_t *oh);
75 static herr_t H5O_alloc_shrink_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh,
76 unsigned chunkno);
77
78
79 /*********************/
80 /* Package Variables */
81 /*********************/
82
83 /* Declare extern the free list for H5O_cont_t's */
84 H5FL_EXTERN(H5O_cont_t);
85
86
87 /*****************************/
88 /* Library Private Variables */
89 /*****************************/
90
91
92 /*******************/
93 /* Local Variables */
94 /*******************/
95
96
97
98 /*-------------------------------------------------------------------------
99 * Function: H5O_add_gap
100 *
101 * Purpose: Add a gap to a chunk
102 *
103 * Return: Non-negative on success/Negative on failure
104 *
105 * Programmer: Quincey Koziol
106 * koziol@hdfgroup.org
107 * Oct 17 2006
108 *
109 *-------------------------------------------------------------------------
110 */
111 static herr_t
H5O_add_gap(H5F_t * f,H5O_t * oh,unsigned chunkno,hbool_t * chk_dirtied,size_t idx,uint8_t * new_gap_loc,size_t new_gap_size)112 H5O_add_gap(H5F_t *f, H5O_t *oh, unsigned chunkno, hbool_t *chk_dirtied,
113 size_t idx, uint8_t *new_gap_loc, size_t new_gap_size)
114 {
115 hbool_t merged_with_null; /* Whether the gap was merged with a null message */
116 size_t u; /* Local index variable */
117 herr_t ret_value = SUCCEED; /* Return value */
118
119 FUNC_ENTER_NOAPI_NOINIT
120
121 /* check args */
122 HDassert(oh);
123 HDassert(oh->version > H5O_VERSION_1);
124 HDassert(chk_dirtied);
125 HDassert(new_gap_loc);
126 HDassert(new_gap_size);
127
128 #ifndef NDEBUG
129 if(chunkno > 0) {
130 unsigned chk_proxy_status = 0; /* Object header chunk proxy entry cache status */
131
132 /* Check the object header chunk proxy's status in the metadata cache */
133 if(H5AC_get_entry_status(f, oh->chunk[chunkno].addr, &chk_proxy_status) < 0)
134 HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to check metadata cache status for object header chunk proxy")
135
136 /* Make certain that object header is protected */
137 HDassert(chk_proxy_status & H5AC_ES__IS_PROTECTED);
138 } /* end if */
139 #endif /* NDEBUG */
140
141 /* Check for existing null message in chunk */
142 merged_with_null = FALSE;
143 for(u = 0; u < oh->nmesgs && !merged_with_null; u++) {
144 /* Find a null message in the chunk with the new gap */
145 /* (a null message that's not the one we are eliminating) */
146 if(H5O_NULL_ID == oh->mesg[u].type->id && oh->mesg[u].chunkno == chunkno
147 && u != idx) {
148 /* Sanity check - chunks with null messages shouldn't have a gap */
149 HDassert(oh->chunk[chunkno].gap == 0);
150
151 /* Eliminate the gap in the chunk */
152 if(H5O_eliminate_gap(oh, chk_dirtied, &oh->mesg[u], new_gap_loc, new_gap_size) < 0)
153 HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't eliminate gap in chunk")
154
155 /* Set flag to indicate that the gap was handled */
156 merged_with_null = TRUE;
157 } /* end if */
158 } /* end for */
159
160 /* If we couldn't find a null message in the chunk, move the gap to the end */
161 if(!merged_with_null) {
162 /* Adjust message offsets after new gap forward in chunk */
163 for(u = 0; u < oh->nmesgs; u++)
164 if(oh->mesg[u].chunkno == chunkno && oh->mesg[u].raw > new_gap_loc)
165 oh->mesg[u].raw -= new_gap_size;
166
167 /* Slide raw message info forward in chunk image */
168 HDmemmove(new_gap_loc, new_gap_loc + new_gap_size,
169 (size_t)((oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh))) - (new_gap_loc + new_gap_size)));
170
171 /* Add existing gap size to new gap size */
172 new_gap_size += oh->chunk[chunkno].gap;
173
174 /* Merging with existing gap will allow for a new null message */
175 if(new_gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) {
176 H5O_mesg_t *null_msg; /* Pointer to new null message */
177
178 /* Check if we need to extend message table to hold the new null message */
179 if(oh->nmesgs >= oh->alloc_nmesgs)
180 if(H5O_alloc_msgs(oh, (size_t)1) < 0)
181 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
182
183 /* Increment new gap size */
184 oh->chunk[chunkno].gap += new_gap_size;
185
186 /* Create new null message, with the tail of the previous null message */
187 null_msg = &(oh->mesg[oh->nmesgs++]);
188 null_msg->type = H5O_MSG_NULL;
189 null_msg->native = NULL;
190 null_msg->raw_size = new_gap_size - (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
191 null_msg->raw = (oh->chunk[chunkno].image + oh->chunk[chunkno].size)
192 - (H5O_SIZEOF_CHKSUM_OH(oh) + null_msg->raw_size);
193 null_msg->chunkno = chunkno;
194
195 /* Zero out new null message's raw data */
196 if(null_msg->raw_size)
197 HDmemset(null_msg->raw, 0, null_msg->raw_size);
198
199 /* Mark message as dirty */
200 null_msg->dirty = TRUE;
201
202 /* Reset size of gap in chunk */
203 oh->chunk[chunkno].gap = 0;
204 } /* end if */
205 else
206 oh->chunk[chunkno].gap = new_gap_size;
207
208 /* Mark the chunk as modified */
209 *chk_dirtied = TRUE;
210 } /* end if */
211
212 done:
213 FUNC_LEAVE_NOAPI(ret_value)
214 } /* H5O_add_gap() */
215
216
217 /*-------------------------------------------------------------------------
218 * Function: H5O_eliminate_gap
219 *
220 * Purpose: Eliminate a gap in a chunk with a null message.
221 *
222 * Note: Sometimes this happens as a result of converting an existing
223 * non-null message to a null message, so we zero out the gap
224 * here, even though it might already be zero (when we're adding
225 * a gap to a chunk with an existing null message). (Mostly,
226 * this just simplifies the code, esp. with the necessary chunk
227 * locking -QAK)
228 *
229 * Return: Non-negative on success/Negative on failure
230 *
231 * Programmer: Quincey Koziol
232 * koziol@hdfgroup.org
233 * Oct 17 2006
234 *
235 *-------------------------------------------------------------------------
236 */
237 static herr_t
H5O_eliminate_gap(H5O_t * oh,hbool_t * chk_dirtied,H5O_mesg_t * mesg,uint8_t * gap_loc,size_t gap_size)238 H5O_eliminate_gap(H5O_t *oh, hbool_t *chk_dirtied, H5O_mesg_t *mesg,
239 uint8_t *gap_loc, size_t gap_size)
240 {
241 uint8_t *move_start, *move_end; /* Pointers to area of messages to move */
242 hbool_t null_before_gap; /* Flag whether the null message is before the gap or not */
243
244 FUNC_ENTER_NOAPI_NOINIT_NOERR
245
246 /* check args */
247 HDassert(oh);
248 HDassert(oh->version > H5O_VERSION_1);
249 HDassert(chk_dirtied);
250 HDassert(mesg);
251 HDassert(gap_loc);
252 HDassert(gap_size);
253
254 /* Check if the null message is before or after the gap produced */
255 null_before_gap = (hbool_t)(mesg->raw < gap_loc);
256
257 /* Set up information about region of messages to move */
258 if(null_before_gap) {
259 move_start = mesg->raw + mesg->raw_size;
260 move_end = gap_loc;
261 } /* end if */
262 else {
263 move_start = gap_loc + gap_size;
264 move_end = mesg->raw - H5O_SIZEOF_MSGHDR_OH(oh);
265 } /* end else */
266
267 /* Check for messages between null message and gap */
268 if(move_end > move_start) {
269 unsigned u; /* Local index variable */
270
271 /* Look for messages that need to move, to adjust raw pointers in chunk */
272 /* (this doesn't change the moved messages 'dirty' state) */
273 for(u = 0; u < oh->nmesgs; u++) {
274 uint8_t *msg_start; /* Start of encoded message in chunk */
275
276 msg_start = oh->mesg[u].raw - H5O_SIZEOF_MSGHDR_OH(oh);
277 if(oh->mesg[u].chunkno == mesg->chunkno
278 && (msg_start >= move_start && msg_start < move_end)) {
279 /* Move message's raw pointer in appropriate direction */
280 if(null_before_gap)
281 oh->mesg[u].raw += gap_size;
282 else
283 oh->mesg[u].raw -= gap_size;
284 } /* end if */
285 } /* end for */
286
287 /* Slide raw message info in chunk image */
288 if(null_before_gap)
289 /* Slide messages down */
290 HDmemmove(move_start + gap_size, move_start, (size_t)(move_end - move_start));
291 else {
292 /* Slide messages up */
293 HDmemmove(move_start - gap_size, move_start, (size_t)(move_end - move_start));
294
295 /* Adjust start of null message */
296 mesg->raw -= gap_size;
297 } /* end else */
298 }
299 else if(move_end == move_start && !null_before_gap) {
300 /* Slide null message up */
301 HDmemmove(move_start - gap_size, move_start, mesg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
302
303 /* Adjust start of null message */
304 mesg->raw -= gap_size;
305 } /* end if */
306
307 /* Zero out addition to null message */
308 HDmemset(mesg->raw + mesg->raw_size, 0, gap_size);
309
310 /* Adjust size of null message */
311 mesg->raw_size += gap_size;
312
313 /* Set the gap size to zero for the chunk */
314 oh->chunk[mesg->chunkno].gap = 0;
315
316 /* Mark null message as dirty */
317 mesg->dirty = TRUE;
318 *chk_dirtied = TRUE;
319
320 FUNC_LEAVE_NOAPI(SUCCEED)
321 } /* H5O_eliminate_gap() */
322
323
324 /*-------------------------------------------------------------------------
325 *
326 * Function: H5O_alloc_null
327 *
328 * Purpose: Allocate room for a new message from a null message
329 *
330 * Return: Non-negative on success/Negative on failure
331 *
332 * Programmer: Quincey Koziol
333 * koziol@hdfgroup.org
334 * Oct 22 2006
335 *
336 *-------------------------------------------------------------------------
337 */
338 static herr_t
H5O_alloc_null(H5F_t * f,hid_t dxpl_id,H5O_t * oh,size_t null_idx,const H5O_msg_class_t * new_type,void * new_native,size_t new_size)339 H5O_alloc_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t null_idx,
340 const H5O_msg_class_t *new_type, void *new_native, size_t new_size)
341 {
342 H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
343 hbool_t chk_dirtied = FALSE; /* Flags for unprotecting chunk */
344 H5O_mesg_t *alloc_msg; /* Pointer to null message to allocate out of */
345 herr_t ret_value = SUCCEED; /* Return value */
346
347 FUNC_ENTER_NOAPI_NOINIT
348
349 /* check args */
350 HDassert(oh);
351 HDassert(new_type);
352 HDassert(new_size);
353
354 /* Point to null message to allocate out of */
355 alloc_msg = &oh->mesg[null_idx];
356
357 /* Protect chunk */
358 if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, alloc_msg->chunkno)))
359 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
360
361 /* Check if there's a need to split the null message */
362 if(alloc_msg->raw_size > new_size) {
363 /* Check for producing a gap in the chunk */
364 if((alloc_msg->raw_size - new_size) < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) {
365 size_t gap_size = alloc_msg->raw_size - new_size; /* Size of gap produced */
366
367 /* Adjust the size of the null message being eliminated */
368 alloc_msg->raw_size = new_size;
369
370 /* Add the gap to the chunk */
371 if(H5O_add_gap(f, oh, alloc_msg->chunkno, &chk_dirtied, null_idx, alloc_msg->raw + alloc_msg->raw_size, gap_size) < 0)
372 HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk")
373 } /* end if */
374 else {
375 size_t new_mesg_size = new_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh); /* Total size of newly allocated message */
376 H5O_mesg_t *null_msg; /* Pointer to new null message */
377
378 /* Check if we need to extend message table to hold the new null message */
379 if(oh->nmesgs >= oh->alloc_nmesgs) {
380 if(H5O_alloc_msgs(oh, (size_t)1) < 0)
381 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
382
383 /* "Retarget" 'alloc_msg' pointer into newly re-allocated array of messages */
384 alloc_msg = &oh->mesg[null_idx];
385 } /* end if */
386
387 /* Create new null message, with the tail of the previous null message */
388 null_msg = &(oh->mesg[oh->nmesgs++]);
389 null_msg->type = H5O_MSG_NULL;
390 null_msg->native = NULL;
391 null_msg->raw = alloc_msg->raw + new_mesg_size;
392 null_msg->raw_size = alloc_msg->raw_size - new_mesg_size;
393 null_msg->chunkno = alloc_msg->chunkno;
394
395 /* Mark the message as dirty */
396 null_msg->dirty = TRUE;
397 chk_dirtied = TRUE;
398
399 /* Check for gap in new null message's chunk */
400 if(oh->chunk[null_msg->chunkno].gap > 0) {
401 unsigned null_chunkno = null_msg->chunkno; /* Chunk w/gap */
402
403 /* Eliminate the gap in the chunk */
404 if(H5O_eliminate_gap(oh, &chk_dirtied, null_msg,
405 ((oh->chunk[null_chunkno].image + oh->chunk[null_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[null_chunkno].gap)),
406 oh->chunk[null_chunkno].gap) < 0)
407 HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk")
408 } /* end if */
409
410 /* Set the size of the new "real" message */
411 alloc_msg->raw_size = new_size;
412 } /* end else */
413 } /* end if */
414
415 /* Initialize the new message */
416 alloc_msg->type = new_type;
417 alloc_msg->native = new_native;
418
419 /* Mark the new message as dirty */
420 alloc_msg->dirty = TRUE;
421 chk_dirtied = TRUE;
422
423 done:
424 /* Release chunk */
425 if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
426 HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
427
428 FUNC_LEAVE_NOAPI(ret_value)
429 } /* H5O_alloc_null() */
430
431
432 /*-------------------------------------------------------------------------
433 *
434 * Function: H5O_alloc_msgs
435 *
436 * Purpose: Allocate more messages for a header
437 *
438 * Return: Non-negative on success/Negative on failure
439 *
440 * Programmer: Quincey Koziol
441 * koziol@ncsa.uiuc.edu
442 * Nov 21 2005
443 *
444 *-------------------------------------------------------------------------
445 */
446 herr_t
H5O_alloc_msgs(H5O_t * oh,size_t min_alloc)447 H5O_alloc_msgs(H5O_t *oh, size_t min_alloc)
448 {
449 size_t old_alloc; /* Old number of messages allocated */
450 size_t na; /* New number of messages allocated */
451 H5O_mesg_t *new_mesg; /* Pointer to new message array */
452 herr_t ret_value = SUCCEED; /* Return value */
453
454 FUNC_ENTER_NOAPI_NOINIT
455
456 /* check args */
457 HDassert(oh);
458
459 /* Initialize number of messages information */
460 old_alloc = oh->alloc_nmesgs;
461 na = oh->alloc_nmesgs + MAX(oh->alloc_nmesgs, min_alloc); /* At least double */
462
463 /* Attempt to allocate more memory */
464 if(NULL == (new_mesg = H5FL_SEQ_REALLOC(H5O_mesg_t, oh->mesg, na)))
465 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
466
467 /* Update ohdr information */
468 oh->alloc_nmesgs = na;
469 oh->mesg = new_mesg;
470
471 /* Set new object header info to zeros */
472 HDmemset(&oh->mesg[old_alloc], 0, (oh->alloc_nmesgs - old_alloc) * sizeof(H5O_mesg_t));
473
474 done:
475 FUNC_LEAVE_NOAPI(ret_value)
476 } /* H5O_alloc_msgs() */
477
478
479 /*-------------------------------------------------------------------------
480 *
481 * Function: H5O_alloc_extend_chunk
482 *
483 * Purpose: Attempt to extend a chunk that is allocated on disk.
484 *
485 * If the extension is successful, and if the last message
486 * of the chunk is the null message, then that message will
487 * be extended with the chunk. Otherwise a new null message
488 * is created.
489 *
490 * f is the file in which the chunk will be written. It is
491 * included to ensure that there is enough space to extend
492 * this chunk.
493 *
494 * Return: TRUE: The chunk has been extended, and *msg_idx
495 * contains the message index for null message
496 * which is large enough to hold size bytes.
497 *
498 * FALSE: The chunk cannot be extended, and *msg_idx
499 * is undefined.
500 *
501 * FAIL: Some internal error has been detected.
502 *
503 * Programmer: John Mainzer -- 8/16/05
504 *
505 *-------------------------------------------------------------------------
506 */
507 static htri_t
H5O_alloc_extend_chunk(H5F_t * f,hid_t dxpl_id,H5O_t * oh,unsigned chunkno,size_t size,size_t * msg_idx)508 H5O_alloc_extend_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno,
509 size_t size, size_t *msg_idx)
510 {
511 H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
512 hbool_t chk_dirtied = FALSE; /* Flag for unprotecting chunk */
513 size_t delta; /* Change in chunk's size */
514 size_t aligned_size = H5O_ALIGN_OH(oh, size);
515 uint8_t *old_image; /* Old address of chunk's image in memory */
516 size_t old_size; /* Old size of chunk */
517 htri_t extended; /* If chunk can be extended */
518 size_t extend_msg = 0; /* Index of null message to extend */
519 hbool_t extended_msg = FALSE; /* Whether an existing message was extended */
520 uint8_t new_size_flags = 0; /* New chunk #0 size flags */
521 hbool_t adjust_size_flags = FALSE; /* Whether to adjust the chunk #0 size flags */
522 size_t extra_prfx_size = 0; /* Extra bytes added to object header prefix */
523 size_t u; /* Local index variable */
524 htri_t ret_value = TRUE; /* return value */
525
526 FUNC_ENTER_NOAPI_NOINIT
527
528 /* check args */
529 HDassert(f != NULL);
530 HDassert(oh != NULL);
531 HDassert(chunkno < oh->nchunks);
532 HDassert(size > 0);
533 HDassert(msg_idx != NULL);
534 HDassert(H5F_addr_defined(oh->chunk[chunkno].addr));
535
536 /* Test to see if the specified chunk ends with a null messages.
537 * If successful, set the index of the the null message in extend_msg.
538 */
539 for(u = 0; u < oh->nmesgs; u++) {
540 /* Check for null message at end of proper chunk */
541 /* (account for possible checksum at end of chunk) */
542 if(oh->mesg[u].chunkno == chunkno && H5O_NULL_ID == oh->mesg[u].type->id &&
543 ((oh->mesg[u].raw + oh->mesg[u].raw_size)
544 == ((oh->chunk[chunkno].image + oh->chunk[chunkno].size) -
545 (oh->chunk[chunkno].gap + H5O_SIZEOF_CHKSUM_OH(oh))))) {
546
547 extend_msg = u;
548 extended_msg = TRUE;
549 break;
550 } /* end if */
551 } /* end for */
552
553 /* If we can extend an existing null message, adjust the delta appropriately */
554 if(extended_msg) {
555 HDassert(oh->chunk[chunkno].gap == 0);
556 delta = aligned_size - oh->mesg[extend_msg].raw_size;
557 } /* end if */
558 else
559 delta = (aligned_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) - oh->chunk[chunkno].gap;
560 delta = H5O_ALIGN_OH(oh, delta);
561
562 /* Check for changing the chunk #0 data size enough to need adjusting the flags */
563 if(oh->version > H5O_VERSION_1 && chunkno == 0) {
564 uint64_t chunk0_size; /* Size of chunk 0's data */
565 size_t orig_prfx_size = (size_t)1 << (oh->flags & H5O_HDR_CHUNK0_SIZE); /* Original prefix size */
566
567 HDassert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh));
568 chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh);
569
570 /* Check for moving to a 8-byte size encoding */
571 if(orig_prfx_size < 8 && (chunk0_size + delta) > 4294967295) {
572 extra_prfx_size = 8 - orig_prfx_size;
573 new_size_flags = H5O_HDR_CHUNK0_8;
574 adjust_size_flags = TRUE;
575 } /* end if */
576 /* Check for moving to a 4-byte size encoding */
577 else if(orig_prfx_size < 4 && (chunk0_size + delta) > 65535) {
578 extra_prfx_size = 4 - orig_prfx_size;
579 new_size_flags = H5O_HDR_CHUNK0_4;
580 adjust_size_flags = TRUE;
581 } /* end if */
582 /* Check for moving to a 2-byte size encoding */
583 else if(orig_prfx_size < 2 && (chunk0_size + delta) > 255) {
584 extra_prfx_size = 2 - orig_prfx_size;
585 new_size_flags = H5O_HDR_CHUNK0_2;
586 adjust_size_flags = TRUE;
587 } /* end if */
588 } /* end if */
589
590 /* Protect chunk */
591 if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, chunkno)))
592 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
593
594 /* Determine whether the chunk can be extended */
595 extended = H5MF_try_extend(f, dxpl_id, H5FD_MEM_OHDR, oh->chunk[chunkno].addr,
596 (hsize_t)(oh->chunk[chunkno].size), (hsize_t)(delta + extra_prfx_size));
597 if(extended < 0) /* error */
598 HGOTO_ERROR(H5E_OHDR, H5E_CANTEXTEND, FAIL, "can't tell if we can extend chunk")
599 else if(extended == FALSE) /* can't extend -- we are done */
600 HGOTO_DONE(FALSE)
601
602 /* Adjust object header prefix flags */
603 if(adjust_size_flags) {
604 oh->flags = (uint8_t)(oh->flags & ~H5O_HDR_CHUNK0_SIZE);
605 oh->flags |= new_size_flags;
606
607 /* Mark object header as dirty in cache */
608 if(H5AC_mark_entry_dirty(oh) < 0)
609 HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty")
610 } /* end if */
611
612 /* If we can extend an existing null message, take care of that */
613 if(extended_msg) {
614 /* Adjust message size of existing null message */
615 oh->mesg[extend_msg].raw_size += delta;
616 } /* end if */
617 /* Create new null message for end of chunk */
618 else {
619 /* Create a new null message */
620 if(oh->nmesgs >= oh->alloc_nmesgs)
621 if(H5O_alloc_msgs(oh, (size_t)1) < 0)
622 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
623
624 /* Set extension message */
625 extend_msg = oh->nmesgs++;
626
627 /* Initialize new null message */
628 oh->mesg[extend_msg].type = H5O_MSG_NULL;
629 oh->mesg[extend_msg].native = NULL;
630 oh->mesg[extend_msg].raw = ((oh->chunk[chunkno].image + oh->chunk[chunkno].size)
631 - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[chunkno].gap))
632 + H5O_SIZEOF_MSGHDR_OH(oh);
633 oh->mesg[extend_msg].raw_size = (delta + oh->chunk[chunkno].gap) - (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
634 oh->mesg[extend_msg].chunkno = chunkno;
635 } /* end else */
636
637 /* Mark the extended message as dirty */
638 oh->mesg[extend_msg].dirty = TRUE;
639 chk_dirtied = TRUE;
640
641 /* Allocate more memory space for chunk's image */
642 old_image = oh->chunk[chunkno].image;
643 old_size = oh->chunk[chunkno].size;
644 oh->chunk[chunkno].size += delta + extra_prfx_size;
645 oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image, old_image, oh->chunk[chunkno].size);
646 oh->chunk[chunkno].gap = 0;
647 if(NULL == oh->chunk[chunkno].image)
648 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
649
650 /* Wipe new space for chunk */
651 HDmemset(oh->chunk[chunkno].image + old_size, 0, oh->chunk[chunkno].size - old_size);
652
653 /* Move chunk 0 data up if the size flags changed */
654 if(adjust_size_flags)
655 HDmemmove(oh->chunk[0].image + H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh),
656 oh->chunk[0].image + H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh) - extra_prfx_size,
657 old_size - (size_t)H5O_SIZEOF_HDR(oh) + extra_prfx_size);
658
659 /* Spin through existing messages, adjusting them */
660 for(u = 0; u < oh->nmesgs; u++) {
661 /* Adjust raw addresses for messages in this chunk to reflect new 'image' address */
662 if(oh->mesg[u].chunkno == chunkno)
663 oh->mesg[u].raw = oh->chunk[chunkno].image + extra_prfx_size + (oh->mesg[u].raw - old_image);
664
665 /* Find continuation message which points to this chunk and adjust chunk's size */
666 /* (Chunk 0 doesn't have a continuation message that points to it and
667 * it's size is directly encoded in the object header) */
668 if(chunkno > 0 && (H5O_CONT_ID == oh->mesg[u].type->id) &&
669 (((H5O_cont_t *)(oh->mesg[u].native))->chunkno == chunkno)) {
670 H5O_chunk_proxy_t *chk_proxy2 = NULL; /* Chunk that continuation message is in */
671 hbool_t chk_dirtied2 = FALSE; /* Flag for unprotecting chunk */
672 unsigned cont_chunkno = oh->mesg[u].chunkno; /* Chunk # for continuation message */
673
674 /* Protect chunk containing continuation message */
675 if(NULL == (chk_proxy2 = H5O_chunk_protect(f, dxpl_id, oh, cont_chunkno)))
676 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
677
678 /* Adjust size in continuation message */
679 HDassert(((H5O_cont_t *)(oh->mesg[u].native))->size == old_size);
680 ((H5O_cont_t *)(oh->mesg[u].native))->size = oh->chunk[chunkno].size;
681
682 /* Flag continuation message as dirty */
683 oh->mesg[u].dirty = TRUE;
684 chk_dirtied2 = TRUE;
685
686 /* Release chunk containing continuation message */
687 if(H5O_chunk_unprotect(f, dxpl_id, chk_proxy2, chk_dirtied2) < 0)
688 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
689 } /* end if */
690 } /* end for */
691
692 /* Resize the chunk in the cache */
693 if(H5O_chunk_resize(oh, chk_proxy) < 0)
694 HGOTO_ERROR(H5E_OHDR, H5E_CANTRESIZE, FAIL, "unable to resize object header chunk")
695
696 /* Set new message index */
697 *msg_idx = extend_msg;
698
699 done:
700 /* Release chunk */
701 if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
702 HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
703
704 FUNC_LEAVE_NOAPI(ret_value)
705 } /* H5O_alloc_extend_chunk() */
706
707
708 /*-------------------------------------------------------------------------
709 * Function: H5O_alloc_new_chunk
710 *
711 * Purpose: Allocates a new chunk for the object header, including
712 * file space.
713 *
714 * One of the other chunks will get an object continuation
715 * message. If there isn't room in any other chunk for the
716 * object continuation message, then some message from
717 * another chunk is moved into this chunk to make room.
718 *
719 * SIZE need not be aligned.
720 *
721 * Note: The algorithm for finding a message to replace with a
722 * continuation message is still fairly limited. It's possible
723 * that two (or more) messages smaller than a continuation message
724 * might occupy a chunk and need to be moved in order to make
725 * room for the continuation message.
726 *
727 * Also, we aren't checking for NULL messages in front of another
728 * message right now...
729 *
730 * Return: Success: Index number of the null message for the
731 * new chunk. The null message will be at
732 * least SIZE bytes not counting the message
733 * ID or size fields.
734 *
735 * Failure: Negative
736 *
737 * Programmer: Robb Matzke
738 * matzke@llnl.gov
739 * Aug 7 1997
740 *
741 *-------------------------------------------------------------------------
742 */
743 static herr_t
H5O_alloc_new_chunk(H5F_t * f,hid_t dxpl_id,H5O_t * oh,size_t size,size_t * new_idx)744 H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size, size_t *new_idx)
745 {
746 /* Struct for storing information about "best" messages to allocate from */
747 typedef struct {
748 int msgno; /* Index in message array */
749 size_t gap_size; /* Size of any "gap" in the chunk immediately after message */
750 size_t null_size; /* Size of any null message in the chunk immediately after message */
751 size_t total_size; /* Total size of "available" space around message */
752 unsigned null_msgno; /* Message index of null message immediately after message */
753 } alloc_info;
754
755 H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */
756 H5O_chunk_proxy_t *chk_proxy; /* Chunk that message is in */
757 size_t cont_size; /*continuation message size */
758 size_t multi_size = 0; /* Size of all the messages in the last chunk */
759 int found_null = (-1); /* Best fit null message */
760 alloc_info found_attr = {-1, 0, 0, 0, 0}; /* Best fit attribute message */
761 alloc_info found_other = {-1, 0, 0, 0, 0}; /* Best fit other message */
762 size_t idx; /* Message number */
763 uint8_t *p = NULL; /*ptr into new chunk */
764 H5O_cont_t *cont = NULL; /*native continuation message */
765 unsigned chunkno; /* Chunk allocated */
766 haddr_t new_chunk_addr;
767 unsigned u; /* Local index variable */
768 herr_t ret_value = SUCCEED; /* Return value */
769
770 FUNC_ENTER_NOAPI_NOINIT
771
772 /* check args */
773 HDassert(oh);
774 HDassert(size > 0);
775 size = H5O_ALIGN_OH(oh, size);
776
777 /*
778 * Find the smallest null message that will hold an object
779 * continuation message. Failing that, find the smallest message
780 * that could be moved to make room for the continuation message.
781 *
782 * Don't ever move continuation message from one chunk to another.
783 *
784 * Avoid moving attributes when possible to preserve their
785 * ordering (although ordering is *not* guaranteed!).
786 *
787 */
788 cont_size = H5O_ALIGN_OH(oh, (size_t)(H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f)));
789 for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
790 if(curr_msg->type->id == H5O_NULL_ID) {
791 if(cont_size == curr_msg->raw_size) {
792 found_null = (int)u;
793 break;
794 } /* end if */
795 else if(curr_msg->raw_size > cont_size &&
796 (found_null < 0 || curr_msg->raw_size < oh->mesg[found_null].raw_size))
797 found_null = (int)u;
798 } /* end if */
799 else if(curr_msg->type->id == H5O_CONT_ID) {
800 /* Don't consider continuation messages (for now) */
801 } /* end if */
802 else if(curr_msg->locked) {
803 /* Don't consider locked messages */
804 } /* end if */
805 else {
806 unsigned msg_chunkno = curr_msg->chunkno; /* Chunk that the message is in */
807 uint8_t *end_chunk_data = (oh->chunk[msg_chunkno].image + oh->chunk[msg_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[msg_chunkno].gap); /* End of message data in chunk */
808 uint8_t *end_msg = curr_msg->raw + curr_msg->raw_size; /* End of current message */
809 size_t gap_size = 0; /* Size of gap after current message */
810 size_t null_size = 0; /* Size of NULL message after current message */
811 unsigned null_msgno = 0; /* Index of NULL message after current message */
812 size_t total_size; /* Total size of available space "around" current message */
813
814 /* Check if the message is the last one in the chunk */
815 if(end_msg == end_chunk_data)
816 gap_size = oh->chunk[msg_chunkno].gap;
817 else {
818 H5O_mesg_t *tmp_msg; /* Temp. pointer to message to operate on */
819 unsigned v; /* Local index variable */
820
821 /* Check for null message after this message, in same chunk */
822 for(v = 0, tmp_msg = &oh->mesg[0]; v < oh->nmesgs; v++, tmp_msg++) {
823 if(tmp_msg->type->id == H5O_NULL_ID && (tmp_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == end_msg) {
824 null_msgno = v;
825 null_size = (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + tmp_msg->raw_size;
826 break;
827 } /* end if */
828
829 /* XXX: Should also check for NULL message in front of current message... */
830
831 } /* end for */
832 } /* end else */
833
834 /* Add up current message's total available space */
835 total_size = curr_msg->raw_size + gap_size + null_size;
836
837 /* Check if message is large enough to hold continuation info */
838 if(total_size >= cont_size) {
839 if(curr_msg->type->id == H5O_ATTR_ID) {
840 if(found_attr.msgno < 0 || total_size < found_attr.total_size) {
841 found_attr.msgno = (int)u;
842 found_attr.gap_size = gap_size;
843 found_attr.null_size = null_size;
844 found_attr.total_size = total_size;
845 found_attr.null_msgno = null_msgno;
846 } /* end if */
847 } /* end if */
848 else {
849 if(found_other.msgno < 0 || total_size < found_other.total_size) {
850 found_other.msgno = (int)u;
851 found_other.gap_size = gap_size;
852 found_other.null_size = null_size;
853 found_other.total_size = total_size;
854 found_other.null_msgno = null_msgno;
855 } /* end if */
856 } /* end else */
857 } /* end if */
858 else if(found_null < 0 && found_attr.msgno < 0 && found_other.msgno < 0 && msg_chunkno == oh->nchunks - 1)
859 /* Keep track of the total size of smaller messages in the last
860 * chunk, in case we need to move more than 1 message.
861 */
862 multi_size += curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
863 } /* end else */
864 } /* end for */
865 if(found_null >= 0 || found_attr.msgno >= 0 || found_other.msgno >= 0)
866 multi_size = 0;
867
868 /*
869 * If we must move some other message to make room for the null
870 * message, then make sure the new chunk has enough room for that
871 * other message.
872 *
873 * Move other messages first, and attributes only as a last resort.
874 *
875 * If all else fails, move every message in the last chunk.
876 *
877 */
878 if(multi_size == 0) {
879 if(found_null < 0) {
880 if(found_other.msgno < 0)
881 found_other = found_attr;
882
883 HDassert(found_other.msgno >= 0);
884 size += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size;
885 } /* end if */
886 } /* end if */
887 else
888 size += multi_size;
889
890 /*
891 * The total chunk size must include the requested space plus enough
892 * for the message header. This must be at least some minimum and
893 * aligned propertly.
894 */
895 size = MAX(H5O_MIN_SIZE, size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
896 HDassert(size == H5O_ALIGN_OH(oh, size));
897
898 /*
899 * The total chunk size must include enough space for the checksum
900 * on the chunk and the continuation chunk magic #. (which are only present
901 * in later versions of the object header)
902 */
903 size += H5O_SIZEOF_CHKHDR_OH(oh);
904
905 /* allocate space in file to hold the new chunk */
906 new_chunk_addr = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)size);
907 if(HADDR_UNDEF == new_chunk_addr)
908 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate space for new chunk")
909
910 /*
911 * Create the new chunk giving it a file address.
912 */
913 if(oh->nchunks >= oh->alloc_nchunks) {
914 size_t na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */
915 H5O_chunk_t *x;
916
917 if(NULL == (x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, na)))
918 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
919 oh->alloc_nchunks = na;
920 oh->chunk = x;
921 } /* end if */
922
923 chunkno = oh->nchunks++;
924 oh->chunk[chunkno].addr = new_chunk_addr;
925 oh->chunk[chunkno].size = size;
926 oh->chunk[chunkno].gap = 0;
927 if(NULL == (oh->chunk[chunkno].image = p = H5FL_BLK_CALLOC(chunk_image, size)))
928 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
929
930 /* If this is a later version of the object header format, put the magic
931 * # at the beginning of the chunk image.
932 */
933 if(oh->version > H5O_VERSION_1) {
934 HDmemcpy(p, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC);
935 p += H5_SIZEOF_MAGIC;
936 } /* end if */
937
938 /*
939 * Make sure we have enough space for all possible new messages
940 * that could be generated below.
941 */
942 if(oh->nmesgs + 3 > oh->alloc_nmesgs)
943 if(H5O_alloc_msgs(oh, (size_t)3) < 0)
944 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
945
946 /* Check if we need to move multiple messages, in order to make room for the new message */
947 if(multi_size > 0) {
948 /* Move all non-null messages in the last chunk to the new chunk. This
949 * should be extremely rare so we don't care too much about minimizing
950 * the space used.
951 */
952 H5O_mesg_t *null_msg; /* Pointer to new null message */
953
954 /* Protect last chunk */
955 if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, chunkno - 1)))
956 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
957
958 /* Copy each message to the new location */
959 for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++)
960 if(curr_msg->chunkno == chunkno - 1) {
961 if(curr_msg->type->id == H5O_NULL_ID) {
962 /* Delete the null message */
963 if(u < oh->nmesgs - 1)
964 HDmemmove(curr_msg, curr_msg + 1, ((oh->nmesgs - 1) - u) * sizeof(H5O_mesg_t));
965 oh->nmesgs--;
966 } /* end if */
967 else {
968 /* Copy the raw data */
969 HDmemcpy(p, curr_msg->raw - (size_t)H5O_SIZEOF_MSGHDR_OH(oh),
970 curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
971
972 /* Update the message info */
973 curr_msg->chunkno = chunkno;
974 curr_msg->raw = p + H5O_SIZEOF_MSGHDR_OH(oh);
975
976 /* Account for copied message in new chunk */
977 p += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size;
978 size -= (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size;
979 } /* end else */
980 } /* end if */
981
982 /* Create a null message spanning the entire last chunk */
983 found_null = (int)oh->nmesgs++;
984 null_msg = &(oh->mesg[found_null]);
985 null_msg->type = H5O_MSG_NULL;
986 null_msg->dirty = TRUE;
987 null_msg->native = NULL;
988 null_msg->raw = oh->chunk[chunkno - 1].image
989 + ((chunkno == 1) ? H5O_SIZEOF_HDR(oh) : H5O_SIZEOF_CHKHDR_OH(oh))
990 - H5O_SIZEOF_CHKSUM_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh);
991 null_msg->raw_size = oh->chunk[chunkno - 1].size
992 - ((chunkno == 1) ? (size_t)H5O_SIZEOF_HDR(oh) : (size_t)H5O_SIZEOF_CHKHDR_OH(oh))
993 - (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
994 null_msg->chunkno = chunkno - 1;
995
996 HDassert(null_msg->raw_size >= cont_size);
997
998 /* Remove any gap in the chunk */
999 oh->chunk[chunkno - 1].gap = 0;
1000
1001 /* Release chunk, marking it dirty */
1002 if(H5O_chunk_unprotect(f, dxpl_id, chk_proxy, TRUE) < 0)
1003 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
1004 } else if(found_null < 0) {
1005 /* Move message (that will be replaced with continuation message)
1006 * to new chunk, if necessary.
1007 */
1008 H5O_mesg_t *null_msg; /* Pointer to new null message */
1009
1010 /* Protect chunk */
1011 if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, oh->mesg[found_other.msgno].chunkno)))
1012 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
1013
1014 /* Create null message for space that message to copy currently occupies */
1015 found_null = (int)oh->nmesgs++;
1016 null_msg = &(oh->mesg[found_null]);
1017 null_msg->type = H5O_MSG_NULL;
1018 null_msg->native = NULL;
1019 null_msg->raw = oh->mesg[found_other.msgno].raw;
1020 null_msg->raw_size = oh->mesg[found_other.msgno].raw_size;
1021 null_msg->chunkno = oh->mesg[found_other.msgno].chunkno;
1022
1023 /* Copy the message to move (& its prefix) to its new location */
1024 HDmemcpy(p, oh->mesg[found_other.msgno].raw - H5O_SIZEOF_MSGHDR_OH(oh),
1025 oh->mesg[found_other.msgno].raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
1026
1027 /* Switch moved message to point to new location */
1028 oh->mesg[found_other.msgno].raw = p + H5O_SIZEOF_MSGHDR_OH(oh);
1029 oh->mesg[found_other.msgno].chunkno = chunkno;
1030
1031 /* Account for copied message in new chunk */
1032 p += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size;
1033 size -= (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size;
1034
1035 /* Add any available space after the message to move to the new null message */
1036 if(found_other.gap_size > 0) {
1037 /* Absorb a gap after the moved message */
1038 HDassert(oh->chunk[null_msg->chunkno].gap == found_other.gap_size);
1039 null_msg->raw_size += found_other.gap_size;
1040 oh->chunk[null_msg->chunkno].gap = 0;
1041 } /* end if */
1042 else if(found_other.null_size > 0) {
1043 H5O_mesg_t *old_null_msg = &oh->mesg[found_other.null_msgno]; /* Pointer to NULL message to eliminate */
1044
1045 /* Absorb a null message after the moved message */
1046 HDassert((null_msg->raw + null_msg->raw_size) == (old_null_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)));
1047 null_msg->raw_size += found_other.null_size;
1048
1049 /* Release any information/memory for message */
1050 H5O_msg_free_mesg(old_null_msg);
1051
1052 /* Remove null message from list of messages */
1053 if(found_other.null_msgno < (oh->nmesgs - 1))
1054 HDmemmove(old_null_msg, old_null_msg + 1, ((oh->nmesgs - 1) - found_other.null_msgno) * sizeof(H5O_mesg_t));
1055
1056 /* Decrement # of messages */
1057 /* (Don't bother reducing size of message array for now -QAK) */
1058 oh->nmesgs--;
1059
1060 /* Adjust message index for new NULL message */
1061 found_null--;
1062 } /* end if */
1063
1064 /* Mark the new null message as dirty */
1065 null_msg->dirty = TRUE;
1066
1067 /* Release chunk, marking it dirty */
1068 if(H5O_chunk_unprotect(f, dxpl_id, chk_proxy, TRUE) < 0)
1069 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
1070 } /* end if */
1071 HDassert(found_null >= 0);
1072
1073 /* Create null message for [rest of] space in new chunk */
1074 /* (account for chunk's magic # & checksum) */
1075 idx = oh->nmesgs++;
1076 oh->mesg[idx].type = H5O_MSG_NULL;
1077 oh->mesg[idx].dirty = TRUE;
1078 oh->mesg[idx].native = NULL;
1079 oh->mesg[idx].raw = p + H5O_SIZEOF_MSGHDR_OH(oh);
1080 oh->mesg[idx].raw_size = size - (size_t)(H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh));
1081 oh->mesg[idx].chunkno = chunkno;
1082
1083 /* Insert the new chunk into the cache */
1084 if(H5O_chunk_add(f, dxpl_id, oh, chunkno) < 0)
1085 HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't add new chunk to cache")
1086
1087 /* Initialize the continuation information */
1088 if(NULL == (cont = H5FL_MALLOC(H5O_cont_t)))
1089 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
1090 cont->addr = oh->chunk[chunkno].addr;
1091 cont->size = oh->chunk[chunkno].size;
1092 cont->chunkno = chunkno;
1093
1094 /* Split the null message and point at continuation message */
1095 if(H5O_alloc_null(f, dxpl_id, oh, (size_t)found_null, H5O_MSG_CONT, cont, cont_size) < 0)
1096 HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't split null message")
1097
1098 /* Set new message index value */
1099 *new_idx = idx;
1100
1101 done:
1102 FUNC_LEAVE_NOAPI(ret_value)
1103 } /* H5O_alloc_new_chunk() */
1104
1105
1106 /*-------------------------------------------------------------------------
1107 * Function: H5O_alloc
1108 *
1109 * Purpose: Allocate enough space in the object header for this message.
1110 *
1111 * Return: Success: Index of message
1112 * Failure: Negative
1113 *
1114 * Programmer: Robb Matzke
1115 * matzke@llnl.gov
1116 * Aug 6 1997
1117 *
1118 *-------------------------------------------------------------------------
1119 */
1120 herr_t
H5O_alloc(H5F_t * f,hid_t dxpl_id,H5O_t * oh,const H5O_msg_class_t * type,const void * mesg,size_t * mesg_idx)1121 H5O_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type,
1122 const void *mesg, size_t *mesg_idx)
1123 {
1124 size_t raw_size; /* Raw size of message */
1125 size_t aligned_size; /* Size of message including alignment */
1126 size_t idx; /* Index of message which fits allocation */
1127 herr_t ret_value = SUCCEED; /* Return value */
1128
1129 FUNC_ENTER_NOAPI(FAIL)
1130
1131 /* check args */
1132 HDassert(oh);
1133 HDassert(type);
1134 HDassert(mesg);
1135 HDassert(mesg_idx);
1136
1137 /* Compute the size needed to store the message in the object header */
1138 raw_size = (type->raw_size)(f, FALSE, mesg);
1139 if(0 == raw_size)
1140 HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "can't compute object header message size")
1141 if(raw_size >= H5O_MESG_MAX_SIZE)
1142 HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "object header message is too large")
1143 aligned_size = H5O_ALIGN_OH(oh, raw_size);
1144
1145 /* look for a null message which is large enough */
1146 for(idx = 0; idx < oh->nmesgs; idx++)
1147 if(H5O_NULL_ID == oh->mesg[idx].type->id && oh->mesg[idx].raw_size >= aligned_size)
1148 break;
1149
1150 /* if we didn't find one, then allocate more header space */
1151 if(idx >= oh->nmesgs) {
1152 unsigned chunkno;
1153
1154 /* check to see if we can extend one of the chunks. If we can,
1155 * do so. Otherwise, we will have to allocate a new chunk.
1156 *
1157 * Note that in this new version of this function, all chunks
1158 * must have file space allocated to them.
1159 */
1160 for(chunkno = 0; chunkno < oh->nchunks; chunkno++) {
1161 htri_t tri_result; /* Status from attempting to extend chunk */
1162
1163 if((tri_result = H5O_alloc_extend_chunk(f, dxpl_id, oh, chunkno, raw_size, &idx)) < 0)
1164 HGOTO_ERROR(H5E_OHDR, H5E_CANTEXTEND, FAIL, "H5O_alloc_extend_chunk failed unexpectedly")
1165 if(tri_result == TRUE)
1166 break;
1167 } /* end for */
1168
1169 /* If we were not able to extend a chunk, create a new one */
1170 if(idx >= oh->nmesgs)
1171 if(H5O_alloc_new_chunk(f, dxpl_id, oh, raw_size, &idx) < 0)
1172 HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "unable to create a new object header data chunk")
1173 } /* end if */
1174 HDassert(idx < oh->nmesgs);
1175
1176 /* Split the null message and point at continuation message */
1177 if(H5O_alloc_null(f, dxpl_id, oh, idx, type, NULL, aligned_size) < 0)
1178 HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't split null message")
1179
1180 /* Mark object header as dirty in cache */
1181 if(H5AC_mark_entry_dirty(oh) < 0)
1182 HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty")
1183
1184 /* Set message index value */
1185 *mesg_idx = idx;
1186
1187 done:
1188 FUNC_LEAVE_NOAPI(ret_value)
1189 } /* H5O_alloc() */
1190
1191
1192 /*-------------------------------------------------------------------------
1193 *
1194 * Function: H5O_release_mesg
1195 *
1196 * Purpose: Convert a message into a null message
1197 *
1198 * Return: Non-negative on success/Negative on failure
1199 *
1200 * Programmer: Quincey Koziol
1201 * koziol@hdfgroup.org
1202 * Oct 22 2006
1203 *
1204 *-------------------------------------------------------------------------
1205 */
1206 herr_t
H5O_release_mesg(H5F_t * f,hid_t dxpl_id,H5O_t * oh,H5O_mesg_t * mesg,hbool_t adj_link)1207 H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg,
1208 hbool_t adj_link)
1209 {
1210 H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that message is in */
1211 hbool_t chk_dirtied = FALSE; /* Flag for unprotecting chunk */
1212 herr_t ret_value = SUCCEED; /* Return value */
1213
1214 FUNC_ENTER_NOAPI(FAIL)
1215
1216 /* check args */
1217 HDassert(f);
1218 HDassert(oh);
1219 HDassert(mesg);
1220
1221 /* Check if we should operate on the message */
1222 if(adj_link) {
1223 /* Free any space referred to in the file from this message */
1224 if(H5O_delete_mesg(f, dxpl_id, oh, mesg) < 0)
1225 HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message")
1226 } /* end if */
1227
1228 /* Protect chunk */
1229 if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, mesg->chunkno)))
1230 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk")
1231
1232 /* Free any native information */
1233 H5O_msg_free_mesg(mesg);
1234
1235 /* Change message type to nil and zero it */
1236 mesg->type = H5O_MSG_NULL;
1237 HDassert(mesg->raw + mesg->raw_size <= (oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap));
1238 HDmemset(mesg->raw, 0, mesg->raw_size);
1239
1240 /* Clear message flags */
1241 mesg->flags = 0;
1242
1243 /* Mark the message as modified */
1244 mesg->dirty = TRUE;
1245 chk_dirtied = TRUE;
1246
1247 /* Check if chunk has a gap currently */
1248 if(oh->chunk[mesg->chunkno].gap) {
1249 /* Eliminate the gap in the chunk */
1250 if(H5O_eliminate_gap(oh, &chk_dirtied, mesg,
1251 ((oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap)),
1252 oh->chunk[mesg->chunkno].gap) < 0)
1253 HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk")
1254 } /* end if */
1255
1256 done:
1257 /* Release chunk, if not already done */
1258 if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
1259 HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
1260
1261 FUNC_LEAVE_NOAPI(ret_value)
1262 } /* H5O_release_mesg() */
1263
1264
1265 /*-------------------------------------------------------------------------
1266 * Function: H5O_move_cont
1267 *
1268 * Purpose: Check and move message(s) forward into a continuation message
1269 *
1270 * Return: Success: non-negative (TRUE/FALSE)
1271 * Failure: negative
1272 *
1273 * Programmer: Vailin Choi
1274 * Feb. 2009
1275 *
1276 *-------------------------------------------------------------------------
1277 */
1278 static htri_t
H5O_move_cont(H5F_t * f,hid_t dxpl_id,H5O_t * oh,unsigned cont_u)1279 H5O_move_cont(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned cont_u)
1280 {
1281 H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk that continuation message is in */
1282 H5O_mesg_t *cont_msg; /* Pointer to the continuation message */
1283 unsigned deleted_chunkno; /* Chunk # to delete */
1284 hbool_t chk_dirtied = FALSE; /* Flags for unprotecting chunk */
1285 htri_t ret_value = TRUE; /* Return value */
1286
1287 FUNC_ENTER_NOAPI_NOINIT
1288
1289 /* Check arguments. */
1290 HDassert(f);
1291 HDassert(oh);
1292
1293 /* Get initial information */
1294 cont_msg = &oh->mesg[cont_u];
1295 H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, cont_msg, FAIL)
1296 deleted_chunkno = ((H5O_cont_t *)(cont_msg->native))->chunkno;
1297
1298 /* Check if continuation message is pointing to the last chunk */
1299 if(deleted_chunkno == (oh->nchunks - 1)) {
1300 size_t nonnull_size; /* Total size of nonnull messages in the chunk pointed to by cont message */
1301 H5O_mesg_t *curr_msg; /* Pointer to the current message to operate on */
1302 size_t gap_size; /* Size of gap produced */
1303 size_t v; /* Local index variable */
1304
1305 /* Spin through messages */
1306 nonnull_size = 0;
1307 for(v = 0, curr_msg = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg++) {
1308 if(curr_msg->chunkno == deleted_chunkno) {
1309 /* If there's a locked message, we can't move all messages out of
1310 * chunk to delete, so get out now.
1311 */
1312 if(curr_msg->locked)
1313 HGOTO_DONE(FALSE)
1314
1315 /* Find size of all non-null messages in the chunk pointed to by the continuation message */
1316 if(curr_msg->type->id != H5O_NULL_ID) {
1317 HDassert(curr_msg->type->id != H5O_CONT_ID);
1318 nonnull_size += curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
1319 } /* end if */
1320 } /* end if */
1321 } /* end for */
1322
1323 /* Size of gap in chunk w/continuation message */
1324 gap_size = oh->chunk[cont_msg->chunkno].gap;
1325
1326 /* Check if messages can fit into the continuation message + gap size */
1327 /* (Could count any null messages in the chunk w/the continuation
1328 * message also, but that is pretty complex. -QAK)
1329 */
1330 if(nonnull_size && nonnull_size <= (gap_size + cont_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh))) {
1331 uint8_t *move_start, *move_end; /* Pointers to area of messages to move */
1332 unsigned cont_chunkno; /* Chunk number for continuation message */
1333
1334 /* Get continuation info */
1335 move_start = cont_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh);
1336 move_end = cont_msg->raw + cont_msg->raw_size;
1337 cont_chunkno = cont_msg->chunkno;
1338
1339 /* Convert continuation message into a null message. Do not delete
1340 * the target chunk yet, so we can still copy messages from it. */
1341 if(H5O_release_mesg(f, dxpl_id, oh, cont_msg, FALSE) < 0)
1342 HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to convert into null message")
1343
1344 /* Protect chunk */
1345 if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, cont_chunkno)))
1346 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk")
1347
1348 /* Move message(s) forward into continuation message */
1349 for(v = 0, curr_msg = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg++)
1350 /* Look for messages in chunk to delete */
1351 if(curr_msg->chunkno == deleted_chunkno) {
1352 /* Move messages out of chunk to delete */
1353 if(curr_msg->type->id != H5O_NULL_ID) {
1354 size_t move_size; /* Size of the message to be moved */
1355
1356 /* Compute size of message to move */
1357 move_size = curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
1358
1359 /* Move message out of deleted chunk */
1360 HDmemcpy(move_start, curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), move_size);
1361 curr_msg->raw = move_start + H5O_SIZEOF_MSGHDR_OH(oh);
1362 curr_msg->chunkno = cont_chunkno;
1363 chk_dirtied = TRUE;
1364
1365 /* Adjust location to move messages to */
1366 move_start += move_size;
1367 } /* end else */
1368 } /* end if */
1369
1370 /* Delete the target chunk */
1371 if(H5O_chunk_delete(f, dxpl_id, oh, deleted_chunkno) < 0)
1372 HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove chunk from cache")
1373
1374 HDassert(move_start <= (move_end + gap_size));
1375
1376 /* Check if there is space remaining in the continuation message */
1377 /* (The remaining space can be gap or a null message) */
1378 gap_size += (size_t)(move_end - move_start);
1379 if(gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) {
1380 /* Adjust size of null (was continuation) message */
1381 cont_msg->raw_size = gap_size - (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
1382 cont_msg->raw = move_start + H5O_SIZEOF_MSGHDR_OH(oh);
1383 cont_msg->dirty = TRUE;
1384 chk_dirtied = TRUE;
1385 } /* end if */
1386 else {
1387 /* Check if there is space that should be a gap */
1388 if(gap_size > 0) {
1389 /* Convert remnant into gap in chunk */
1390 if(H5O_add_gap(f, oh, cont_chunkno, &chk_dirtied, cont_u, move_start, gap_size) < 0)
1391 HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk")
1392 } /* end if */
1393
1394 /* Release any information/memory for continuation message */
1395 H5O_msg_free_mesg(cont_msg);
1396 if(cont_u < (oh->nmesgs - 1))
1397 HDmemmove(&oh->mesg[cont_u], &oh->mesg[cont_u + 1], ((oh->nmesgs - 1) - cont_u) * sizeof(H5O_mesg_t));
1398 oh->nmesgs--;
1399 } /* end else */
1400
1401 /* Move message(s) forward into continuation message */
1402 /* Note: unsigned v wrapping around at the end */
1403 for(v = oh->nmesgs - 1, curr_msg = &oh->mesg[v]; v < oh->nmesgs; v--, curr_msg--)
1404 /* Look for messages in chunk to delete */
1405 if(curr_msg->chunkno == deleted_chunkno) {
1406 /* Remove all null messages in deleted chunk from list of messages */
1407 if(curr_msg->type->id == H5O_NULL_ID) {
1408 /* Release any information/memory for message */
1409 H5O_msg_free_mesg(curr_msg);
1410 chk_dirtied = TRUE;
1411
1412 /* Remove from message list */
1413 if(v < (oh->nmesgs - 1))
1414 HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t));
1415 oh->nmesgs--;
1416 } /* end if */
1417 } /* end if */
1418
1419 /* Remove chunk from list of chunks */
1420 oh->chunk[deleted_chunkno].image = H5FL_BLK_FREE(chunk_image, oh->chunk[deleted_chunkno].image);
1421 oh->nchunks--;
1422 } /* end if */
1423 else
1424 ret_value = FALSE;
1425 } /* end if */
1426 else
1427 ret_value = FALSE;
1428
1429 done:
1430 /* Release chunk, if not already done */
1431 if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, chk_dirtied) < 0)
1432 HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
1433
1434 FUNC_LEAVE_NOAPI(ret_value)
1435 } /* H5O_move_cont() */
1436
1437
1438 /*-------------------------------------------------------------------------
1439 *
1440 * Function: H5O_move_msgs_forward
1441 *
1442 * Purpose: Move messages toward first chunk
1443 *
1444 * Return: Non-negative on success/Negative on failure
1445 *
1446 * Programmer: Quincey Koziol
1447 * koziol@ncsa.uiuc.edu
1448 * Oct 17 2005
1449 *
1450 *-------------------------------------------------------------------------
1451 */
1452 static htri_t
H5O_move_msgs_forward(H5F_t * f,hid_t dxpl_id,H5O_t * oh)1453 H5O_move_msgs_forward(H5F_t *f, hid_t dxpl_id, H5O_t *oh)
1454 {
1455 H5O_chunk_proxy_t *null_chk_proxy = NULL; /* Chunk that null message is in */
1456 H5O_chunk_proxy_t *curr_chk_proxy = NULL; /* Chunk that message is in */
1457 hbool_t null_chk_dirtied = FALSE; /* Flags for unprotecting null chunk */
1458 hbool_t curr_chk_dirtied = FALSE; /* Flags for unprotecting curr chunk */
1459 hbool_t packed_msg; /* Flag to indicate that messages were packed */
1460 hbool_t did_packing = FALSE; /* Whether any messages were packed */
1461 htri_t ret_value; /* Return value */
1462
1463 FUNC_ENTER_NOAPI_NOINIT
1464
1465 /* check args */
1466 HDassert(oh);
1467
1468 /* Loop until no messages packed */
1469 /* (Double loop is not very efficient, but it would be some extra work to
1470 * add a list of messages to each chunk -QAK)
1471 */
1472 do {
1473 H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */
1474 unsigned u; /* Local index variable */
1475
1476 /* Reset packed messages flag */
1477 packed_msg = FALSE;
1478
1479 /* Scan through messages for messages that can be moved earlier in chunks */
1480 for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
1481 if(H5O_NULL_ID == curr_msg->type->id) {
1482 H5O_chunk_t *chunk; /* Pointer to chunk that null message is in */
1483
1484 /* Check if null message is not last in chunk */
1485 chunk = &(oh->chunk[curr_msg->chunkno]);
1486 if((curr_msg->raw + curr_msg->raw_size)
1487 != ((chunk->image + chunk->size) - (H5O_SIZEOF_CHKSUM_OH(oh) + chunk->gap))) {
1488 H5O_mesg_t *nonnull_msg; /* Pointer to current message to operate on */
1489 unsigned v; /* Local index variable */
1490
1491 /* Loop over messages again, looking for the message in the chunk after the null message */
1492 for(v = 0, nonnull_msg = &oh->mesg[0]; v < oh->nmesgs; v++, nonnull_msg++) {
1493 /* Locate message that is immediately after the null message */
1494 if((curr_msg->chunkno == nonnull_msg->chunkno) &&
1495 ((curr_msg->raw + curr_msg->raw_size) == (nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)))) {
1496 /* Don't swap messages if the second message is also a null message */
1497 /* (We'll merge them together later, in another routine) */
1498 if(H5O_NULL_ID != nonnull_msg->type->id) {
1499 /* Protect chunk */
1500 if(NULL == (null_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno)))
1501 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
1502
1503 /* Copy raw data for non-null message to new location */
1504 HDmemmove(curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh),
1505 nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), nonnull_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
1506
1507 /* Adjust non-null message's offset in chunk */
1508 nonnull_msg->raw = curr_msg->raw;
1509
1510 /* Adjust null message's offset in chunk */
1511 curr_msg->raw = nonnull_msg->raw +
1512 nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh);
1513
1514 /* Mark null message dirty */
1515 /* (since we need to re-encode its message header) */
1516 curr_msg->dirty = TRUE;
1517
1518 /* Release chunk, marking it dirty */
1519 if(H5O_chunk_unprotect(f, dxpl_id, null_chk_proxy, TRUE) < 0)
1520 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
1521 null_chk_proxy = NULL;
1522
1523 /* Set the flag to indicate that the null message
1524 * was packed - if its not at the end its chunk,
1525 * we'll move it again on the next pass.
1526 */
1527 packed_msg = TRUE;
1528 } /* end if */
1529
1530 /* Break out of loop */
1531 break;
1532 } /* end if */
1533 } /* end for */
1534 /* Should have been message after null message */
1535 HDassert(v < oh->nmesgs);
1536 } /* end if */
1537 } /* end if */
1538 else {
1539 H5O_mesg_t *null_msg; /* Pointer to current message to operate on */
1540 size_t v; /* Local index variable */
1541
1542 /* Check if messages in chunk pointed to can replace continuation message */
1543 if(H5O_CONT_ID == curr_msg->type->id) {
1544 htri_t status; /* Status from moving messages */
1545
1546 if((status = H5O_move_cont(f, dxpl_id, oh, u)) < 0)
1547 HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "Error in moving messages into cont message")
1548 else if(status > 0) { /* Message(s) got moved into "continuation" message */
1549 packed_msg = TRUE;
1550 break;
1551 } /* end else-if */
1552 } /* end if */
1553
1554 /* Don't let locked messages be moved into earlier chunk */
1555 if(!curr_msg->locked) {
1556 /* Loop over messages again, looking for large enough null message in earlier chunk */
1557 for(v = 0, null_msg = &oh->mesg[0]; v < oh->nmesgs; v++, null_msg++) {
1558 if(H5O_NULL_ID == null_msg->type->id && curr_msg->chunkno > null_msg->chunkno
1559 && curr_msg->raw_size <= null_msg->raw_size) {
1560 unsigned old_chunkno; /* Old message information */
1561 uint8_t *old_raw;
1562
1563 /* Keep old information about non-null message */
1564 old_chunkno = curr_msg->chunkno;
1565 old_raw = curr_msg->raw;
1566
1567 /* Protect chunks */
1568 if(NULL == (null_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, null_msg->chunkno)))
1569 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
1570 if(NULL == (curr_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno)))
1571 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
1572
1573 /* Copy raw data for non-null message to new chunk */
1574 HDmemcpy(null_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh));
1575
1576 /* Point non-null message at null message's space */
1577 curr_msg->chunkno = null_msg->chunkno;
1578 curr_msg->raw = null_msg->raw;
1579 curr_chk_dirtied = TRUE;
1580
1581 /* Change information for null message */
1582 if(curr_msg->raw_size == null_msg->raw_size) {
1583 /* Point null message at old non-null space */
1584 /* (Instead of freeing it and allocating new message) */
1585 null_msg->chunkno = old_chunkno;
1586 null_msg->raw = old_raw;
1587
1588 /* Mark null message dirty */
1589 null_msg->dirty = TRUE;
1590 null_chk_dirtied = TRUE;
1591
1592 /* Release current chunk, marking it dirty */
1593 if(H5O_chunk_unprotect(f, dxpl_id, curr_chk_proxy, curr_chk_dirtied) < 0)
1594 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
1595 curr_chk_proxy = NULL;
1596 curr_chk_dirtied = FALSE;
1597
1598 /* Check for gap in null message's chunk */
1599 if(oh->chunk[old_chunkno].gap > 0) {
1600 /* Eliminate the gap in the chunk */
1601 if(H5O_eliminate_gap(oh, &null_chk_dirtied, null_msg,
1602 ((oh->chunk[old_chunkno].image + oh->chunk[old_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[old_chunkno].gap)),
1603 oh->chunk[old_chunkno].gap) < 0)
1604 HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk")
1605 } /* end if */
1606
1607 /* Release null chunk, marking it dirty */
1608 if(H5O_chunk_unprotect(f, dxpl_id, null_chk_proxy, null_chk_dirtied) < 0)
1609 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
1610 null_chk_proxy = NULL;
1611 null_chk_dirtied = FALSE;
1612 } /* end if */
1613 else {
1614 size_t new_null_msg; /* Message index for new null message */
1615
1616 /* Check if null message is large enough to still exist */
1617 if((null_msg->raw_size - curr_msg->raw_size) < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) {
1618 size_t gap_size = null_msg->raw_size - curr_msg->raw_size; /* Size of gap produced */
1619
1620 /* Adjust the size of the null message being eliminated */
1621 null_msg->raw_size = curr_msg->raw_size;
1622
1623 /* Mark null message dirty */
1624 null_msg->dirty = TRUE;
1625 null_chk_dirtied = TRUE;
1626
1627 /* Add the gap to the chunk */
1628 if(H5O_add_gap(f, oh, null_msg->chunkno, &null_chk_dirtied, v, null_msg->raw + null_msg->raw_size, gap_size) < 0)
1629 HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk")
1630
1631 /* Re-use message # for new null message taking place of non-null message */
1632 new_null_msg = v;
1633 } /* end if */
1634 else {
1635 /* Adjust null message's size & offset */
1636 null_msg->raw += curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
1637 null_msg->raw_size -= curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh);
1638
1639 /* Mark null message dirty */
1640 null_msg->dirty = TRUE;
1641 null_chk_dirtied = TRUE;
1642
1643 /* Create new null message for previous location of non-null message */
1644 if(oh->nmesgs >= oh->alloc_nmesgs) {
1645 if(H5O_alloc_msgs(oh, (size_t)1) < 0)
1646 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
1647
1648 /* "Retarget" 'curr_msg' pointer into newly re-allocated array of messages */
1649 curr_msg = &oh->mesg[u];
1650 } /* end if */
1651
1652 /* Get message # for new null message */
1653 new_null_msg = oh->nmesgs++;
1654 } /* end else */
1655
1656 /* Release null message's chunk, marking it dirty */
1657 if(H5O_chunk_unprotect(f, dxpl_id, null_chk_proxy, null_chk_dirtied) < 0)
1658 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
1659 null_chk_proxy = NULL;
1660 null_chk_dirtied = FALSE;
1661
1662 /* Initialize new null message to take over non-null message's location */
1663 oh->mesg[new_null_msg].type = H5O_MSG_NULL;
1664 oh->mesg[new_null_msg].native = NULL;
1665 oh->mesg[new_null_msg].raw = old_raw;
1666 oh->mesg[new_null_msg].raw_size = curr_msg->raw_size;
1667 oh->mesg[new_null_msg].chunkno = old_chunkno;
1668
1669 /* Mark new null message dirty */
1670 oh->mesg[new_null_msg].dirty = TRUE;
1671 curr_chk_dirtied = TRUE;
1672
1673 /* Check for gap in new null message's chunk */
1674 if(oh->chunk[old_chunkno].gap > 0) {
1675 /* Eliminate the gap in the chunk */
1676 if(H5O_eliminate_gap(oh, &curr_chk_dirtied, &oh->mesg[new_null_msg],
1677 ((oh->chunk[old_chunkno].image + oh->chunk[old_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[old_chunkno].gap)),
1678 oh->chunk[old_chunkno].gap) < 0)
1679 HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk")
1680 } /* end if */
1681
1682 /* Release new null message's chunk, marking it dirty */
1683 if(H5O_chunk_unprotect(f, dxpl_id, curr_chk_proxy, curr_chk_dirtied) < 0)
1684 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
1685 curr_chk_proxy = NULL;
1686 curr_chk_dirtied = FALSE;
1687 } /* end else */
1688
1689 /* Indicate that we packed messages */
1690 packed_msg = TRUE;
1691
1692 /* Break out of loop */
1693 /* (If it's possible to move message to even earlier chunk
1694 * we'll get it on the next pass - QAK)
1695 */
1696 break;
1697 } /* end if */
1698 } /* end for */
1699 } /* end if */
1700
1701 /* If we packed messages, get out of loop and start over */
1702 /* (Don't know if this has any benefit one way or the other -QAK) */
1703 if(packed_msg)
1704 break;
1705 } /* end else */
1706 } /* end for */
1707
1708 /* If we did any packing, remember that */
1709 if(packed_msg)
1710 did_packing = TRUE;
1711 } while(packed_msg);
1712
1713 /* Set return value */
1714 ret_value = (htri_t)did_packing;
1715
1716 done:
1717 if(null_chk_proxy && H5O_chunk_unprotect(f, dxpl_id, null_chk_proxy, null_chk_dirtied) < 0)
1718 HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect null object header chunk")
1719 if(curr_chk_proxy && H5O_chunk_unprotect(f, dxpl_id, curr_chk_proxy, curr_chk_dirtied) < 0)
1720 HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect current object header chunk")
1721
1722 FUNC_LEAVE_NOAPI(ret_value)
1723 } /* H5O_move_msgs_forward() */
1724
1725
1726 /*-------------------------------------------------------------------------
1727 *
1728 * Function: H5O_merge_null
1729 *
1730 * Purpose: Merge neighboring null messages in an object header
1731 *
1732 * Return: Non-negative on success/Negative on failure
1733 *
1734 * Programmer: Quincey Koziol
1735 * koziol@ncsa.uiuc.edu
1736 * Oct 10 2005
1737 *
1738 *-------------------------------------------------------------------------
1739 */
1740 static htri_t
H5O_merge_null(H5F_t * f,hid_t dxpl_id,H5O_t * oh)1741 H5O_merge_null(H5F_t *f, hid_t dxpl_id, H5O_t *oh)
1742 {
1743 hbool_t merged_msg; /* Flag to indicate that messages were merged */
1744 hbool_t did_merging = FALSE; /* Whether any messages were merged */
1745 htri_t ret_value; /* Return value */
1746
1747 FUNC_ENTER_NOAPI_NOINIT
1748
1749 /* check args */
1750 HDassert(oh != NULL);
1751
1752 /* Loop until no messages merged */
1753 /* (Double loop is not very efficient, but it would be some extra work to add
1754 * a list of messages to each chunk -QAK)
1755 */
1756 do {
1757 H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */
1758 unsigned u; /* Local index variable */
1759
1760 /* Reset merged messages flag */
1761 merged_msg = FALSE;
1762
1763 /* Scan messages for adjacent null messages & merge them */
1764 for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
1765 if(H5O_NULL_ID == curr_msg->type->id) {
1766 H5O_mesg_t *curr_msg2; /* Pointer to current message to operate on */
1767 unsigned v; /* Local index variable */
1768
1769 /* Should be no gaps in chunk with null message */
1770 HDassert(oh->chunk[curr_msg->chunkno].gap == 0);
1771
1772 /* Loop over messages again, looking for null message in same chunk */
1773 for(v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++) {
1774 if(u != v && H5O_NULL_ID == curr_msg2->type->id && curr_msg->chunkno == curr_msg2->chunkno) {
1775 ssize_t adj_raw; /* Amount to adjust raw message pointer */
1776 size_t adj_raw_size; /* Amount to adjust raw message size */
1777
1778 /* Check for second message after first message */
1779 if((curr_msg->raw + curr_msg->raw_size) == (curr_msg2->raw - H5O_SIZEOF_MSGHDR_OH(oh))) {
1780 /* Extend first null message length to cover second null message */
1781 adj_raw = 0;
1782 adj_raw_size = (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size;
1783
1784 /* Message has been merged */
1785 merged_msg = TRUE;
1786 } /* end if */
1787 /* Check for second message before first message */
1788 else if((curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == (curr_msg2->raw + curr_msg2->raw_size)) {
1789 /* Adjust first message address and extend length to cover second message */
1790 adj_raw = -((ssize_t)((size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size));
1791 adj_raw_size = (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size;
1792
1793 /* Message has been merged */
1794 merged_msg = TRUE;
1795 } /* end if */
1796
1797 /* Second message has been merged, delete it */
1798 if(merged_msg) {
1799 H5O_chunk_proxy_t *curr_chk_proxy; /* Chunk that message is in */
1800
1801 /* Release any information/memory for second message */
1802 H5O_msg_free_mesg(curr_msg2);
1803
1804 /* Protect chunk */
1805 if(NULL == (curr_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno)))
1806 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
1807
1808 /* Adjust first message address and extend length to cover second message */
1809 curr_msg->raw += adj_raw;
1810 curr_msg->raw_size += adj_raw_size;
1811
1812 /* Mark first message as dirty */
1813 curr_msg->dirty = TRUE;
1814
1815 /* Release new null message's chunk, marking it dirty */
1816 if(H5O_chunk_unprotect(f, dxpl_id, curr_chk_proxy, TRUE) < 0)
1817 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
1818
1819 /* Remove second message from list of messages */
1820 if(v < (oh->nmesgs - 1))
1821 HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t));
1822
1823 /* Decrement # of messages */
1824 /* (Don't bother reducing size of message array for now -QAK) */
1825 oh->nmesgs--;
1826
1827 /* If the merged message is too large, shrink the chunk */
1828 if(curr_msg->raw_size >= H5O_MESG_MAX_SIZE)
1829 if(H5O_alloc_shrink_chunk(f, dxpl_id, oh, curr_msg->chunkno) < 0)
1830 HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "unable to shrink chunk")
1831
1832 /* Get out of loop */
1833 break;
1834 } /* end if */
1835 } /* end if */
1836 } /* end for */
1837
1838 /* Get out of loop if we merged messages */
1839 if(merged_msg)
1840 break;
1841 } /* end if */
1842 } /* end for */
1843
1844 /* If we did any merging, remember that */
1845 if(merged_msg)
1846 did_merging = TRUE;
1847 } while(merged_msg);
1848
1849 /* Set return value */
1850 ret_value = (htri_t)did_merging;
1851
1852 done:
1853 FUNC_LEAVE_NOAPI(ret_value)
1854 } /* H5O_merge_null() */
1855
1856
1857 /*-------------------------------------------------------------------------
1858 *
1859 * Function: H5O_remove_empty_chunks
1860 *
1861 * Purpose: Attempt to eliminate empty chunks from object header.
1862 *
1863 * This examines a chunk to see if it's empty
1864 * and removes it (and the continuation message that points to it)
1865 * from the object header.
1866 *
1867 * Return: Non-negative on success/Negative on failure
1868 *
1869 * Programmer: Quincey Koziol
1870 * koziol@ncsa.uiuc.edu
1871 * Oct 17 2005
1872 *
1873 *-------------------------------------------------------------------------
1874 */
1875 static htri_t
H5O_remove_empty_chunks(H5F_t * f,hid_t dxpl_id,H5O_t * oh)1876 H5O_remove_empty_chunks(H5F_t *f, hid_t dxpl_id, H5O_t *oh)
1877 {
1878 hbool_t deleted_chunk; /* Whether to a chunk was deleted */
1879 hbool_t did_deleting = FALSE; /* Whether any chunks were deleted */
1880 htri_t ret_value; /* Return value */
1881
1882 FUNC_ENTER_NOAPI_NOINIT
1883
1884 /* check args */
1885 HDassert(oh != NULL);
1886
1887 /* Loop until no chunks are freed */
1888 do {
1889 H5O_mesg_t *null_msg; /* Pointer to null message found */
1890 H5O_mesg_t *cont_msg; /* Pointer to continuation message found */
1891 unsigned u, v; /* Local index variables */
1892
1893 /* Reset 'chunk deleted' flag */
1894 deleted_chunk = FALSE;
1895
1896 /* Scan messages for null messages that fill an entire chunk */
1897 for(u = 0, null_msg = &oh->mesg[0]; u < oh->nmesgs; u++, null_msg++) {
1898 /* If a null message takes up an entire object header chunk (and
1899 * its not the "base" chunk), delete that chunk from object header
1900 */
1901 if(H5O_NULL_ID == null_msg->type->id && null_msg->chunkno > 0 &&
1902 ((size_t)H5O_SIZEOF_MSGHDR_OH(oh) + null_msg->raw_size)
1903 == (oh->chunk[null_msg->chunkno].size - H5O_SIZEOF_CHKHDR_OH(oh))) {
1904 H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */
1905 unsigned null_msg_no; /* Message # for null message */
1906 unsigned deleted_chunkno; /* Chunk # to delete */
1907
1908 /* Locate continuation message that points to chunk */
1909 for(v = 0, cont_msg = &oh->mesg[0]; v < oh->nmesgs; v++, cont_msg++) {
1910 if(H5O_CONT_ID == cont_msg->type->id) {
1911 /* Decode current continuation message if necessary */
1912 H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, cont_msg, FAIL)
1913
1914 /* Check if the chunkno needs to be set */
1915 /* (should only occur when the continuation message is first decoded) */
1916 if(0 == ((H5O_cont_t *)(cont_msg->native))->chunkno) {
1917 unsigned w; /* Local index variable */
1918
1919 /* Find chunk that this continuation message points to */
1920 for(w = 0; w < oh->nchunks; w++)
1921 if(oh->chunk[w].addr == ((H5O_cont_t *)(cont_msg->native))->addr) {
1922 ((H5O_cont_t *)(cont_msg->native))->chunkno = w;
1923 break;
1924 } /* end if */
1925 HDassert(((H5O_cont_t *)(cont_msg->native))->chunkno > 0);
1926 } /* end if */
1927
1928 /* Check for correct chunk to delete */
1929 if(oh->chunk[null_msg->chunkno].addr == ((H5O_cont_t *)(cont_msg->native))->addr)
1930 break;
1931 } /* end if */
1932 } /* end for */
1933 /* Must be a continuation message that points to chunk containing null message */
1934 HDassert(v < oh->nmesgs);
1935 HDassert(cont_msg);
1936 HDassert(((H5O_cont_t *)(cont_msg->native))->chunkno == null_msg->chunkno);
1937
1938 /* Initialize information about null message */
1939 null_msg_no = u;
1940 deleted_chunkno = null_msg->chunkno;
1941
1942 /* Convert continuation message into a null message */
1943 if(H5O_release_mesg(f, dxpl_id, oh, cont_msg, TRUE) < 0)
1944 HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to convert into null message")
1945
1946 /*
1947 * Remove chunk from object header's data structure
1948 */
1949
1950 /* Free memory for chunk image */
1951 oh->chunk[null_msg->chunkno].image = H5FL_BLK_FREE(chunk_image, oh->chunk[null_msg->chunkno].image);
1952
1953 /* Remove chunk from list of chunks */
1954 if(null_msg->chunkno < (oh->nchunks - 1)) {
1955 HDmemmove(&oh->chunk[null_msg->chunkno], &oh->chunk[null_msg->chunkno + 1], ((oh->nchunks - 1) - null_msg->chunkno) * sizeof(H5O_chunk_t));
1956
1957 /* Adjust chunk number for any chunk proxies that are in the cache */
1958 for(u = null_msg->chunkno; u < (oh->nchunks - 1); u++) {
1959 unsigned chk_proxy_status = 0; /* Metadata cache status of chunk proxy for chunk */
1960
1961 /* Check the chunk proxy's status in the metadata cache */
1962 if(H5AC_get_entry_status(f, oh->chunk[u].addr, &chk_proxy_status) < 0)
1963 HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to check metadata cache status for chunk proxy")
1964
1965 /* If the entry is in the cache, update its chunk index */
1966 if(chk_proxy_status & H5AC_ES__IN_CACHE) {
1967 if(H5O_chunk_update_idx(f, dxpl_id, oh, u) < 0)
1968 HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to update index for chunk proxy")
1969 } /* end if */
1970 } /* end for */
1971 } /* end if */
1972
1973 /* Decrement # of chunks */
1974 /* (Don't bother reducing size of chunk array for now -QAK) */
1975 oh->nchunks--;
1976
1977 /*
1978 * Delete null message (in empty chunk that was be freed) from list of messages
1979 */
1980
1981 /* Release any information/memory for message */
1982 H5O_msg_free_mesg(null_msg);
1983
1984 /* Remove null message from list of messages */
1985 if(null_msg_no < (oh->nmesgs - 1))
1986 HDmemmove(&oh->mesg[null_msg_no], &oh->mesg[null_msg_no + 1], ((oh->nmesgs - 1) - null_msg_no) * sizeof(H5O_mesg_t));
1987
1988 /* Decrement # of messages */
1989 /* (Don't bother reducing size of message array for now -QAK) */
1990 oh->nmesgs--;
1991
1992 /* Adjust chunk # for messages in chunks after deleted chunk */
1993 for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
1994 /* Sanity check - there should be no messages in deleted chunk */
1995 HDassert(curr_msg->chunkno != deleted_chunkno);
1996
1997 /* Adjust chunk index for messages in later chunks */
1998 if(curr_msg->chunkno > deleted_chunkno)
1999 curr_msg->chunkno--;
2000
2001 /* Check for continuation message */
2002 if(H5O_CONT_ID == curr_msg->type->id) {
2003 /* Decode current continuation message if necessary */
2004 H5O_LOAD_NATIVE(f, dxpl_id, 0, oh, curr_msg, FAIL)
2005
2006 /* Check if the chunkno needs to be set */
2007 /* (should only occur when the continuation message is first decoded) */
2008 if(0 == ((H5O_cont_t *)(curr_msg->native))->chunkno) {
2009 unsigned w; /* Local index variable */
2010
2011 /* Find chunk that this continuation message points to */
2012 for(w = 0; w < oh->nchunks; w++)
2013 if(oh->chunk[w].addr == ((H5O_cont_t *)(curr_msg->native))->addr) {
2014 ((H5O_cont_t *)(curr_msg->native))->chunkno = w;
2015 break;
2016 } /* end if */
2017 HDassert(((H5O_cont_t *)(curr_msg->native))->chunkno > 0);
2018 } /* end if */
2019 else {
2020 /* Check for pointer to chunk after deleted chunk */
2021 if(((H5O_cont_t *)(curr_msg->native))->chunkno > deleted_chunkno)
2022 ((H5O_cont_t *)(curr_msg->native))->chunkno--;
2023 } /* end else */
2024 } /* end if */
2025 } /* end for */
2026
2027 /* Found chunk to delete */
2028 deleted_chunk = TRUE;
2029 break;
2030 } /* end if */
2031 } /* end for */
2032
2033 /* If we deleted any chunks, remember that */
2034 if(deleted_chunk)
2035 did_deleting = TRUE;
2036 } while(deleted_chunk);
2037
2038 /* Set return value */
2039 ret_value = (htri_t)did_deleting;
2040
2041 done:
2042 FUNC_LEAVE_NOAPI(ret_value)
2043 } /* H5O_remove_empty_chunks() */
2044
2045
2046 /*-------------------------------------------------------------------------
2047 *
2048 * Function: H5O_condense_header
2049 *
2050 * Purpose: Attempt to eliminate empty chunks from object header.
2051 *
2052 * Return: Non-negative on success/Negative on failure
2053 *
2054 * Programmer: Quincey Koziol
2055 * koziol@ncsa.uiuc.edu
2056 * Oct 4 2005
2057 *
2058 * Modifications:
2059 * Feb. 2009: Vailin Choi
2060 * Add 2 more parameters to H5O_move_msgs_forward() for moving
2061 * messages forward into "continuation" message
2062 *
2063 *-------------------------------------------------------------------------
2064 */
2065 herr_t
H5O_condense_header(H5F_t * f,H5O_t * oh,hid_t dxpl_id)2066 H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id)
2067 {
2068 hbool_t rescan_header; /* Whether to rescan header */
2069 htri_t result; /* Result from packing/merging/etc */
2070 herr_t ret_value = SUCCEED; /* return value */
2071
2072 FUNC_ENTER_NOAPI(FAIL)
2073
2074 /* check args */
2075 HDassert(oh != NULL);
2076
2077 /* Loop until no changed to the object header messages & chunks */
2078 do {
2079 /* Reset 'rescan chunks' flag */
2080 rescan_header = FALSE;
2081
2082 /* Scan for messages that can be moved earlier in chunks */
2083 result = H5O_move_msgs_forward(f, dxpl_id, oh);
2084 if(result < 0)
2085 HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't move header messages forward")
2086 if(result > 0)
2087 rescan_header = TRUE;
2088
2089 /* Scan for adjacent null messages & merge them */
2090 result = H5O_merge_null(f, dxpl_id, oh);
2091 if(result < 0)
2092 HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack null header messages")
2093 if(result > 0)
2094 rescan_header = TRUE;
2095
2096 /* Scan for empty chunks to remove */
2097 result = H5O_remove_empty_chunks(f, dxpl_id, oh);
2098 if(result < 0)
2099 HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't remove empty chunk")
2100 if(result > 0)
2101 rescan_header = TRUE;
2102 } while(rescan_header);
2103 #ifdef H5O_DEBUG
2104 H5O_assert(oh);
2105 #endif /* H5O_DEBUG */
2106
2107 done:
2108 FUNC_LEAVE_NOAPI(ret_value)
2109 } /* H5O_condense_header() */
2110
2111
2112 /*-------------------------------------------------------------------------
2113 *
2114 * Function: H5O_alloc_shrink_chunk
2115 *
2116 * Purpose: Shrinks a chunk, removing all null messages and any gap.
2117 *
2118 * Return: Non-negative on success/Negative on failure
2119 *
2120 * Programmer: Neil Fortner
2121 * nfortne2@hdfgroup.org
2122 * Oct 20 2008
2123 *
2124 *-------------------------------------------------------------------------
2125 */
2126 static herr_t
H5O_alloc_shrink_chunk(H5F_t * f,hid_t dxpl_id,H5O_t * oh,unsigned chunkno)2127 H5O_alloc_shrink_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned chunkno)
2128 {
2129 H5O_chunk_t *chunk = &oh->chunk[chunkno]; /* Chunk to shrink */
2130 H5O_chunk_proxy_t *chk_proxy = NULL; /* Metadata cache proxy for chunk to shrink */
2131 H5O_mesg_t *curr_msg; /* Current message to examine */
2132 uint8_t *old_image = chunk->image; /* Old address of chunk's image in memory */
2133 size_t old_size = chunk->size; /* Old size of chunk */
2134 size_t new_size = chunk->size - chunk->gap; /* Size of shrunk chunk */
2135 size_t total_msg_size; /* Size of the messages in this chunk */
2136 size_t min_chunk_size = H5O_ALIGN_OH(oh, H5O_MIN_SIZE); /* Minimum chunk size */
2137 size_t sizeof_chksum = H5O_SIZEOF_CHKSUM_OH(oh); /* Size of chunk checksum */
2138 size_t sizeof_msghdr = H5O_SIZEOF_MSGHDR_OH(oh); /* Size of message header */
2139 uint8_t new_size_flags = 0; /* New chunk #0 size flags */
2140 hbool_t adjust_size_flags = FALSE; /* Whether to adjust the chunk #0 size flags */
2141 size_t less_prfx_size = 0; /* Bytes removed from object header prefix */
2142 size_t u; /* Index */
2143 herr_t ret_value = SUCCEED; /* Return value */
2144
2145 FUNC_ENTER_NOAPI_NOINIT
2146
2147 /* check args */
2148 HDassert(f);
2149 HDassert(oh);
2150
2151 /* Protect chunk */
2152 if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, chunkno)))
2153 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk")
2154
2155 /* Loop backwards to increase the chance of seeing more null messages at the
2156 * end of the chunk. Note that we rely on unsigned u wrapping around at the
2157 * end.
2158 */
2159 for(u = oh->nmesgs - 1, curr_msg = &oh->mesg[u]; u < oh->nmesgs; u--, curr_msg--) {
2160 if((H5O_NULL_ID == curr_msg->type->id) && (chunkno == curr_msg->chunkno)) {
2161 size_t shrink_size = curr_msg->raw_size + sizeof_msghdr; /* Amount to shrink the chunk by */
2162
2163 /* If the current message is not at the end of the chunk, copy the
2164 * data after it (except the checksum).
2165 */
2166 if(curr_msg->raw + curr_msg->raw_size
2167 < old_image + new_size - sizeof_chksum) {
2168 unsigned v; /* Index */
2169 H5O_mesg_t *curr_msg2;
2170 uint8_t *src = curr_msg->raw + curr_msg->raw_size; /* Source location */
2171
2172 /* Slide down the raw data */
2173 HDmemmove(curr_msg->raw - sizeof_msghdr, src,
2174 (size_t)(old_image + new_size - sizeof_chksum - src));
2175
2176 /* Update the raw data pointers for messages after this one */
2177 for(v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++)
2178 if((chunkno == curr_msg2->chunkno) && (curr_msg2->raw > curr_msg->raw))
2179 curr_msg2->raw -= shrink_size;
2180 } /* end if */
2181
2182 /* Adjust the new chunk size */
2183 new_size -= shrink_size;
2184
2185 /* Release any information/memory for the message */
2186 H5O_msg_free_mesg(curr_msg);
2187
2188 /* Remove the deleted null message from list of messages */
2189 if(u < (oh->nmesgs - 1))
2190 HDmemmove(&oh->mesg[u], &oh->mesg[u+1], ((oh->nmesgs - 1) - u) * sizeof(H5O_mesg_t));
2191
2192 /* Decrement # of messages */
2193 /* (Don't bother reducing size of message array for now) */
2194 oh->nmesgs--;
2195 } /* end if */
2196 } /* end for */
2197
2198 /* Check if the chunk is too small, extend if necessary */
2199 total_msg_size = new_size - (size_t)(chunkno == 0 ? H5O_SIZEOF_HDR(oh) : H5O_SIZEOF_CHKHDR_OH(oh));
2200 if(total_msg_size < min_chunk_size) {
2201 HDassert(oh->alloc_nmesgs > oh->nmesgs);
2202 oh->nmesgs++;
2203
2204 /* Initialize new null message to make the chunk large enough */
2205 oh->mesg[oh->nmesgs].type = H5O_MSG_NULL;
2206 oh->mesg[oh->nmesgs].dirty = TRUE;
2207 oh->mesg[oh->nmesgs].native = NULL;
2208 oh->mesg[oh->nmesgs].raw = old_image + new_size + sizeof_msghdr - sizeof_chksum;
2209 oh->mesg[oh->nmesgs].raw_size = MAX(H5O_ALIGN_OH(oh, min_chunk_size - total_msg_size),
2210 sizeof_msghdr) - sizeof_msghdr;
2211 oh->mesg[oh->nmesgs].chunkno = chunkno;
2212
2213 /* update the new chunk size */
2214 new_size += oh->mesg[oh->nmesgs].raw_size + sizeof_msghdr;
2215 } /* end if */
2216
2217 /* Check for changing the chunk #0 data size enough to need adjusting the flags */
2218 if(oh->version > H5O_VERSION_1 && chunkno == 0) {
2219 uint64_t chunk0_newsize = new_size - (size_t)H5O_SIZEOF_HDR(oh); /* New size of chunk 0's data */
2220 size_t orig_prfx_size = (size_t)1 << (oh->flags & H5O_HDR_CHUNK0_SIZE); /* Original prefix size */
2221
2222 /* Check for moving to a 1-byte size encoding */
2223 if(orig_prfx_size > 1 && chunk0_newsize <= 255) {
2224 less_prfx_size = orig_prfx_size - 1;
2225 new_size_flags = H5O_HDR_CHUNK0_1;
2226 adjust_size_flags = TRUE;
2227 } /* end if */
2228 /* Check for moving to a 2-byte size encoding */
2229 else if(orig_prfx_size > 2 && chunk0_newsize <= 65535) {
2230 less_prfx_size = orig_prfx_size - 2;
2231 new_size_flags = H5O_HDR_CHUNK0_2;
2232 adjust_size_flags = TRUE;
2233 } /* end if */
2234 /* Check for moving to a 4-byte size encoding */
2235 else if(orig_prfx_size > 4 && chunk0_newsize <= 4294967295) {
2236 less_prfx_size = orig_prfx_size - 4;
2237 new_size_flags = H5O_HDR_CHUNK0_4;
2238 adjust_size_flags = TRUE;
2239 } /* end if */
2240 } /* end if */
2241
2242 if(adjust_size_flags) {
2243 /* Adjust object header prefix flags */
2244 oh->flags = (uint8_t)(oh->flags & ~H5O_HDR_CHUNK0_SIZE);
2245 oh->flags |= new_size_flags;
2246
2247 /* Slide chunk 0 data down */
2248 HDmemmove(chunk->image + H5O_SIZEOF_HDR(oh) - sizeof_chksum,
2249 chunk->image + H5O_SIZEOF_HDR(oh) - sizeof_chksum + less_prfx_size,
2250 new_size - (size_t)H5O_SIZEOF_HDR(oh));
2251
2252 /* Adjust chunk size */
2253 new_size -= less_prfx_size;
2254 } /* end if */
2255
2256 /* Allocate less memory space for chunk's image */
2257 chunk->size = new_size;
2258 chunk->image = H5FL_BLK_REALLOC(chunk_image, old_image, chunk->size);
2259 chunk->gap = 0;
2260 if(NULL == oh->chunk[chunkno].image)
2261 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
2262
2263 /* Spin through existing messages, adjusting them */
2264 for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
2265 if(adjust_size_flags || (chunk->image != old_image))
2266 /* Adjust raw addresses for messages in this chunk to reflect new 'image' address */
2267 if(curr_msg->chunkno == chunkno)
2268 curr_msg->raw = chunk->image - less_prfx_size + (curr_msg->raw - old_image);
2269
2270 /* Find continuation message which points to this chunk and adjust chunk's size */
2271 /* (Chunk 0 doesn't have a continuation message that points to it and
2272 * its size is directly encoded in the object header) */
2273 if(chunkno > 0 && (H5O_CONT_ID == curr_msg->type->id) &&
2274 (((H5O_cont_t *)(curr_msg->native))->chunkno == chunkno)) {
2275 H5O_chunk_proxy_t *cont_chk_proxy; /* Chunk that message is in */
2276
2277 /* Protect chunk */
2278 if(NULL == (cont_chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, curr_msg->chunkno)))
2279 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header chunk")
2280
2281 /* Adjust size of continuation message */
2282 HDassert(((H5O_cont_t *)(curr_msg->native))->size == old_size);
2283 ((H5O_cont_t *)(curr_msg->native))->size = chunk->size;
2284
2285 /* Flag continuation message as dirty */
2286 curr_msg->dirty = TRUE;
2287
2288 /* Release chunk, marking it dirty */
2289 if(H5O_chunk_unprotect(f, dxpl_id, cont_chk_proxy, TRUE) < 0)
2290 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
2291 } /* end if */
2292 } /* end for */
2293
2294 HDassert(new_size <= old_size);
2295
2296 /* Resize the chunk in the cache */
2297 if(H5O_chunk_resize(oh, chk_proxy) < 0)
2298 HGOTO_ERROR(H5E_OHDR, H5E_CANTRESIZE, FAIL, "unable to resize object header chunk")
2299
2300 /* Free the unused space in the file */
2301 if(H5MF_xfree(f, H5FD_MEM_OHDR, dxpl_id, chunk->addr + new_size, (hsize_t)(old_size - new_size)) < 0)
2302 HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to shrink object header chunk")
2303
2304 done:
2305 /* Release chunk, marking it dirty */
2306 if(chk_proxy && H5O_chunk_unprotect(f, dxpl_id, chk_proxy, TRUE) < 0)
2307 HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
2308
2309 FUNC_LEAVE_NOAPI(ret_value)
2310 } /* H5O_alloc_shrink_chunk() */
2311
2312