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