1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /*-------------------------------------------------------------------------
15  *
16  * Created:     H5HFtiny.c
17  *              Aug 14 2006
18  *              Quincey Koziol <koziol@hdfgroup.org>
19  *
20  * Purpose:     Routines for "tiny" objects in fractal heap
21  *
22  *-------------------------------------------------------------------------
23  */
24 
25 /****************/
26 /* Module Setup */
27 /****************/
28 
29 #include "H5HFmodule.h"         /* This source code file is part of the H5HF module */
30 
31 
32 /***********/
33 /* Headers */
34 /***********/
35 #include "H5private.h"      /* Generic Functions        */
36 #include "H5Eprivate.h"     /* Error handling           */
37 #include "H5HFpkg.h"        /* Fractal heaps            */
38 
39 
40 /****************/
41 /* Local Macros */
42 /****************/
43 
44 /* Tiny object length information */
45 #define H5HF_TINY_LEN_SHORT     16          /* Max. length able to be encoded in first heap ID byte */
46 #define H5HF_TINY_MASK_SHORT    0x0F        /* Mask for length in first heap ID byte                */
47 #define H5HF_TINY_MASK_EXT      0x0FFF      /* Mask for length in two heap ID bytes                 */
48 #define H5HF_TINY_MASK_EXT_1    0x0F00      /* Mask for length in first byte of two heap ID bytes   */
49 #define H5HF_TINY_MASK_EXT_2    0x00FF      /* Mask for length in second byte of two heap ID bytes  */
50 
51 
52 /******************/
53 /* Local Typedefs */
54 /******************/
55 
56 
57 /********************/
58 /* Package Typedefs */
59 /********************/
60 
61 
62 /********************/
63 /* Local Prototypes */
64 /********************/
65 static herr_t H5HF_tiny_op_real(H5HF_hdr_t *hdr, const uint8_t *id,
66     H5HF_operator_t op, void *op_data);
67 
68 
69 /*********************/
70 /* Package Variables */
71 /*********************/
72 
73 
74 /*****************************/
75 /* Library Private Variables */
76 /*****************************/
77 
78 
79 /*******************/
80 /* Local Variables */
81 /*******************/
82 
83 
84 /*-------------------------------------------------------------------------
85  * Function:    H5HF_tiny_init
86  *
87  * Purpose:     Initialize information for tracking 'tiny' objects
88  *
89  * Return:      SUCCEED/FAIL
90  *
91  * Programmer:  Quincey Koziol
92  *              koziol@hdfgroup.org
93  *              Aug 14 2006
94  *
95  *-------------------------------------------------------------------------
96  */
97 herr_t
H5HF_tiny_init(H5HF_hdr_t * hdr)98 H5HF_tiny_init(H5HF_hdr_t *hdr)
99 {
100     FUNC_ENTER_NOAPI_NOINIT_NOERR
101 
102     /*
103      * Check arguments.
104      */
105     HDassert(hdr);
106 
107     /* Compute information about 'tiny' objects for the heap */
108 
109     /* Check if tiny objects need an extra byte for their length */
110     /* (account for boundary condition when length of an object would need an
111      *  extra byte, but using that byte means that the extra length byte is
112      *  unneccessary)
113      */
114     if((hdr->id_len - 1) <= H5HF_TINY_LEN_SHORT) {
115         hdr->tiny_max_len = hdr->id_len - 1;
116         hdr->tiny_len_extended = FALSE;
117     } /* end if */
118     else if((hdr->id_len - 1) == (H5HF_TINY_LEN_SHORT + 1)) {
119         hdr->tiny_max_len = H5HF_TINY_LEN_SHORT;
120         hdr->tiny_len_extended = FALSE;
121     } /* end if */
122     else {
123         hdr->tiny_max_len = hdr->id_len - 2;
124         hdr->tiny_len_extended = TRUE;
125     } /* end else */
126 
127     FUNC_LEAVE_NOAPI(SUCCEED)
128 } /* end H5HF_tiny_init() */
129 
130 
131 /*-------------------------------------------------------------------------
132  * Function:    H5HF_tiny_insert
133  *
134  * Purpose:     Pack a 'tiny' object in a heap ID
135  *
136  * Return:      SUCCEED/FAIL
137  *
138  * Programmer:  Quincey Koziol
139  *              koziol@hdfgroup.org
140  *              Aug 14 2006
141  *
142  *-------------------------------------------------------------------------
143  */
144 herr_t
H5HF_tiny_insert(H5HF_hdr_t * hdr,size_t obj_size,const void * obj,void * _id)145 H5HF_tiny_insert(H5HF_hdr_t *hdr, size_t obj_size, const void *obj, void *_id)
146 {
147     uint8_t *id = (uint8_t *)_id;       /* Pointer to ID buffer */
148     size_t enc_obj_size;                /* Encoded object size */
149     herr_t ret_value = SUCCEED;         /* Return value */
150 
151     FUNC_ENTER_NOAPI_NOINIT
152 #ifdef QAK
153 HDfprintf(stderr, "%s: obj_size = %Zu\n", FUNC, obj_size);
154 #endif /* QAK */
155 
156     /*
157      * Check arguments.
158      */
159     HDassert(hdr);
160     HDassert(obj_size <= hdr->tiny_max_len);
161     HDassert(obj_size <= (H5HF_TINY_MASK_EXT + 1));
162     HDassert(obj);
163     HDassert(id);
164 
165     /* Adjust object's size for encoding it */
166     enc_obj_size = obj_size - 1;
167 
168     /* Encode object into ID */
169     if(!hdr->tiny_len_extended) {
170         *id++ = (uint8_t)(H5HF_ID_VERS_CURR | H5HF_ID_TYPE_TINY |
171                 (enc_obj_size & H5HF_TINY_MASK_SHORT));
172     } /* end if */
173     else {
174         *id++ = (uint8_t)(H5HF_ID_VERS_CURR | H5HF_ID_TYPE_TINY |
175                 ((enc_obj_size & H5HF_TINY_MASK_EXT_1) >> 8));
176         *id++ = enc_obj_size & H5HF_TINY_MASK_EXT_2;
177     } /* end else */
178 
179     HDmemcpy(id, obj, obj_size);
180     HDmemset(id + obj_size, 0, (hdr->id_len - ((size_t)1 + (size_t)hdr->tiny_len_extended + obj_size)));
181 
182     /* Update statistics about heap */
183     hdr->tiny_size += obj_size;
184     hdr->tiny_nobjs++;
185 
186     /* Mark heap header as modified */
187     if(H5HF_hdr_dirty(hdr) < 0)
188         HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
189 
190 done:
191     FUNC_LEAVE_NOAPI(ret_value)
192 } /* end H5HF_tiny_insert() */
193 
194 
195 /*-------------------------------------------------------------------------
196  * Function:    H5HF_tiny_get_obj_len
197  *
198  * Purpose:     Get the size of a 'tiny' object in a fractal heap
199  *
200  * Return:      SUCCEED (Can't fail)
201  *
202  * Programmer:  Quincey Koziol
203  *              koziol@hdfgroup.org
204  *              Aug 14 2006
205  *
206  *-------------------------------------------------------------------------
207  */
208 herr_t
H5HF_tiny_get_obj_len(H5HF_hdr_t * hdr,const uint8_t * id,size_t * obj_len_p)209 H5HF_tiny_get_obj_len(H5HF_hdr_t *hdr, const uint8_t *id, size_t *obj_len_p)
210 {
211     size_t enc_obj_size;                /* Encoded object size */
212 
213     FUNC_ENTER_NOAPI_NOINIT_NOERR
214 
215     /*
216      * Check arguments.
217      */
218     HDassert(hdr);
219     HDassert(id);
220     HDassert(obj_len_p);
221 
222     /* Check if 'tiny' object ID is in extended form, and retrieve encoded size */
223     if(!hdr->tiny_len_extended)
224         enc_obj_size = *id & H5HF_TINY_MASK_SHORT;
225     else
226         /* (performed in this odd way to avoid compiler bug on tg-login3 with
227          *  gcc 3.2.2 - QAK)
228          */
229         enc_obj_size = (size_t)*(id + 1) | ((size_t)(*id & H5HF_TINY_MASK_EXT_1) << 8);
230 
231     /* Set the object's length */
232     *obj_len_p = enc_obj_size + 1;
233 
234     FUNC_LEAVE_NOAPI(SUCCEED)
235 } /* end H5HF_tiny_get_obj_len() */
236 
237 
238 /*-------------------------------------------------------------------------
239  * Function:    H5HF_tiny_op_real
240  *
241  * Purpose:     Internal routine to perform operation on 'tiny' object
242  *
243  * Return:      SUCCEED/FAIL
244  *
245  * Programmer:  Quincey Koziol
246  *              koziol@hdfgroup.org
247  *              Sep 11 2006
248  *
249  *-------------------------------------------------------------------------
250  */
251 static herr_t
H5HF_tiny_op_real(H5HF_hdr_t * hdr,const uint8_t * id,H5HF_operator_t op,void * op_data)252 H5HF_tiny_op_real(H5HF_hdr_t *hdr, const uint8_t *id, H5HF_operator_t op,
253     void *op_data)
254 {
255     size_t enc_obj_size;                /* Encoded object size */
256     herr_t ret_value = SUCCEED;         /* Return value */
257 
258     FUNC_ENTER_NOAPI_NOINIT
259 
260     /*
261      * Check arguments.
262      */
263     HDassert(hdr);
264     HDassert(id);
265     HDassert(op);
266 
267     /* Get the object's encoded length */
268     /* H5HF_tiny_obj_len can't fail */
269     ret_value = H5HF_tiny_get_obj_len(hdr, id, &enc_obj_size);
270 
271     /* Advance past flag byte(s) */
272     if(!hdr->tiny_len_extended)
273         id++;
274     else {
275         /* (performed in two steps to avoid compiler bug on tg-login3 with
276          *  gcc 3.2.2 - QAK)
277          */
278         id++; id++;
279     }
280 
281     /* Call the user's 'op' callback */
282     if(op(id, enc_obj_size, op_data) < 0)
283         HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "application's callback failed")
284 
285 done:
286     FUNC_LEAVE_NOAPI(ret_value)
287 } /* end H5HF_tiny_op_real() */
288 
289 
290 /*-------------------------------------------------------------------------
291  * Function:    H5HF_tiny_read
292  *
293  * Purpose:     Read a 'tiny' object from the heap
294  *
295  * Return:      SUCCEED/FAIL
296  *
297  * Programmer:  Quincey Koziol
298  *              koziol@hdfgroup.org
299  *              Aug  8 2006
300  *
301  *-------------------------------------------------------------------------
302  */
303 herr_t
H5HF_tiny_read(H5HF_hdr_t * hdr,const uint8_t * id,void * obj)304 H5HF_tiny_read(H5HF_hdr_t *hdr, const uint8_t *id, void *obj)
305 {
306     herr_t ret_value = SUCCEED;         /* Return value */
307 
308     FUNC_ENTER_NOAPI_NOINIT
309 
310     /*
311      * Check arguments.
312      */
313     HDassert(hdr);
314     HDassert(id);
315     HDassert(obj);
316 
317     /* Call the internal 'op' routine */
318     if(H5HF_tiny_op_real(hdr, id, H5HF_op_read, obj) < 0)
319         HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object")
320 
321 done:
322     FUNC_LEAVE_NOAPI(ret_value)
323 } /* end H5HF_tiny_read() */
324 
325 
326 /*-------------------------------------------------------------------------
327  * Function:    H5HF_tiny_op
328  *
329  * Purpose:     Operate directly on a 'tiny' object
330  *
331  * Return:      SUCCEED/FAIL
332  *
333  * Programmer:  Quincey Koziol
334  *              koziol@hdfgroup.org
335  *              Sept 11 2006
336  *
337  *-------------------------------------------------------------------------
338  */
339 herr_t
H5HF_tiny_op(H5HF_hdr_t * hdr,const uint8_t * id,H5HF_operator_t op,void * op_data)340 H5HF_tiny_op(H5HF_hdr_t *hdr, const uint8_t *id, H5HF_operator_t op,
341     void *op_data)
342 {
343     herr_t ret_value = SUCCEED;         /* Return value */
344 
345     FUNC_ENTER_NOAPI_NOINIT
346 
347     /*
348      * Check arguments.
349      */
350     HDassert(hdr);
351     HDassert(id);
352     HDassert(op);
353 
354     /* Call the internal 'op' routine routine */
355     if(H5HF_tiny_op_real(hdr, id, op, op_data) < 0)
356         HGOTO_ERROR(H5E_HEAP, H5E_CANTOPERATE, FAIL, "unable to operate on heap object")
357 
358 done:
359     FUNC_LEAVE_NOAPI(ret_value)
360 } /* end H5HF_tiny_op() */
361 
362 
363 /*-------------------------------------------------------------------------
364  * Function:    H5HF_tiny_remove
365  *
366  * Purpose:     Remove a 'tiny' object from the heap statistics
367  *
368  * Return:      SUCCEED/FAIL
369  *
370  * Programmer:  Quincey Koziol
371  *              koziol@hdfgroup.org
372  *              Aug 14 2006
373  *
374  *-------------------------------------------------------------------------
375  */
376 herr_t
H5HF_tiny_remove(H5HF_hdr_t * hdr,const uint8_t * id)377 H5HF_tiny_remove(H5HF_hdr_t *hdr, const uint8_t *id)
378 {
379     size_t enc_obj_size;                /* Encoded object size */
380     herr_t ret_value = SUCCEED;         /* Return value */
381 
382     FUNC_ENTER_NOAPI_NOINIT
383 
384     /*
385      * Check arguments.
386      */
387     HDassert(hdr);
388     HDassert(id);
389 
390     /* Get the object's encoded length */
391     /* H5HF_tiny_obj_len can't fail */
392     ret_value = H5HF_tiny_get_obj_len(hdr, id, &enc_obj_size);
393 
394     /* Update statistics about heap */
395     hdr->tiny_size -= enc_obj_size;
396     hdr->tiny_nobjs--;
397 
398     /* Mark heap header as modified */
399     if(H5HF_hdr_dirty(hdr) < 0)
400         HGOTO_ERROR(H5E_HEAP, H5E_CANTDIRTY, FAIL, "can't mark heap header as dirty")
401 
402 done:
403     FUNC_LEAVE_NOAPI(ret_value)
404 } /* end H5HF_tiny_remove() */
405