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 /* Module Setup */
16 /****************/
17 
18 #define H5O_FRIEND		/*suppress error about including H5Opkg	  */
19 #include "H5SMmodule.h"         /* This source code file is part of the H5SM module */
20 
21 
22 /***********/
23 /* Headers */
24 /***********/
25 #include "H5private.h"		/* Generic Functions			*/
26 #include "H5Eprivate.h"		/* Error handling		  	*/
27 #include "H5Fprivate.h"		/* File access                          */
28 #include "H5FLprivate.h"	/* Free Lists                           */
29 #include "H5MFprivate.h"        /* File memory management		*/
30 #include "H5MMprivate.h"	/* Memory management			*/
31 #include "H5Opkg.h"             /* Object Headers                       */
32 #include "H5SMpkg.h"            /* Shared object header messages        */
33 
34 
35 /****************/
36 /* Local Macros */
37 /****************/
38 
39 
40 /******************/
41 /* Local Typedefs */
42 /******************/
43 
44 /* Udata struct for calls to H5SM_read_iter_op */
45 typedef struct H5SM_read_udata_t {
46     H5F_t *file;                    /* File in which sharing is happening (in) */
47     H5O_msg_crt_idx_t idx;          /* Creation index of this message (in) */
48     size_t buf_size;                /* Size of the encoded message (out) */
49     void *encoding_buf;             /* The encoded message (out) */
50 } H5SM_read_udata_t;
51 
52 
53 /********************/
54 /* Local Prototypes */
55 /********************/
56 static herr_t H5SM_create_index(H5F_t *f, H5SM_index_header_t *header,
57                                 hid_t dxpl_id);
58 static herr_t H5SM_delete_index(H5F_t *f, H5SM_index_header_t *header,
59                                 hid_t dxpl_id, hbool_t delete_heap);
60 static haddr_t H5SM_create_list(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id);
61 static herr_t H5SM__find_in_list(const H5SM_list_t *list, const H5SM_mesg_key_t *key,
62                                 size_t *empty_pos, size_t *list_pos);
63 static herr_t H5SM_convert_list_to_btree(H5F_t * f, H5SM_index_header_t * header,
64                 H5SM_list_t **_list, H5HF_t *fheap, H5O_t *open_oh, hid_t dxpl_id);
65 static herr_t H5SM_convert_btree_to_list(H5F_t * f, H5SM_index_header_t * header, hid_t dxpl_id);
66 static herr_t H5SM_incr_ref(void *record, void *_op_data, hbool_t *changed);
67 static herr_t H5SM_write_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
68     H5SM_index_header_t *header, hbool_t defer, unsigned type_id, void *mesg,
69     unsigned *cache_flags_ptr);
70 static herr_t H5SM_decr_ref(void *record, void *op_data, hbool_t *changed);
71 static herr_t H5SM_delete_from_index(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
72     H5SM_index_header_t *header, const H5O_shared_t * mesg,
73     unsigned *cache_flags, void ** /*out*/ encoded_mesg);
74 static herr_t H5SM_type_to_flag(unsigned type_id, unsigned *type_flag);
75 static herr_t H5SM_read_iter_op(H5O_t *oh, H5O_mesg_t *mesg, unsigned sequence,
76     unsigned *oh_modified, void *_udata);
77 static herr_t H5SM_read_mesg_fh_cb(const void *obj, size_t obj_len, void *_udata);
78 static herr_t H5SM_read_mesg(H5F_t *f, const H5SM_sohm_t *mesg, H5HF_t *fheap,
79                H5O_t * open_oh, hid_t dxpl_id, size_t *encoding_size /*out*/,
80                void ** encoded_mesg /*out*/);
81 
82 
83 /*********************/
84 /* Package Variables */
85 /*********************/
86 
87 /* Package initialization variable */
88 hbool_t H5_PKG_INIT_VAR = FALSE;
89 
90 H5FL_DEFINE(H5SM_master_table_t);
91 H5FL_ARR_DEFINE(H5SM_index_header_t, H5O_SHMESG_MAX_NINDEXES);
92 H5FL_DEFINE(H5SM_list_t);
93 H5FL_ARR_DEFINE(H5SM_sohm_t, H5O_SHMESG_MAX_LIST_SIZE);
94 
95 
96 /*****************************/
97 /* Library Private Variables */
98 /*****************************/
99 
100 
101 /*******************/
102 /* Local Variables */
103 /*******************/
104 
105 
106 
107 /*-------------------------------------------------------------------------
108  * Function:    H5SM_init
109  *
110  * Purpose:     Initializes the Shared Message interface.
111  *
112  *              Creates a master SOHM table in the file and in the cache.
113  *              This function should not be called for files that have
114  *              SOHMs disabled in the FCPL.
115  *
116  * Return:      Non-negative on success/Negative on failure
117  *
118  * Programmer:  James Laird
119  *              Tuesday, May 2, 2006
120  *
121  *-------------------------------------------------------------------------
122  */
123 herr_t
H5SM_init(H5F_t * f,H5P_genplist_t * fc_plist,const H5O_loc_t * ext_loc,hid_t dxpl_id)124 H5SM_init(H5F_t *f, H5P_genplist_t * fc_plist, const H5O_loc_t *ext_loc, hid_t dxpl_id)
125 {
126     H5O_shmesg_table_t sohm_table;      /* SOHM message for superblock extension */
127     H5SM_master_table_t *table = NULL;  /* SOHM master table for file */
128     H5P_genplist_t *dxpl = NULL;        /* DXPL for setting ring */
129     H5AC_ring_t ring, orig_ring = H5AC_RING_INV;      /* Original ring value */
130     haddr_t table_addr = HADDR_UNDEF;   /* Address of SOHM master table in file */
131     unsigned list_max, btree_min;       /* Phase change limits for SOHM indices */
132     unsigned index_type_flags[H5O_SHMESG_MAX_NINDEXES]; /* Messages types stored in each index */
133     unsigned minsizes[H5O_SHMESG_MAX_NINDEXES]; /* Message size sharing threshhold for each index */
134     unsigned type_flags_used;           /* Message type flags used, for sanity checking */
135     unsigned x;                         /* Local index variable */
136     herr_t ret_value = SUCCEED;         /* Return value */
137 
138     FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
139 
140     HDassert(f);
141     /* File should not already have a SOHM table */
142     HDassert(!H5F_addr_defined(H5F_SOHM_ADDR(f)));
143 
144     /* Set the ring type in the DXPL */
145     if(H5AC_set_ring(dxpl_id, H5AC_RING_USER, &dxpl, &orig_ring) < 0)
146         HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "unable to set ring value")
147 
148     /* Initialize master table */
149     if(NULL == (table = H5FL_CALLOC(H5SM_master_table_t)))
150 	HGOTO_ERROR(H5E_SOHM, H5E_CANTALLOC, FAIL, "memory allocation failed for SOHM table")
151     table->num_indexes = H5F_SOHM_NINDEXES(f);
152     table->table_size = H5SM_TABLE_SIZE(f);
153 
154     /* Get information from fcpl */
155     if(H5P_get(fc_plist, H5F_CRT_SHMSG_INDEX_TYPES_NAME, &index_type_flags) < 0)
156         HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get SOHM type flags")
157     if(H5P_get(fc_plist, H5F_CRT_SHMSG_LIST_MAX_NAME, &list_max) < 0)
158         HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get SOHM list maximum")
159     if(H5P_get(fc_plist, H5F_CRT_SHMSG_BTREE_MIN_NAME, &btree_min) < 0)
160         HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get SOHM btree minimum")
161     if(H5P_get(fc_plist, H5F_CRT_SHMSG_INDEX_MINSIZE_NAME, &minsizes) < 0)
162         HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get SOHM message min sizes")
163 
164     /* Verify that values are valid */
165     if(table->num_indexes > H5O_SHMESG_MAX_NINDEXES)
166         HGOTO_ERROR(H5E_SOHM, H5E_BADRANGE, FAIL, "number of indexes in property list is too large")
167 
168     /* Check that type flags weren't duplicated anywhere */
169     type_flags_used = 0;
170     for(x = 0; x < table->num_indexes; ++x) {
171         if(index_type_flags[x] & type_flags_used)
172             HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, FAIL, "the same shared message type flag is assigned to more than one index")
173         type_flags_used |= index_type_flags[x];
174     } /* end for */
175 
176     /* Check that number of indexes in table and in superblock make sense.
177      * Right now we just use one byte to hold the number of indexes.
178      */
179     HDassert(table->num_indexes < 256);
180 
181     /* Check that list and btree cutoffs make sense.  There can't be any
182      * values greater than the list max but less than the btree min; the
183      * list max has to be greater than or equal to one less than the btree
184      * min.
185      */
186     HDassert(list_max + 1 >= btree_min);
187     HDassert(table->num_indexes > 0 && table->num_indexes <= H5O_SHMESG_MAX_NINDEXES);
188 
189     /* Allocate the SOHM indexes as an array. */
190     if(NULL == (table->indexes = (H5SM_index_header_t *)H5FL_ARR_MALLOC(H5SM_index_header_t, (size_t)table->num_indexes)))
191 	HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "memory allocation failed for SOHM indexes")
192 
193     /* Initialize all of the indexes, but don't allocate space for them to
194      * hold messages until we actually need to write to them.
195      */
196     for(x = 0; x < table->num_indexes; x++) {
197         table->indexes[x].btree_min = btree_min;
198         table->indexes[x].list_max = list_max;
199         table->indexes[x].mesg_types = index_type_flags[x];
200         table->indexes[x].min_mesg_size = minsizes[x];
201         table->indexes[x].index_addr = HADDR_UNDEF;
202         table->indexes[x].heap_addr = HADDR_UNDEF;
203         table->indexes[x].num_messages = 0;
204 
205         /* Indexes start as lists unless the list-to-btree threshold is zero */
206         if(table->indexes[x].list_max > 0)
207             table->indexes[x].index_type = H5SM_LIST;
208         else
209             table->indexes[x].index_type = H5SM_BTREE;
210 
211         /* Compute the size of a list index for this SOHM index */
212         table->indexes[x].list_size = H5SM_LIST_SIZE(f, list_max);
213     } /* end for */
214 
215     /* Allocate space for the table on disk */
216     if(HADDR_UNDEF == (table_addr = H5MF_alloc(f, H5FD_MEM_SOHM_TABLE, dxpl_id, (hsize_t)table->table_size)))
217 	HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "file allocation failed for SOHM table")
218 
219     /* Cache the new table */
220     if(H5AC_insert_entry(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, table, H5AC__NO_FLAGS_SET) < 0)
221 	HGOTO_ERROR(H5E_SOHM, H5E_CANTINS, FAIL, "can't add SOHM table to cache")
222 
223     /* Record the address of the master table in the file */
224     H5F_SET_SOHM_ADDR(f, table_addr);
225 
226     /* Check for sharing attributes in this file, which means that creation
227      *  indices must be tracked on object header message in the file.
228      */
229     if(type_flags_used & H5O_SHMESG_ATTR_FLAG)
230         H5F_SET_STORE_MSG_CRT_IDX(f, TRUE);
231 
232     /* Set the ring type to superblock extension */
233     ring = H5AC_RING_SBE;
234     if((H5P_set(dxpl, H5AC_RING_NAME, &ring)) < 0)
235         HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "unable to set property value")
236 
237     /* Write shared message information to the superblock extension */
238     sohm_table.addr = H5F_SOHM_ADDR(f);
239     sohm_table.version = H5F_SOHM_VERS(f);
240     sohm_table.nindexes = H5F_SOHM_NINDEXES(f);
241     if(H5O_msg_create(ext_loc, H5O_SHMESG_ID, H5O_MSG_FLAG_CONSTANT | H5O_MSG_FLAG_DONTSHARE, H5O_UPDATE_TIME, &sohm_table, dxpl_id) < 0)
242         HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to update SOHM header message")
243 
244 done:
245     /* Reset the ring in the DXPL */
246     if(H5AC_reset_ring(dxpl, orig_ring) < 0)
247         HDONE_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "unable to set property value")
248 
249     if(ret_value < 0) {
250         if(table_addr != HADDR_UNDEF)
251             H5MF_xfree(f, H5FD_MEM_SOHM_TABLE, dxpl_id, table_addr, (hsize_t)table->table_size);
252         if(table != NULL)
253             table = H5FL_FREE(H5SM_master_table_t, table);
254     } /* end if */
255 
256     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
257 } /* end H5SM_init() */
258 
259 
260 /*-------------------------------------------------------------------------
261  * Function:    H5SM_type_to_flag
262  *
263  * Purpose:     Get the shared message flag for a given message type.
264  *
265  * Return:      Non-negative on success/Negative on failure
266  *
267  * Programmer:  James Laird
268  *              Tuesday, October 10, 2006
269  *
270  *-------------------------------------------------------------------------
271  */
272 static herr_t
H5SM_type_to_flag(unsigned type_id,unsigned * type_flag)273 H5SM_type_to_flag(unsigned type_id, unsigned *type_flag)
274 {
275     herr_t ret_value = SUCCEED;         /* Return value */
276 
277     FUNC_ENTER_NOAPI_NOINIT
278 
279     /* Translate the H5O type_id into an H5SM type flag */
280     switch(type_id) {
281         case H5O_FILL_ID:
282             type_id = H5O_FILL_NEW_ID;
283             /* Fall through... */
284 
285         case H5O_SDSPACE_ID:
286         case H5O_DTYPE_ID:
287         case H5O_FILL_NEW_ID:
288         case H5O_PLINE_ID:
289         case H5O_ATTR_ID:
290             *type_flag = (unsigned)1 << type_id;
291             break;
292 
293         default:
294             HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "unknown message type ID")
295     } /* end switch */
296 
297 done:
298     FUNC_LEAVE_NOAPI(ret_value)
299 } /* end H5SM_type_to_flag() */
300 
301 
302 /*-------------------------------------------------------------------------
303  * Function:    H5SM_get_index
304  *
305  * Purpose:     Get the index number for a given message type.
306  *
307  *              Returns the number of the index in the supplied table
308  *              that holds messages of type type_id, or negative if
309  *              there is no index for this message type.
310  *
311  * Return:      Non-negative on success/Negative on failure
312  *
313  * Programmer:  James Laird
314  *              Tuesday, October 10, 2006
315  *
316  *-------------------------------------------------------------------------
317  */
318 ssize_t
H5SM_get_index(const H5SM_master_table_t * table,unsigned type_id)319 H5SM_get_index(const H5SM_master_table_t *table, unsigned type_id)
320 {
321     size_t x;
322     unsigned type_flag;
323     ssize_t ret_value = FAIL;
324 
325     FUNC_ENTER_NOAPI_NOINIT
326 
327     /* Translate the H5O type_id into an H5SM type flag */
328     if(H5SM_type_to_flag(type_id, &type_flag) < 0)
329         HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't map message type to flag")
330 
331     /* Search the indexes until we find one that matches this flag or we've
332      * searched them all.
333      */
334     for(x = 0; x < table->num_indexes; ++x)
335         if(table->indexes[x].mesg_types & type_flag)
336             HGOTO_DONE((ssize_t)x)
337 
338     /* At this point, ret_value is either the location of the correct
339      * index or it's still FAIL because we didn't find an index.
340      */
341 done:
342     FUNC_LEAVE_NOAPI(ret_value)
343 } /* end H5SM_get_index() */
344 
345 
346 /*-------------------------------------------------------------------------
347  * Function:    H5SM_type_shared
348  *
349  * Purpose:     Check if a given message type is shared in a file.
350  *
351  * Return:      Non-negative on success/Negative on failure
352  *
353  * Programmer:  Quincey Koziol
354  *              Tuesday, December 12, 2006
355  *
356  *-------------------------------------------------------------------------
357  */
358 htri_t
H5SM_type_shared(H5F_t * f,unsigned type_id,hid_t dxpl_id)359 H5SM_type_shared(H5F_t *f, unsigned type_id, hid_t dxpl_id)
360 {
361     H5SM_master_table_t *table = NULL;  /* Shared object master table */
362     unsigned type_flag;                 /* Flag corresponding to message type */
363     size_t u;                           /* Local index variable */
364     htri_t ret_value = FALSE;           /* Return value */
365 
366     FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
367 
368     /* Translate the H5O type_id into an H5SM type flag */
369     if(H5SM_type_to_flag(type_id, &type_flag) < 0)
370         HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't map message type to flag")
371 
372     /* Look up the master SOHM table */
373     if(H5F_addr_defined(H5F_SOHM_ADDR(f))) {
374         H5SM_table_cache_ud_t cache_udata;      /* User-data for callback */
375 
376         /* Set up user data for callback */
377         cache_udata.f = f;
378 
379         if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
380             HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
381     } /* end if */
382     else
383         /* No shared messages of any type */
384         HGOTO_DONE(FALSE)
385 
386     /* Search the indexes until we find one that matches this flag or we've
387      * searched them all.
388      */
389     for(u = 0; u < table->num_indexes; u++)
390         if(table->indexes[u].mesg_types & type_flag)
391             HGOTO_DONE(TRUE)
392 
393 done:
394     /* Release the master SOHM table */
395     if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
396 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
397 
398     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
399 } /* end H5SM_type_shared() */
400 
401 
402 /*-------------------------------------------------------------------------
403  * Function:    H5SM_get_fheap_addr
404  *
405  * Purpose:     Gets the address of the fractal heap used to store
406  *              messages of type type_id.
407  *
408  * Return:      Non-negative on success/negative on failure
409  *
410  * Programmer:  James Laird
411  *              Tuesday, October 3, 2006
412  *
413  *-------------------------------------------------------------------------
414  */
415 herr_t
H5SM_get_fheap_addr(H5F_t * f,hid_t dxpl_id,unsigned type_id,haddr_t * fheap_addr)416 H5SM_get_fheap_addr(H5F_t *f, hid_t dxpl_id, unsigned type_id, haddr_t *fheap_addr)
417 {
418     H5SM_master_table_t *table = NULL;  /* Shared object master table */
419     H5SM_table_cache_ud_t cache_udata;  /* User-data for callback */
420     ssize_t index_num;                  /* Which index */
421     herr_t ret_value = SUCCEED;         /* Return value */
422 
423     FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
424 
425     /* Sanity checks */
426     HDassert(f);
427     HDassert(fheap_addr);
428 
429     /* Set up user data for callback */
430     cache_udata.f = f;
431 
432     /* Look up the master SOHM table */
433     if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
434 	HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
435 
436     /* Look up index for message type */
437     if((index_num = H5SM_get_index(table, type_id)) < 0)
438 	HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to find correct SOHM index")
439 
440     /* Retrieve heap address for index */
441     *fheap_addr = table->indexes[index_num].heap_addr;
442 
443 done:
444     /* Release the master SOHM table */
445     if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
446 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
447 
448     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
449 } /* end H5SM_get_fheap_addr() */
450 
451 
452 /*-------------------------------------------------------------------------
453  * Function:    H5SM_create_index
454  *
455  * Purpose:     Allocates storage for an index, populating the HEADER struct.
456  *
457  * Return:      Non-negative on success/negative on failure
458  *
459  * Programmer:  James Laird
460  *              Tuesday, May 2, 2006
461  *
462  *-------------------------------------------------------------------------
463  */
464 static herr_t
H5SM_create_index(H5F_t * f,H5SM_index_header_t * header,hid_t dxpl_id)465 H5SM_create_index(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id)
466 {
467     H5HF_create_t fheap_cparam;         /* Fractal heap creation parameters */
468     H5HF_t *fheap = NULL;               /* Fractal heap handle */
469     H5B2_t *bt2 = NULL;                 /* v2 B-tree handle for index */
470     herr_t ret_value = SUCCEED;
471 
472     FUNC_ENTER_NOAPI_NOINIT
473 
474     /* Sanity check */
475     HDassert(header);
476     HDassert(header->index_addr == HADDR_UNDEF);
477     HDassert(header->btree_min <= header->list_max + 1);
478 
479     /* In most cases, the index starts as a list */
480     if(header->list_max > 0) {
481         haddr_t list_addr = HADDR_UNDEF;    /* Address of SOHM list */
482 
483         /* Create the list index */
484         if((list_addr = H5SM_create_list(f, header, dxpl_id)) == HADDR_UNDEF)
485             HGOTO_ERROR(H5E_SOHM, H5E_CANTCREATE, FAIL, "list creation failed for SOHM index")
486 
487         /* Set the index type & address */
488         header->index_type = H5SM_LIST;
489         header->index_addr = list_addr;
490     } /* end if */
491     /* index is a B-tree */
492     else {
493         H5B2_create_t bt2_cparam;           /* v2 B-tree creation parameters */
494         haddr_t tree_addr = HADDR_UNDEF;    /* Address of SOHM B-tree */
495 
496         /* Create the v2 B-tree index */
497         bt2_cparam.cls = H5SM_INDEX;
498         bt2_cparam.node_size = (uint32_t)H5SM_B2_NODE_SIZE;
499         bt2_cparam.rrec_size = (uint32_t)H5SM_SOHM_ENTRY_SIZE(f);
500         bt2_cparam.split_percent = H5SM_B2_SPLIT_PERCENT;
501         bt2_cparam.merge_percent = H5SM_B2_MERGE_PERCENT;
502         if(NULL == (bt2 = H5B2_create(f, dxpl_id, &bt2_cparam, f)))
503             HGOTO_ERROR(H5E_SOHM, H5E_CANTCREATE, FAIL, "B-tree creation failed for SOHM index")
504 
505         /* Retrieve the v2 B-tree's address in the file */
506         if(H5B2_get_addr(bt2, &tree_addr) < 0)
507             HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get v2 B-tree address for SOHM index")
508 
509         /* Set the index type & address */
510         header->index_type = H5SM_BTREE;
511         header->index_addr = tree_addr;
512     } /* end else */
513 
514     /* Create a heap to hold the shared messages that the list or B-tree will index */
515     HDmemset(&fheap_cparam, 0, sizeof(fheap_cparam));
516     fheap_cparam.managed.width = H5O_FHEAP_MAN_WIDTH;
517     fheap_cparam.managed.start_block_size = H5O_FHEAP_MAN_START_BLOCK_SIZE;
518     fheap_cparam.managed.max_direct_size = H5O_FHEAP_MAN_MAX_DIRECT_SIZE;
519     fheap_cparam.managed.max_index = H5O_FHEAP_MAN_MAX_INDEX;
520     fheap_cparam.managed.start_root_rows = H5O_FHEAP_MAN_START_ROOT_ROWS;
521     fheap_cparam.checksum_dblocks = H5O_FHEAP_CHECKSUM_DBLOCKS;
522     fheap_cparam.id_len = 0;
523     fheap_cparam.max_man_size = H5O_FHEAP_MAX_MAN_SIZE;
524     if(NULL == (fheap = H5HF_create(f, dxpl_id, &fheap_cparam)))
525         HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to create fractal heap")
526 
527     if(H5HF_get_heap_addr(fheap, &(header->heap_addr)) < 0)
528         HGOTO_ERROR(H5E_SOHM, H5E_CANTGETSIZE, FAIL, "can't get fractal heap address")
529 
530 #ifndef NDEBUG
531 {
532     size_t fheap_id_len;             /* Size of a fractal heap ID */
533 
534     /* Sanity check ID length */
535     if(H5HF_get_id_len(fheap, &fheap_id_len) < 0)
536         HGOTO_ERROR(H5E_SOHM, H5E_CANTGETSIZE, FAIL, "can't get fractal heap ID length")
537     HDassert(fheap_id_len == H5O_FHEAP_ID_LEN);
538 }
539 #endif /* NDEBUG */
540 
541 done:
542     /* Release resources */
543     if(fheap && H5HF_close(fheap, dxpl_id) < 0)
544         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
545     if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
546         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
547 
548     FUNC_LEAVE_NOAPI(ret_value)
549 } /* end H5SM_create_index */
550 
551 
552 /*-------------------------------------------------------------------------
553  * Function:    H5SM_delete_index
554  *
555  * Purpose:     De-allocates storage for an index whose header is HEADER.
556  *
557  *              If DELETE_HEAP is TRUE, deletes the index's heap, eliminating
558  *              it completely.
559  *
560  *              If DELETE_HEAP is FALSE, the heap is not deleted.  This is
561  *              useful when deleting only the index header as the index is
562  *              converted from a list to a B-tree and back again.
563  *
564  * Return:      Non-negative on success/negative on failure
565  *
566  * Programmer:  James Laird
567  *              Thursday, January 4, 2006
568  *
569  *-------------------------------------------------------------------------
570  */
571 static herr_t
H5SM_delete_index(H5F_t * f,H5SM_index_header_t * header,hid_t dxpl_id,hbool_t delete_heap)572 H5SM_delete_index(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id,
573     hbool_t delete_heap)
574 {
575     herr_t ret_value = SUCCEED;         /* Return value */
576 
577     FUNC_ENTER_NOAPI_NOINIT
578 
579     /* Determine whether index is a list or a B-tree. */
580     if(header->index_type == H5SM_LIST) {
581         unsigned index_status = 0;         /* Index list's status in the metadata cache */
582 
583         /* Check the index list's status in the metadata cache */
584         if(H5AC_get_entry_status(f, header->index_addr, &index_status) < 0)
585             HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "unable to check metadata cache status for direct block")
586 
587         /* If the index list is in the cache, expunge it now */
588         if(index_status & H5AC_ES__IN_CACHE) {
589             /* Sanity checks on index list */
590             HDassert(!(index_status & H5AC_ES__IS_PINNED));
591             HDassert(!(index_status & H5AC_ES__IS_PROTECTED));
592 
593             /* Evict the index list from the metadata cache */
594             if(H5AC_expunge_entry(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, H5AC__FREE_FILE_SPACE_FLAG) < 0)
595                 HGOTO_ERROR(H5E_SOHM, H5E_CANTREMOVE, FAIL, "unable to remove list index from cache")
596         } /* end if */
597     } /* end if */
598     else {
599         HDassert(header->index_type == H5SM_BTREE);
600 
601         /* Delete the B-tree. */
602         if(H5B2_delete(f, dxpl_id, header->index_addr, f, NULL, NULL) < 0)
603             HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to delete B-tree")
604 
605         /* Revert to list unless B-trees can have zero records */
606         if(header->btree_min > 0)
607             header->index_type = H5SM_LIST;
608     } /* end else */
609 
610     /* Free the index's heap if requested. */
611     if(delete_heap == TRUE) {
612         if(H5HF_delete(f, dxpl_id, header->heap_addr) < 0)
613             HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to delete fractal heap")
614         header->heap_addr = HADDR_UNDEF;
615     } /* end if */
616 
617     /* Reset index info */
618     header->index_addr = HADDR_UNDEF;
619     header->num_messages = 0;
620 
621 done:
622     FUNC_LEAVE_NOAPI(ret_value)
623 } /* end H5SM_delete_index */
624 
625 
626 /*-------------------------------------------------------------------------
627  * Function:    H5SM_create_list
628  *
629  * Purpose:     Creates a list of SOHM messages.
630  *
631  *              Called when a new index is created from scratch or when a
632  *              B-tree needs to be converted back into a list.
633  *
634  * Return:      Non-negative on success/Negative on failure
635  *
636  * Programmer:  James Laird
637  *              Monday, August 28, 2006
638  *
639  *-------------------------------------------------------------------------
640  */
641 static haddr_t
H5SM_create_list(H5F_t * f,H5SM_index_header_t * header,hid_t dxpl_id)642 H5SM_create_list(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id)
643 {
644     H5SM_list_t *list = NULL;   /* List of messages */
645     hsize_t x;                  /* Counter variable */
646     size_t num_entries;         /* Number of messages to create in list */
647     haddr_t addr = HADDR_UNDEF; /* Address of the list on disk */
648     haddr_t ret_value = HADDR_UNDEF;    /* Return value */
649 
650     FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, HADDR_UNDEF)
651 
652     HDassert(f);
653     HDassert(header);
654 
655     num_entries = header->list_max;
656 
657     /* Allocate list in memory */
658     if(NULL == (list = H5FL_CALLOC(H5SM_list_t)))
659 	HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for SOHM list")
660     if(NULL == (list->messages = (H5SM_sohm_t *)H5FL_ARR_CALLOC(H5SM_sohm_t, num_entries)))
661 	HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for SOHM list")
662 
663     /* Initialize messages in list */
664     for(x = 0; x < num_entries; x++)
665         list->messages[x].location = H5SM_NO_LOC;
666 
667     /* Point list at header passed in */
668     list->header = header;
669 
670     /* Allocate space for the list on disk */
671     if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_SOHM_INDEX, dxpl_id, (hsize_t)header->list_size)))
672 	HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for SOHM list")
673 
674     /* Put the list into the cache */
675     if(H5AC_insert_entry(f, dxpl_id, H5AC_SOHM_LIST, addr, list, H5AC__NO_FLAGS_SET) < 0)
676 	HGOTO_ERROR(H5E_SOHM, H5E_CANTINS, HADDR_UNDEF, "can't add SOHM list to cache")
677 
678     /* Set return value */
679     ret_value = addr;
680 
681 done:
682     if(ret_value == HADDR_UNDEF) {
683         if(list != NULL) {
684             if(list->messages != NULL)
685                 list->messages = H5FL_ARR_FREE(H5SM_sohm_t, list->messages);
686             list = H5FL_FREE(H5SM_list_t, list);
687         } /* end if */
688         if(addr != HADDR_UNDEF)
689             H5MF_xfree(f, H5FD_MEM_SOHM_INDEX, dxpl_id, addr, (hsize_t)header->list_size);
690     } /* end if */
691 
692     FUNC_LEAVE_NOAPI_TAG(ret_value, HADDR_UNDEF)
693 } /* end H5SM_create_list */
694 
695 
696 /*-------------------------------------------------------------------------
697  * Function:    H5SM_convert_list_to_btree
698  *
699  * Purpose:     Given a list index, turns it into a B-tree index.  This is
700  *              done when too many messages are added to the list.
701  *
702  *              Requires that *_LIST be a valid list and currently protected
703  *              in the cache.  Unprotects (and expunges) *_LIST from the cache.
704  *
705  *              _LIST needs to be a double pointer so that the calling function
706  *              knows if it is released from the cache if this function exits
707  *              in error.  Trying to free it again will trigger an assert.
708  *
709  * Return:      Non-negative on success
710  *              Negative on failure
711  *
712  * Programmer:  James Laird
713  *              Thursday, January 4, 2006
714  *
715  *-------------------------------------------------------------------------
716  */
717 static herr_t
H5SM_convert_list_to_btree(H5F_t * f,H5SM_index_header_t * header,H5SM_list_t ** _list,H5HF_t * fheap,H5O_t * open_oh,hid_t dxpl_id)718 H5SM_convert_list_to_btree(H5F_t *f, H5SM_index_header_t *header,
719     H5SM_list_t **_list, H5HF_t *fheap, H5O_t *open_oh, hid_t dxpl_id)
720 {
721     H5SM_list_t *list;                  /* Pointer to the existing message list */
722     H5SM_mesg_key_t key;                /* Key for inserting records in v2 B-tree */
723     H5B2_create_t bt2_cparam;           /* v2 B-tree creation parameters */
724     H5B2_t *bt2 = NULL;                 /* v2 B-tree handle for index */
725     haddr_t     tree_addr;              /* New v2 B-tree's address */
726     size_t      num_messages;		/* Number of messages being tracked */
727     size_t      x;
728     void *      encoding_buf = NULL;
729     herr_t      ret_value = SUCCEED;    /* Return value */
730 
731     FUNC_ENTER_NOAPI_NOINIT
732 
733     HDassert(_list && *_list);
734     HDassert(header);
735 
736     /* Get pointer to list of messages to convert */
737     list = *_list;
738 
739     /* Create the new v2 B-tree for tracking the messages */
740     bt2_cparam.cls = H5SM_INDEX;
741     bt2_cparam.node_size = (uint32_t)H5SM_B2_NODE_SIZE;
742     bt2_cparam.rrec_size = (uint32_t)H5SM_SOHM_ENTRY_SIZE(f);
743     bt2_cparam.split_percent = H5SM_B2_SPLIT_PERCENT;
744     bt2_cparam.merge_percent = H5SM_B2_MERGE_PERCENT;
745     if(NULL == (bt2 = H5B2_create(f, dxpl_id, &bt2_cparam, f)))
746         HGOTO_ERROR(H5E_SOHM, H5E_CANTCREATE, FAIL, "B-tree creation failed for SOHM index")
747 
748     /* Retrieve the v2 B-tree's address in the file */
749     if(H5B2_get_addr(bt2, &tree_addr) < 0)
750         HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't get v2 B-tree address for SOHM index")
751 
752     /* Set up key values that all messages will use.  Since these messages
753      * are in the heap, they have a heap ID and no encoding or type_id.
754      */
755     key.file = f;
756     key.dxpl_id = dxpl_id;
757     key.fheap = fheap;
758     key.encoding_size = 0;
759     key.encoding = NULL;
760 
761     /* Insert each record into the new B-tree */
762     for(x = 0; x < header->list_max; x++) {
763         if(list->messages[x].location != H5SM_NO_LOC) {
764             /* Copy message into key */
765             key.message = list->messages[x];
766 
767             /* Get the encoded message */
768             if(H5SM_read_mesg(f, &(key.message), fheap, open_oh, dxpl_id, &key.encoding_size, &encoding_buf) < 0)
769                 HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, FAIL, "Couldn't read SOHM message in list")
770 
771             key.encoding = encoding_buf;
772 
773             /* Insert the message into the B-tree */
774             if(H5B2_insert(bt2, dxpl_id, &key) < 0)
775                 HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "couldn't add SOHM to B-tree")
776 
777             /* Free buffer from H5SM_read_mesg */
778             if(encoding_buf)
779                 encoding_buf = H5MM_xfree(encoding_buf);
780         } /* end if */
781     } /* end for */
782 
783     /* Unprotect list in cache and release heap */
784     if(H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
785 	HGOTO_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to release SOHM list")
786     *_list = list = NULL;
787 
788     /* Delete the old list index (but not its heap, which the new index is
789      * still using!)
790      */
791     num_messages = header->num_messages;        /* preserve this across the index deletion */
792     if(H5SM_delete_index(f, header, dxpl_id, FALSE) < 0)
793         HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "can't free list index")
794 
795     /* Set/restore header info */
796     header->index_addr = tree_addr;
797     header->index_type = H5SM_BTREE;
798     header->num_messages = num_messages;
799 
800 done:
801     /* Release resources */
802     if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
803         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
804     if(encoding_buf)
805         encoding_buf = H5MM_xfree(encoding_buf);
806 
807     FUNC_LEAVE_NOAPI(ret_value)
808 } /* H5SM_convert_list_to_btree() */
809 
810 
811 /*-------------------------------------------------------------------------
812  * Function:    H5SM_convert_btree_to_list
813  *
814  * Purpose:     Given a B-tree index, turns it into a list index.  This is
815  *              done when too many messages are deleted from the B-tree.
816  *
817  * Return:      Non-negative on success
818  *              Negative on failure
819  *
820  * Programmer:  James Laird
821  *              Thursday, January 4, 2006
822  *
823  *-------------------------------------------------------------------------
824  */
825 static herr_t
H5SM_convert_btree_to_list(H5F_t * f,H5SM_index_header_t * header,hid_t dxpl_id)826 H5SM_convert_btree_to_list(H5F_t * f, H5SM_index_header_t * header, hid_t dxpl_id)
827 {
828     H5SM_list_t     *list = NULL;
829     H5SM_list_cache_ud_t cache_udata;   /* User-data for metadata cache callback */
830     haddr_t          btree_addr;
831     herr_t           ret_value = SUCCEED;
832 
833     FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
834 
835     /* Remember the address of the old B-tree, but change the header over to be
836      * a list..
837      */
838     btree_addr = header->index_addr;
839 
840     header->num_messages = 0;
841     header->index_type = H5SM_LIST;
842 
843     /* Create a new list index */
844     if(HADDR_UNDEF == (header->index_addr = H5SM_create_list(f, header, dxpl_id)))
845         HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to create shared message list")
846 
847     /* Set up user data for metadata cache callback */
848     cache_udata.f = f;
849     cache_udata.header = header;
850 
851     /* Protect the SOHM list */
852     if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, H5AC__NO_FLAGS_SET)))
853         HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM list index")
854 
855     /* Delete the B-tree and have messages copy themselves to the
856      * list as they're deleted
857      */
858     if(H5B2_delete(f, dxpl_id, btree_addr, f, H5SM_bt2_convert_to_list_op, list) < 0)
859         HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to delete B-tree")
860 
861 done:
862     /* Release the SOHM list from the cache */
863     if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__DIRTIED_FLAG) < 0)
864         HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect SOHM index")
865 
866     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
867 } /* end H5SM_convert_btree_to_list() */
868 
869 
870 /*-------------------------------------------------------------------------
871  * Function:    H5SM_can_share_common
872  *
873  * Purpose:     "trivial" checks for determining if a message can be shared.
874  *
875  * Note:	These checks are common to the "can share" and "try share"
876  *		routines and are the "fast" checks before we need to protect
877  *		the SOHM master table.
878  *
879  * Return:      TRUE if message could be a SOHM
880  *              FALSE if this message couldn't be a SOHM
881  *              Negative on failure
882  *
883  * Programmer:  Quincey Koziol
884  *              Wednesday, February 21, 2007
885  *
886  *-------------------------------------------------------------------------
887  */
888 static htri_t
H5SM_can_share_common(const H5F_t * f,unsigned type_id,const void * mesg)889 H5SM_can_share_common(const H5F_t *f, unsigned type_id, const void *mesg)
890 {
891     htri_t ret_value = FAIL;    /* Return value */
892 
893     FUNC_ENTER_NOAPI_NOINIT
894 
895     /* Check whether this message ought to be shared or not */
896     /* If sharing is disabled in this file, don't share the message */
897     if(!H5F_addr_defined(H5F_SOHM_ADDR(f)))
898         HGOTO_DONE(FALSE)
899 
900     /* Type-specific check */
901     if((ret_value = H5O_msg_can_share(type_id, mesg)) < 0)
902         HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "can_share callback returned error")
903     if(ret_value == FALSE)
904         HGOTO_DONE(FALSE)
905 
906     /* At this point, the message passes the "trivial" checks and is worth
907      *  further checks.
908      */
909 
910 done:
911     FUNC_LEAVE_NOAPI(ret_value)
912 } /* end H5SM_can_share_common() */
913 
914 
915 /*-------------------------------------------------------------------------
916  * Function:    H5SM_can_share
917  *
918  * Purpose:     Checks if an object header message would be shared or is
919  *		already shared.
920  *
921  *              If not, returns FALSE and does nothing.
922  *
923  * Return:      TRUE if message will be a SOHM
924  *              FALSE if this message won't be a SOHM
925  *              Negative on failure
926  *
927  * Programmer:  Quincey Koziol
928  *              Wednesday, February 21, 2007
929  *
930  *-------------------------------------------------------------------------
931  */
932 htri_t
H5SM_can_share(H5F_t * f,hid_t dxpl_id,H5SM_master_table_t * table,ssize_t * sohm_index_num,unsigned type_id,const void * mesg)933 H5SM_can_share(H5F_t *f, hid_t dxpl_id, H5SM_master_table_t *table,
934     ssize_t *sohm_index_num, unsigned type_id, const void *mesg)
935 {
936     size_t              mesg_size;
937     H5SM_master_table_t *my_table = NULL;
938     ssize_t             index_num;
939     htri_t              tri_ret;
940     htri_t              ret_value = TRUE;
941 
942     FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
943 
944     /* "trivial" sharing checks */
945     if((tri_ret = H5SM_can_share_common(f, type_id, mesg)) < 0)
946         HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'trivial' sharing checks returned error")
947     if(tri_ret == FALSE)
948         HGOTO_DONE(FALSE)
949 
950     /* Look up the master SOHM table */
951     /* (use incoming master SOHM table if possible) */
952     if(table)
953         my_table = table;
954     else {
955         H5SM_table_cache_ud_t cache_udata;      /* User-data for callback */
956 
957         /* Set up user data for callback */
958         cache_udata.f = f;
959 
960         if(NULL == (my_table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
961             HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
962     } /* end if */
963 
964     /* Find the right index for this message type.  If there is no such index
965      * then this type of message isn't shareable
966      */
967     if((index_num = H5SM_get_index(my_table, type_id)) < 0) {
968         H5E_clear_stack(NULL); /*ignore error*/
969         HGOTO_DONE(FALSE)
970     } /* end if */
971 
972     /* If the message isn't big enough, don't bother sharing it */
973     if(0 == (mesg_size = H5O_msg_raw_size(f, type_id, TRUE, mesg)))
974         HGOTO_ERROR(H5E_SOHM, H5E_BADMESG, FAIL, "unable to get OH message size")
975     if(mesg_size < my_table->indexes[index_num].min_mesg_size)
976         HGOTO_DONE(FALSE)
977 
978     /* At this point, the message will be shared, set the index number if requested. */
979     if(sohm_index_num)
980         *sohm_index_num = index_num;
981 
982 done:
983     /* Release the master SOHM table, if we protected it */
984     if(my_table && my_table != table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), my_table, H5AC__NO_FLAGS_SET) < 0)
985 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
986 
987     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
988 } /* end H5SM_can_share() */
989 
990 
991 /*-------------------------------------------------------------------------
992  * Function:    H5SM_try_share
993  *
994  * Purpose:     Attempts to share an object header message.
995  *
996  *              MESG_LOC is an H5O_mesg_loc_t struct that gives the message's
997  *              location in an object header (address and index).  This
998  *              function sets the type_id in MESG_LOC.
999  *              If MESG_LOC is not NULL, this message will be "unique but
1000  *              shareable" and will be entered in the index but not actually
1001  *              shared.  If it is NULL, this message will be fully shared if
1002  *              it is shareable at all.
1003  *
1004  *              OPEN_OH is the object header that is currently open and
1005  *              protected.  If NULL, the SM module will protect any object
1006  *              header it needs (which can cause an error if that OH is
1007  *              already protected!).
1008  *
1009  *              DEFER_FLAGS indicates whether the sharing operation should
1010  *              actually occur, or whether this is just a set up call for a
1011  *              future sharing operation.  In the latter case this argument
1012  *              should be H5SM_DEFER.  If the message was previously deferred
1013  *              this argument should be H5SM_WAS_DEFERRED.
1014  *
1015  *              MESG_FLAGS will have the H5O_MSG_FLAG_SHAREABLE or
1016  *              H5O_MSG_FLAG_SHARED flag set if one is appropriate.  This is
1017  *              the only way to tell the difference between a message that
1018  *              has just been fully shared and a message that is only
1019  *              "shareable" and is still in the object header, so it cannot
1020  *              be NULL if MESG_LOC is not NULL.  If MESG_LOC is NULL, then
1021  *              the message won't be "unique but shareable" and MESG_FLAGS
1022  *              can be NULL as well.
1023  *
1024  *              If the message should be shared (if sharing has been
1025  *              enabled and this message qualifies), this function turns the
1026  *              message into a shared message, sets the H5O_MSG_FLAG_SHARED
1027  *              flag in mesg_flags, and returns TRUE.
1028  *
1029  *              If the message isn't shared, returns FALSE.  If the message
1030  *              isn't shared but was entered in the shared message index,
1031  *              the H5O_MSG_FLAG_SHAREABLE flag will be set in mesg_flags
1032  *              and returns TRUE.
1033  *
1034  *              If this message was already shared, increments its reference
1035  *              count, and leaves it otherwise unchanged, returning TRUE and
1036  *              setting the H5O_MSG_FLAG_SHARED flag in mesg_flags.
1037  *
1038  *              If mesg_flags is NULL, the calling function should just look
1039  *              at the return value to determine if the message was shared
1040  *              or not.  Such messages should never be "unique but shareable."
1041  *
1042  * Return:      TRUE if message is now a SOHM
1043  *              FALSE if this message is not a SOHM
1044  *              Negative on failure
1045  *
1046  * Programmer:  James Laird
1047  *              Tuesday, May 2, 2006
1048  *
1049  *-------------------------------------------------------------------------
1050  */
1051 htri_t
H5SM_try_share(H5F_t * f,hid_t dxpl_id,H5O_t * open_oh,unsigned defer_flags,unsigned type_id,void * mesg,unsigned * mesg_flags)1052 H5SM_try_share(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, unsigned defer_flags,
1053     unsigned type_id, void *mesg, unsigned *mesg_flags)
1054 {
1055     H5SM_master_table_t *table = NULL;
1056     H5SM_table_cache_ud_t cache_udata;      /* User-data for callback */
1057     unsigned            cache_flags = H5AC__NO_FLAGS_SET;
1058     ssize_t             index_num;
1059     htri_t              tri_ret;
1060 #ifndef NDEBUG
1061     unsigned            deferred_type = -1u;
1062 #endif
1063     htri_t              ret_value = TRUE;
1064 
1065     FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
1066 
1067     /* If we previously deferred this operation, the saved message type should
1068      * be the same as the one we get here.  In debug mode, we make sure this
1069      * holds true; otherwise we can leave now if it wasn't shared in the DEFER
1070      * pass. */
1071     if(defer_flags & H5SM_WAS_DEFERRED)
1072 #ifndef NDEBUG
1073         deferred_type = ((H5O_shared_t *)mesg)->type;
1074 #else /* NDEBUG */
1075         if((((H5O_shared_t *)mesg)->type != H5O_SHARE_TYPE_HERE)
1076                 && (((H5O_shared_t *)mesg)->type != H5O_SHARE_TYPE_SOHM))
1077             HGOTO_DONE(FALSE);
1078 #endif /* NDEBUG */
1079 
1080     /* "trivial" sharing checks */
1081     if(mesg_flags && (*mesg_flags & H5O_MSG_FLAG_DONTSHARE))
1082         HGOTO_DONE(FALSE)
1083     if((tri_ret = H5SM_can_share_common(f, type_id, mesg)) < 0)
1084         HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'trivial' sharing checks returned error")
1085     if(tri_ret == FALSE)
1086         HGOTO_DONE(FALSE)
1087 
1088     /* Set up user data for callback */
1089     cache_udata.f = f;
1090 
1091     /* Look up the master SOHM table */
1092     if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__NO_FLAGS_SET)))
1093 	HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
1094 
1095     /* "complex" sharing checks */
1096     if((tri_ret = H5SM_can_share(f, dxpl_id, table, &index_num, type_id, mesg)) < 0)
1097         HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'complex' sharing checks returned error")
1098     if(tri_ret == FALSE)
1099         HGOTO_DONE(FALSE)
1100 
1101     /* At this point, the message will be shared. */
1102 
1103     /* If the index hasn't been allocated yet, create it */
1104     if(table->indexes[index_num].index_addr == HADDR_UNDEF) {
1105         if(H5SM_create_index(f, &(table->indexes[index_num]), dxpl_id) < 0)
1106             HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to create SOHM index")
1107         cache_flags |= H5AC__DIRTIED_FLAG;
1108     } /* end if */
1109 
1110     /* Write the message as a shared message.  This may or may not cause the
1111      * message to become shared (if it is unique, it will not be shared).
1112      */
1113     if(H5SM_write_mesg(f, dxpl_id, open_oh, &(table->indexes[index_num]),
1114             (defer_flags & H5SM_DEFER) != 0, type_id, mesg, &cache_flags) < 0)
1115 	HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "can't write shared message")
1116 
1117     /* Set flags if this message was "written" without error and wasn't a
1118      * 'defer' attempt; it is now either fully shared or "shareable".
1119      */
1120     if(mesg_flags) {
1121         if(((H5O_shared_t *)mesg)->type == H5O_SHARE_TYPE_HERE)
1122             *mesg_flags |= H5O_MSG_FLAG_SHAREABLE;
1123         else {
1124             HDassert(((H5O_shared_t *)mesg)->type == H5O_SHARE_TYPE_SOHM);
1125             *mesg_flags |= H5O_MSG_FLAG_SHARED;
1126         } /* end else */
1127     } /* end if */
1128 
1129 done:
1130     HDassert((ret_value != TRUE)
1131             || ((H5O_shared_t *)mesg)->type == H5O_SHARE_TYPE_HERE
1132             || ((H5O_shared_t *)mesg)->type == H5O_SHARE_TYPE_SOHM);
1133 #ifndef NDEBUG
1134     /* If we previously deferred this operation, make sure the saved message
1135      * type is the same as the one we get here. */
1136     if(defer_flags & H5SM_WAS_DEFERRED)
1137         HDassert(deferred_type == ((H5O_shared_t *)mesg)->type);
1138 #endif /* NDEBUG */
1139 
1140     /* Release the master SOHM table */
1141     if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, cache_flags) < 0)
1142 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
1143 
1144     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
1145 } /* end H5SM_try_share() */
1146 
1147 
1148 /*-------------------------------------------------------------------------
1149  * Function:	H5SM_incr_ref
1150  *
1151  * Purpose:	Increment the reference count for a SOHM message and return
1152  *              the message's heap ID.
1153  *
1154  *              The message pointer is actually returned via op_data, which
1155  *              should be a pointer to a H5SM_fheap_id_t.
1156  *
1157  * Return:	Non-negative on success
1158  *              Negative on failure
1159  *
1160  * Programmer:	James Laird
1161  *              Monday, November 6, 2006
1162  *
1163  *-------------------------------------------------------------------------
1164  */
1165 static herr_t
H5SM_incr_ref(void * record,void * _op_data,hbool_t * changed)1166 H5SM_incr_ref(void *record, void *_op_data, hbool_t *changed)
1167 {
1168     H5SM_sohm_t *message = (H5SM_sohm_t *) record;
1169     H5SM_incr_ref_opdata *op_data = (H5SM_incr_ref_opdata *) _op_data;
1170     herr_t ret_value = SUCCEED;
1171 
1172     FUNC_ENTER_NOAPI_NOINIT
1173 
1174     HDassert(record);
1175     HDassert(op_data);
1176     HDassert(changed);
1177 
1178     /* If the message was previously shared in an object header, share
1179      * it in the heap now.
1180      */
1181     if(message->location == H5SM_IN_OH) {
1182         HDassert(op_data->key && op_data->key->fheap);
1183 
1184         /* Put the message in the heap and record its new heap ID */
1185         if(H5HF_insert(op_data->key->fheap, op_data->dxpl_id, op_data->key->encoding_size, op_data->key->encoding, &message->u.heap_loc.fheap_id) < 0)
1186             HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to insert message into fractal heap")
1187 
1188         message->location = H5SM_IN_HEAP;
1189         message->u.heap_loc.ref_count = 2;
1190     } /* end if */
1191     else {
1192         HDassert(message->location == H5SM_IN_HEAP);
1193         /* If it's already in the heap, just increment the ref count */
1194         ++message->u.heap_loc.ref_count;
1195     } /* end else */
1196 
1197     /* If we got here, the message has changed */
1198     *changed = TRUE;
1199 
1200     /* Check for retrieving the heap ID */
1201     if(op_data)
1202        op_data->fheap_id = message->u.heap_loc.fheap_id;
1203 
1204 done:
1205     FUNC_LEAVE_NOAPI(ret_value)
1206 } /* end H5SM_incr_ref() */
1207 
1208 
1209 /*-------------------------------------------------------------------------
1210  * Function:    H5SM_write_mesg
1211  *
1212  * Purpose:     This routine adds a shareable message to an index.
1213  *              The behavior is controlled by the DEFER parameter:
1214  *
1215  *              If DEFER is TRUE, this routine Simulates adding a shareable
1216  *              message to an index.  It determines what the outcome would
1217  *              be with DEFER set the FALSE and updates the shared message
1218  *              info, but does not actually add the message to a heap, list,
1219  *              or b-tree.  Assumes that an open object header will be
1220  *              available when H5SM_write_mesg is called with DEFER set to
1221  *              FALSE.
1222  *
1223  *              If DEFER is FALSE, this routine adds a shareable message to
1224  *              an index.  If this is the first such message and we have an
1225  *              object header location for this message, we record it in the
1226  *              index but don't modify the message passed in.  If the message
1227  *              is already in the index or we don't have an object header
1228  *              location for it, it is shared in the heap and this function
1229  *              sets its sharing struct to reflect this.
1230  *
1231  *              The index could be a list or a B-tree.
1232  *
1233  * Return:      Non-negative on success
1234  *              Negative on failure
1235  *
1236  * Programmer:  James Laird
1237  *              Tuesday, May 2, 2006
1238  *
1239  *-------------------------------------------------------------------------
1240  */
1241 static herr_t
H5SM_write_mesg(H5F_t * f,hid_t dxpl_id,H5O_t * open_oh,H5SM_index_header_t * header,hbool_t defer,unsigned type_id,void * mesg,unsigned * cache_flags_ptr)1242 H5SM_write_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
1243     H5SM_index_header_t *header, hbool_t defer, unsigned type_id, void *mesg,
1244     unsigned *cache_flags_ptr)
1245 {
1246     H5SM_list_t           *list = NULL;     /* List index */
1247     H5SM_mesg_key_t       key;              /* Key used to search the index */
1248     H5SM_list_cache_ud_t cache_udata;   /* User-data for metadata cache callback */
1249     H5O_shared_t          shared;           /* Shared H5O message */
1250     hbool_t               found = FALSE;    /* Was the message in the index? */
1251     H5HF_t                *fheap = NULL;    /* Fractal heap handle */
1252     H5B2_t                *bt2 = NULL;      /* v2 B-tree handle for index */
1253     size_t                buf_size;         /* Size of the encoded message */
1254     void *                encoding_buf = NULL; /* Buffer for encoded message */
1255     size_t                empty_pos = UFAIL; /* Empty entry in list */
1256     herr_t                ret_value = SUCCEED;
1257 
1258     FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
1259 
1260     /* Sanity check */
1261     HDassert(header);
1262     HDassert(header->index_type != H5SM_BADTYPE);
1263     HDassert(cache_flags_ptr);
1264 
1265     /* Encode the message to be written */
1266     if((buf_size = H5O_msg_raw_size(f, type_id, TRUE, mesg)) == 0)
1267 	HGOTO_ERROR(H5E_SOHM, H5E_BADSIZE, FAIL, "can't find message size")
1268     if(NULL == (encoding_buf = H5MM_malloc(buf_size)))
1269 	HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "can't allocate buffer for encoding")
1270     if(H5O_msg_encode(f, type_id, TRUE, (unsigned char *)encoding_buf, mesg) < 0)
1271 	HGOTO_ERROR(H5E_SOHM, H5E_CANTENCODE, FAIL, "can't encode message to be shared")
1272 
1273     /* Open the fractal heap for this index */
1274     if(NULL == (fheap = H5HF_open(f, dxpl_id, header->heap_addr)))
1275 	HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
1276 
1277     /* Set up a key for the message to be written */
1278     key.dxpl_id = dxpl_id;
1279     key.file = f;
1280     key.fheap = fheap;
1281     key.encoding = encoding_buf;
1282     key.encoding_size = buf_size;
1283     key.message.hash = H5_checksum_lookup3(encoding_buf, buf_size, type_id);
1284     key.message.location = H5SM_NO_LOC;
1285 
1286     /* Assume the message is already in the index and try to increment its
1287      * reference count.  If this fails, the message isn't in the index after
1288      * all and we'll need to add it.
1289      */
1290     if(header->index_type == H5SM_LIST) {
1291         size_t list_pos;        /* Position in a list index */
1292 
1293         /* Set up user data for metadata cache callback */
1294         cache_udata.f = f;
1295         cache_udata.header = header;
1296 
1297         /* The index is a list; get it from the cache */
1298         if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, defer ? H5AC__READ_ONLY_FLAG : H5AC__NO_FLAGS_SET)))
1299 	    HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index")
1300 
1301         /* See if the message is already in the index and get its location.
1302          * Also record the first empty list position we find in case we need it
1303          * later.
1304          */
1305         if(H5SM__find_in_list(list, &key, &empty_pos, &list_pos) < 0)
1306 	    HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to search for message in list")
1307 
1308         if(defer) {
1309             if(list_pos != UFAIL)
1310                 found = TRUE;
1311         } /* end if */
1312         else {
1313             if(list_pos != UFAIL) {
1314                 /* If the message was previously shared in an object header, share
1315                  * it in the heap now.
1316                  */
1317                 if(list->messages[list_pos].location == H5SM_IN_OH) {
1318                     /* Put the message in the heap and record its new heap ID */
1319                     if(H5HF_insert(fheap, dxpl_id, key.encoding_size, key.encoding, &shared.u.heap_id) < 0)
1320                         HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to insert message into fractal heap")
1321 
1322                     list->messages[list_pos].location = H5SM_IN_HEAP;
1323                     list->messages[list_pos].u.heap_loc.fheap_id = shared.u.heap_id;
1324                     list->messages[list_pos].u.heap_loc.ref_count = 2;
1325                 } /* end if */
1326                 else {
1327                     /* If the message was already in the heap, increase its ref count */
1328                     HDassert(list->messages[list_pos].location == H5SM_IN_HEAP);
1329                     ++(list->messages[list_pos].u.heap_loc.ref_count);
1330                 } /* end else */
1331 
1332                 /* Set up the shared location to point to the shared location */
1333                 shared.u.heap_id = list->messages[list_pos].u.heap_loc.fheap_id;
1334                 found = TRUE;
1335             } /* end if */
1336         } /* end else */
1337     } /* end if */
1338     /* Index is a B-tree */
1339     else {
1340         HDassert(header->index_type == H5SM_BTREE);
1341 
1342         /* Open the index v2 B-tree */
1343         if(NULL == (bt2 = H5B2_open(f, dxpl_id, header->index_addr, f)))
1344             HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
1345 
1346         if(defer) {
1347             htri_t bt2_find;  /* Result from searching in the v2 B-tree */
1348 
1349             /* If this returns 0, it means that the message wasn't found. */
1350             /* If it return 1, set the heap_id in the shared struct.  It will
1351              * return a heap ID, since a message with a reference count greater
1352              * than 1 is always shared in the heap.
1353              */
1354             if((bt2_find = H5B2_find(bt2, dxpl_id, &key, NULL, NULL)) < 0)
1355                 HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "can't search for message in index")
1356             found = (hbool_t)bt2_find;
1357         } /* end if */
1358         else {
1359             H5SM_incr_ref_opdata op_data;
1360 
1361             /* Set up callback info */
1362             op_data.key = &key;
1363             op_data.dxpl_id = dxpl_id;
1364 
1365             /* If this returns failure, it means that the message wasn't found. */
1366             /* If it succeeds, set the heap_id in the shared struct.  It will
1367              * return a heap ID, since a message with a reference count greater
1368              * than 1 is always shared in the heap.
1369              */
1370             if(H5B2_modify(bt2, dxpl_id, &key, H5SM_incr_ref, &op_data) >= 0) {
1371                 shared.u.heap_id = op_data.fheap_id;
1372                 found = TRUE;
1373             } /* end if */
1374             else
1375                 H5E_clear_stack(NULL); /*ignore error*/
1376         } /* end else */
1377     } /* end else */
1378 
1379     if(found) {
1380         /* If the message was found, it's shared in the heap (now).  Set up a
1381          * shared message so we can mark it as shared.
1382          */
1383         shared.type = H5O_SHARE_TYPE_SOHM;
1384 
1385 #ifdef H5_USING_MEMCHECKER
1386         /* Reset the shared message payload if deferring.  This doesn't matter
1387          *      in the long run since the payload will get overwritten when the
1388          *      non-deferred call to this routine occurs, but it stops memory
1389          *      checkers like valgrind from whining when the partially initialized
1390          *      shared message is serialized. -QAK
1391          */
1392         if(defer)
1393             HDmemset(&shared.u, 0, sizeof(shared.u));
1394 #endif /* H5_USING_MEMCHECKER */
1395     } /* end if */
1396     else {
1397         htri_t share_in_ohdr;           /* Whether the new message can be shared in another object's header */
1398 
1399         /* Add the message to the index */
1400 
1401         /* Check if the message can be shared in another object's header */
1402         if((share_in_ohdr = H5O_msg_can_share_in_ohdr(type_id)) < 0)
1403             HGOTO_ERROR(H5E_SOHM, H5E_BADTYPE, FAIL, "'share in ohdr' check returned error")
1404 
1405         /* If this message can be shared in an object header location, it is
1406          *      "shareable" but not shared in the heap.
1407          *
1408          * If 'defer' flag is set:
1409          *      We will insert it in the index but not modify the original
1410          *              message.
1411          *      If it can't be shared in an object header location, we will
1412          *              insert it in the heap.  Note that we will only share
1413          *              the message in the object header if there is an
1414          *              "open_oh" available.
1415          *
1416          * If 'defer' flag is not set:
1417          *      Insert it in the index but don't modify the original message.
1418          *      If it can't be shared in an object header location or there's
1419          *              no object header location available, insert it in the
1420          *              heap.
1421          */
1422         if(share_in_ohdr && open_oh) {
1423             /* Set up shared component info */
1424             shared.type = H5O_SHARE_TYPE_HERE;
1425 
1426             /* Retrieve any creation index from the native message */
1427             if(H5O_msg_get_crt_index(type_id, mesg, &shared.u.loc.index) < 0)
1428                 HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "unable to retrieve creation index")
1429 
1430             if(defer)
1431                 shared.u.loc.oh_addr = HADDR_UNDEF;
1432             else {
1433                 shared.u.loc.oh_addr = H5O_OH_GET_ADDR(open_oh);
1434 
1435                 /* Copy shared component info into key for inserting into index */
1436                 key.message.location = H5SM_IN_OH;
1437                 key.message.u.mesg_loc = shared.u.loc;
1438             } /* end else */
1439         } /* end if */
1440         else {
1441             /* Set up shared component info */
1442             /* (heap ID set below, if not deferred) */
1443             shared.type = H5O_SHARE_TYPE_SOHM;
1444 
1445             if(!defer) {
1446                 /* Put the message in the heap and record its new heap ID */
1447                 if(H5HF_insert(fheap, dxpl_id, key.encoding_size, key.encoding, &shared.u.heap_id) < 0)
1448                     HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to insert message into fractal heap")
1449 
1450                 key.message.location = H5SM_IN_HEAP;
1451                 key.message.u.heap_loc.fheap_id = shared.u.heap_id;
1452                 key.message.u.heap_loc.ref_count = 1;
1453             } /* end if */
1454         } /* end else */
1455 
1456         if(!defer) {
1457             /* Set common information */
1458             key.message.msg_type_id = type_id;
1459 
1460             /* Check whether the list has grown enough that it needs to become a B-tree */
1461             if(header->index_type == H5SM_LIST && header->num_messages >= header->list_max)
1462                 if(H5SM_convert_list_to_btree(f, header, &list, fheap, open_oh, dxpl_id) < 0)
1463                     HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to convert list to B-tree")
1464 
1465             /* Insert the new message into the SOHM index */
1466             if(header->index_type == H5SM_LIST) {
1467                 /* Index is a list.  Find an empty spot if we haven't already */
1468                 if(empty_pos == UFAIL) {
1469                     size_t pos;
1470 
1471                     if(H5SM__find_in_list(list, NULL, &empty_pos, &pos) < 0)
1472                         HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to search for message in list")
1473 
1474                     if(pos == UFAIL || empty_pos == UFAIL)
1475                         HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "unable to find empty entry in list")
1476                 }
1477                 /* Insert message into list */
1478                 HDassert(list->messages[empty_pos].location == H5SM_NO_LOC);
1479                 HDassert(key.message.location != H5SM_NO_LOC);
1480                 list->messages[empty_pos] = key.message;
1481             } /* end if */
1482             /* Index is a B-tree */
1483             else {
1484                 HDassert(header->index_type == H5SM_BTREE);
1485 
1486                 /* Open the index v2 B-tree, if it isn't already */
1487                 if(NULL == bt2) {
1488                     if(NULL == (bt2 = H5B2_open(f, dxpl_id, header->index_addr, f)))
1489                         HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
1490                 } /* end if */
1491 
1492                 if(H5B2_insert(bt2, dxpl_id, &key) < 0)
1493                     HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "couldn't add SOHM to B-tree")
1494             } /* end else */
1495 
1496             ++(header->num_messages);
1497             (*cache_flags_ptr) |= H5AC__DIRTIED_FLAG;
1498         } /* end if */
1499     } /* end else */
1500 
1501     /* Set the file pointer & message type for the shared component */
1502     shared.file = f;
1503     shared.msg_type_id = type_id;
1504 
1505     /* Update the original message's shared component */
1506     if(H5O_msg_set_share(type_id, &shared, mesg) < 0)
1507         HGOTO_ERROR(H5E_SOHM, H5E_BADMESG, FAIL, "unable to set sharing information")
1508 
1509 done:
1510     /* Release the fractal heap & v2 B-tree if we opened them */
1511     if(fheap && H5HF_close(fheap, dxpl_id) < 0)
1512         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
1513     if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
1514         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
1515 
1516     /* If we got a list out of the cache, release it (it is always dirty after writing a message) */
1517     if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, defer ? H5AC__NO_FLAGS_SET : H5AC__DIRTIED_FLAG) < 0)
1518 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM index")
1519 
1520     if(encoding_buf)
1521         encoding_buf = H5MM_xfree(encoding_buf);
1522 
1523     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
1524 } /* end H5SM_write_mesg() */
1525 
1526 
1527 /*-------------------------------------------------------------------------
1528  * Function:    H5SM_delete
1529  *
1530  * Purpose:     Given an object header message that is being deleted,
1531  *              checks if it is a SOHM.  If so, decrements its reference
1532  *              count.
1533  *
1534  *              If an object header is currently protected, it needs to
1535  *              be passed in as open_oh so the SM code doesn't try to
1536  *              re-protect it.
1537  *
1538  * Return:      Non-negative on success/Negative on failure
1539  *
1540  * Programmer:  James Laird
1541  *              Tuesday, May 2, 2006
1542  *
1543  *-------------------------------------------------------------------------
1544  */
1545 herr_t
H5SM_delete(H5F_t * f,hid_t dxpl_id,H5O_t * open_oh,H5O_shared_t * sh_mesg)1546 H5SM_delete(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh, H5O_shared_t *sh_mesg)
1547 {
1548     H5SM_master_table_t  *table = NULL;
1549     unsigned              cache_flags = H5AC__NO_FLAGS_SET;
1550     H5SM_table_cache_ud_t cache_udata;      /* User-data for callback */
1551     ssize_t               index_num;
1552     void                 *mesg_buf = NULL;
1553     void                 *native_mesg = NULL;
1554     unsigned              type_id;              /* Message type ID to operate on */
1555     herr_t                ret_value = SUCCEED;
1556 
1557     FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
1558 
1559     HDassert(f);
1560     HDassert(H5F_addr_defined(H5F_SOHM_ADDR(f)));
1561     HDassert(sh_mesg);
1562 
1563     /* Get message type */
1564     type_id = sh_mesg->msg_type_id;
1565 
1566     /* Set up user data for callback */
1567     cache_udata.f = f;
1568 
1569     /* Look up the master SOHM table */
1570     if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__NO_FLAGS_SET)))
1571 	HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
1572 
1573     /* Find the correct index and try to delete from it */
1574     if((index_num = H5SM_get_index(table, type_id)) < 0)
1575 	HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "unable to find correct SOHM index")
1576 
1577     /* If mesg_buf is not NULL, the message's reference count has reached
1578      * zero and any file space it uses needs to be freed.  mesg_buf holds the
1579      * serialized form of the message.
1580      */
1581     if(H5SM_delete_from_index(f, dxpl_id, open_oh, &(table->indexes[index_num]), sh_mesg, &cache_flags, &mesg_buf) < 0)
1582 	HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to delete mesage from SOHM index")
1583 
1584     /* Release the master SOHM table */
1585     if(H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, cache_flags) < 0)
1586 	HGOTO_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
1587     table = NULL;
1588 
1589     /* If buf was allocated, delete the message it holds.  This message may
1590      * reference other shared messages that also need to be deleted, so the
1591      * master table needs to be unprotected when we do this.
1592      */
1593     if(mesg_buf) {
1594         if(NULL == (native_mesg = H5O_msg_decode(f, dxpl_id, open_oh, type_id, (const unsigned char *)mesg_buf)))
1595             HGOTO_ERROR(H5E_SOHM, H5E_CANTDECODE, FAIL, "can't decode shared message.")
1596 
1597         if(H5O_msg_delete(f, dxpl_id, open_oh, type_id, native_mesg) < 0)
1598             HGOTO_ERROR(H5E_SOHM, H5E_CANTFREE, FAIL, "can't delete shared message.")
1599     } /* end if */
1600 
1601 done:
1602     /* Release the master SOHM table (should only happen on error) */
1603     if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, cache_flags) < 0)
1604 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
1605 
1606     /* Release any native message we decoded */
1607     if(native_mesg)
1608         H5O_msg_free(type_id, native_mesg);
1609 
1610     /* Free encoding buf */
1611     if(mesg_buf)
1612         mesg_buf = H5MM_xfree(mesg_buf);
1613 
1614     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
1615 } /* end H5SM_delete() */
1616 
1617 
1618 /*-------------------------------------------------------------------------
1619  * Function:    H5SM__find_in_list
1620  *
1621  * Purpose:     Find a message's location in a list.  Also find the first
1622  *              empty location in the list (since if we don't find the
1623  *              message, we may want to insert it into an open spot).
1624  *
1625  *              If KEY is NULL, simply find the first empty location in the
1626  *              list.
1627  *
1628  *              If EMPTY_POS is NULL, don't store anything in it.
1629  *
1630  * Return:      Message's position in the list on success
1631  *              UFAIL if message couldn't be found
1632  *              empty_pos set to position of empty message or UFAIL.
1633  *
1634  * Programmer:  James Laird
1635  *              Tuesday, May 2, 2006
1636  *
1637  *-------------------------------------------------------------------------
1638  */
1639 static herr_t
H5SM__find_in_list(const H5SM_list_t * list,const H5SM_mesg_key_t * key,size_t * empty_pos,size_t * pos)1640 H5SM__find_in_list(const H5SM_list_t *list, const H5SM_mesg_key_t *key, size_t *empty_pos, size_t *pos)
1641 {
1642     size_t x;
1643     herr_t ret_value = SUCCEED;       /* Return value */
1644 
1645     FUNC_ENTER_STATIC
1646 
1647     HDassert(list);
1648     /* Both key and empty_pos can be NULL, but not both! */
1649     HDassert(key || empty_pos);
1650 
1651     /* Initialize empty_pos to an invalid value */
1652     if(empty_pos)
1653         *empty_pos = UFAIL;
1654 
1655     /* Find the first (only) message equal to the key passed in.
1656      * Also record the first empty position we find.
1657      */
1658     for(x = 0; x < list->header->list_max; x++) {
1659         if(list->messages[x].location != H5SM_NO_LOC) {
1660             int cmp;
1661 
1662             if(H5SM__message_compare(key, &(list->messages[x]), &cmp) < 0)
1663                 HGOTO_ERROR(H5E_SOHM, H5E_CANTCOMPARE, FAIL, "can't compare message records")
1664 
1665             if(0 == cmp) {
1666                 *pos = x;
1667                 HGOTO_DONE(SUCCEED)
1668             }
1669         }
1670         else if(empty_pos && list->messages[x].location == H5SM_NO_LOC) {
1671             /* Note position */
1672             *empty_pos = x;
1673 
1674             /* Found earlier position possible, don't check any more */
1675             empty_pos = NULL;
1676         } /* end if */
1677     } /* end for */
1678 
1679     /* If we reached this point, we didn't find the message */
1680     *pos = UFAIL;
1681 
1682 done:
1683     FUNC_LEAVE_NOAPI(ret_value)
1684 } /* end H5SM__find_in_list */
1685 
1686 
1687 /*-------------------------------------------------------------------------
1688  * Function:	H5SM_get_hash_fh_cb
1689  *
1690  * Purpose:	Callback for fractal heap operator, to make copy of link when
1691  *              when lookup up a link by index
1692  *
1693  * Return:	SUCCEED/FAIL
1694  *
1695  * Programmer:	Quincey Koziol
1696  *		koziol@hdfgroup.org
1697  *		Nov  7 2006
1698  *
1699  *-------------------------------------------------------------------------
1700  */
1701 herr_t
H5SM_get_hash_fh_cb(const void * obj,size_t obj_len,void * _udata)1702 H5SM_get_hash_fh_cb(const void *obj, size_t obj_len, void *_udata)
1703 {
1704     H5SM_fh_ud_gh_t *udata = (H5SM_fh_ud_gh_t *)_udata;       /* User data for fractal heap 'op' callback */
1705 
1706     FUNC_ENTER_NOAPI_NOINIT_NOERR
1707 
1708     /* Compute hash value on raw message */
1709     udata->hash = H5_checksum_lookup3(obj, obj_len, udata->type_id);
1710 
1711     FUNC_LEAVE_NOAPI(SUCCEED)
1712 } /* end H5SM_get_hash_fh_cb() */
1713 
1714 
1715 /*-------------------------------------------------------------------------
1716  * Function:	H5SM_decr_ref
1717  *
1718  * Purpose:	Decrement the reference count for a SOHM message.  Doesn't
1719  *              remove the record from the B-tree even if the refcount
1720  *              reaches zero.
1721  *
1722  *              The new message is returned through op_data.  If its
1723  *              reference count is zero, the calling function should
1724  *              remove this record from the B-tree.
1725  *
1726  * Return:	Non-negative on success
1727  *              Negative on failure
1728  *
1729  * Programmer:	James Laird
1730  *              Monday, November 6, 2006
1731  *
1732  *-------------------------------------------------------------------------
1733  */
1734 static herr_t
H5SM_decr_ref(void * record,void * op_data,hbool_t * changed)1735 H5SM_decr_ref(void *record, void *op_data, hbool_t *changed)
1736 {
1737     H5SM_sohm_t *message = (H5SM_sohm_t *) record;
1738 
1739     FUNC_ENTER_NOAPI_NOINIT_NOERR
1740 
1741     HDassert(record);
1742     HDassert(op_data);
1743     HDassert(changed);
1744 
1745     /* Adjust the message's reference count if it's stored in the heap.
1746      * Messages stored in object headers always have refcounts of 1,
1747      * so the calling function should know to just delete such a message
1748      */
1749     if(message->location == H5SM_IN_HEAP) {
1750         --message->u.heap_loc.ref_count;
1751         *changed = TRUE;
1752     } /* end if */
1753 
1754     if(op_data)
1755        *(H5SM_sohm_t *)op_data = *message;
1756 
1757     FUNC_LEAVE_NOAPI(SUCCEED)
1758 } /* end H5SM_decr_ref() */
1759 
1760 
1761 /*-------------------------------------------------------------------------
1762  * Function:    H5SM_delete_from_index
1763  *
1764  * Purpose:     Decrement the reference count for a particular message in this
1765  *              index.  If the reference count reaches zero, allocate a buffer
1766  *              to hold the serialized form of this message so that any
1767  *              resources it uses can be freed, and return this buffer in
1768  *              ENCODED_MESG.
1769  *
1770  * Return:      Non-negative on success
1771  *              Negative on failure
1772  *
1773  * Programmer:  James Laird
1774  *              Tuesday, May 2, 2006
1775  *
1776  *-------------------------------------------------------------------------
1777  */
1778 static herr_t
H5SM_delete_from_index(H5F_t * f,hid_t dxpl_id,H5O_t * open_oh,H5SM_index_header_t * header,const H5O_shared_t * mesg,unsigned * cache_flags,void ** encoded_mesg)1779 H5SM_delete_from_index(H5F_t *f, hid_t dxpl_id, H5O_t *open_oh,
1780     H5SM_index_header_t *header, const H5O_shared_t *mesg,
1781     unsigned *cache_flags, void ** /*out*/ encoded_mesg)
1782 {
1783     H5SM_list_t     *list = NULL;
1784     H5SM_mesg_key_t key;
1785     H5SM_sohm_t     message;            /* Deleted message returned from index */
1786     H5SM_sohm_t    *message_ptr;        /* Pointer to deleted message returned from index */
1787     H5HF_t         *fheap = NULL;       /* Fractal heap that contains the message */
1788     H5B2_t         *bt2 = NULL;         /* v2 B-tree handle for index */
1789     size_t          buf_size;           /* Size of the encoded message (out) */
1790     void            *encoding_buf = NULL; /* The encoded message (out) */
1791     unsigned        type_id;            /* Message type to operate on */
1792     herr_t          ret_value = SUCCEED;
1793 
1794     FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
1795 
1796     /* Sanity check */
1797     HDassert(f);
1798     HDassert(header);
1799     HDassert(mesg);
1800     HDassert(cache_flags);
1801     HDassert(*encoded_mesg == NULL);
1802 
1803     /* Get the message type for later */
1804     type_id = mesg->msg_type_id;
1805 
1806     /* Open the heap for this type of message. */
1807     if(NULL == (fheap = H5HF_open(f, dxpl_id, header->heap_addr)))
1808 	HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
1809 
1810     /* Get the message size and encoded message for the message to be deleted,
1811      * either from its OH or from the heap.
1812      */
1813     if(mesg->type == H5O_SHARE_TYPE_HERE) {
1814         key.message.location = H5SM_IN_OH;
1815         key.message.msg_type_id = type_id;
1816         key.message.u.mesg_loc = mesg->u.loc;
1817     } /* end if */
1818     else {
1819         key.message.location = H5SM_IN_HEAP;
1820         key.message.msg_type_id = type_id;
1821         key.message.u.heap_loc.ref_count = 0; /* Refcount isn't relevant here */
1822         key.message.u.heap_loc.fheap_id = mesg->u.heap_id;
1823     } /* end else */
1824 
1825     /* Get the encoded message */
1826     if(H5SM_read_mesg(f, &key.message, fheap, open_oh, dxpl_id, &buf_size, &encoding_buf) < 0)
1827 	HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
1828 
1829     /* Set up key for message to be deleted. */
1830     key.file = f;
1831     key.dxpl_id = dxpl_id;
1832     key.fheap = fheap;
1833     key.encoding = encoding_buf;
1834     key.encoding_size = buf_size;
1835     key.message.hash = H5_checksum_lookup3(encoding_buf, buf_size, type_id);
1836 
1837     /* Try to find the message in the index */
1838     if(header->index_type == H5SM_LIST) {
1839         H5SM_list_cache_ud_t cache_udata;   /* User-data for metadata cache callback */
1840         size_t list_pos;        /* Position of the message in the list */
1841 
1842         /* Set up user data for metadata cache callback */
1843         cache_udata.f = f;
1844         cache_udata.header = header;
1845 
1846         /* If the index is stored as a list, get it from the cache */
1847         if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &cache_udata, H5AC__NO_FLAGS_SET)))
1848 	    HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index")
1849 
1850         /* Find the message in the list */
1851         if(H5SM__find_in_list(list, &key, NULL, &list_pos) < 0)
1852             HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "unable to search for message in list")
1853         if(list_pos == UFAIL)
1854 	    HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "message not in index")
1855 
1856         if(list->messages[list_pos].location == H5SM_IN_HEAP)
1857             --(list->messages[list_pos].u.heap_loc.ref_count);
1858 
1859         /* Point to the message */
1860         message_ptr = &list->messages[list_pos];
1861     } /* end if */
1862     else {
1863         /* Index is a B-tree */
1864         HDassert(header->index_type == H5SM_BTREE);
1865 
1866         /* Open the index v2 B-tree */
1867         if(NULL == (bt2 = H5B2_open(f, dxpl_id, header->index_addr, f)))
1868             HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
1869 
1870         /* If this returns failure, it means that the message wasn't found.
1871          * If it succeeds, a copy of the modified message will be returned.
1872          */
1873         if(H5B2_modify(bt2, dxpl_id, &key, H5SM_decr_ref, &message) < 0)
1874 	    HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "message not in index")
1875 
1876         /* Point to the message */
1877         message_ptr = &message;
1878     } /* end else */
1879 
1880     /* If the ref count is zero or this message was in an OH (which always
1881      * has a ref count of 1) delete the message from the index
1882      */
1883     if(message_ptr->location == H5SM_IN_OH || message_ptr->u.heap_loc.ref_count == 0) {
1884         /* Save the location */
1885         H5SM_storage_loc_t old_loc = message_ptr->location;
1886 
1887         /* Updated the index header, so set its dirty flag */
1888         --header->num_messages;
1889         *cache_flags |= H5AC__DIRTIED_FLAG;
1890 
1891         /* Remove the message from the index */
1892         if(header->index_type == H5SM_LIST)
1893             message_ptr->location = H5SM_NO_LOC;
1894         else {
1895             /* Open the index v2 B-tree, if it isn't already */
1896             if(NULL == bt2) {
1897                 if(NULL == (bt2 = H5B2_open(f, dxpl_id, header->index_addr, f)))
1898                     HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
1899             } /* end if */
1900 
1901             if(H5B2_remove(bt2, dxpl_id, &key, NULL, NULL) < 0)
1902                 HGOTO_ERROR(H5E_SOHM, H5E_CANTREMOVE, FAIL, "unable to delete message from index")
1903         } /* end else */
1904 
1905         /* Remove the message from the heap if it was stored in the heap*/
1906         if(old_loc == H5SM_IN_HEAP)
1907             if(H5HF_remove(fheap, dxpl_id, &(message_ptr->u.heap_loc.fheap_id)) < 0)
1908 	        HGOTO_ERROR(H5E_SOHM, H5E_CANTREMOVE, FAIL, "unable to remove message from heap")
1909 
1910 
1911         /* Return the message's encoding so anything it references can be freed */
1912         *encoded_mesg = encoding_buf;
1913 
1914         /* If there are no messages left in the index, delete it */
1915         if(header->num_messages == 0) {
1916 
1917             /* Unprotect cache and release heap */
1918             if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG) < 0)
1919 	        HGOTO_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to release SOHM list")
1920             list = NULL;
1921 
1922             HDassert(fheap);
1923             if(H5HF_close(fheap, dxpl_id) < 0)
1924                 HGOTO_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
1925             fheap = NULL;
1926 
1927             /* Delete the index and its heap */
1928             if(H5SM_delete_index(f, header, dxpl_id, TRUE) < 0)
1929                 HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "can't delete empty index")
1930         }  /* end if */
1931         else if(header->index_type == H5SM_BTREE && header->num_messages < header->btree_min) {
1932             /* Otherwise, if we've just passed the btree-to-list cutoff, convert
1933              * this B-tree into a list
1934              */
1935            if(H5SM_convert_btree_to_list(f, header, dxpl_id) < 0)
1936                 HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to convert btree to list")
1937         } /* end if */
1938     } /* end if */
1939 
1940 done:
1941     /* Release the SOHM list */
1942     if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__DIRTIED_FLAG) < 0)
1943 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM index")
1944 
1945     /* Release the fractal heap & v2 B-tree if we opened them */
1946     if(fheap && H5HF_close(fheap, dxpl_id) < 0)
1947         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
1948     if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
1949         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
1950 
1951     /* Free the message encoding, if we're not returning it in encoded_mesg
1952      * or if there's been an error.
1953      */
1954     if(encoding_buf && (NULL == *encoded_mesg || ret_value < 0))
1955         encoding_buf = H5MM_xfree(encoding_buf);
1956 
1957     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
1958 } /* end H5SM_delete_from_index() */
1959 
1960 
1961 /*-------------------------------------------------------------------------
1962  * Function:    H5SM_get_info
1963  *
1964  * Purpose:     Get the shared message info for a file, if there is any.
1965  *
1966  * Return:      Non-negative on success/Negative on failure
1967  *
1968  * Programmer:  James Laird
1969  *              Thursday, May 11, 2006
1970  *
1971  *-------------------------------------------------------------------------
1972  */
1973 herr_t
H5SM_get_info(const H5O_loc_t * ext_loc,H5P_genplist_t * fc_plist,hid_t dxpl_id)1974 H5SM_get_info(const H5O_loc_t *ext_loc, H5P_genplist_t *fc_plist, hid_t dxpl_id)
1975 {
1976     H5F_t *f = ext_loc->file;           /* File pointer (convenience variable) */
1977     H5O_shmesg_table_t sohm_table;      /* SOHM message from superblock extension */
1978     H5SM_master_table_t *table = NULL;  /* SOHM master table */
1979     H5P_genplist_t *dxpl = NULL;        /* DXPL for setting ring */
1980     H5AC_ring_t orig_ring = H5AC_RING_INV;      /* Original ring value */
1981     unsigned tmp_sohm_nindexes;		/* Number of shared messages indexes in the table */
1982     htri_t status;                      /* Status for message existing */
1983     herr_t ret_value = SUCCEED;         /* Return value */
1984 
1985     FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
1986 
1987     /* Sanity check */
1988     HDassert(ext_loc);
1989     HDassert(f);
1990     HDassert(fc_plist);
1991 
1992     /* Check for the extension having a 'shared message info' message */
1993     if((status = H5O_msg_exists(ext_loc, H5O_SHMESG_ID, dxpl_id)) < 0)
1994         HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "unable to read object header")
1995     if(status) {
1996         H5SM_table_cache_ud_t cache_udata;      /* User-data for callback */
1997         unsigned index_flags[H5O_SHMESG_MAX_NINDEXES];  /* Message flags for each index */
1998         unsigned minsizes[H5O_SHMESG_MAX_NINDEXES];     /* Minimum message size for each index */
1999         unsigned sohm_l2b;           /* SOHM list-to-btree cutoff */
2000         unsigned sohm_b2l;           /* SOHM btree-to-list cutoff */
2001         unsigned u;                  /* Local index variable */
2002 
2003         /* Retrieve the 'shared message info' structure */
2004         if(NULL == H5O_msg_read(ext_loc, H5O_SHMESG_ID, &sohm_table, dxpl_id))
2005             HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "shared message info message not present")
2006 
2007         /* Portably initialize the arrays */
2008         HDmemset(index_flags, 0, sizeof(index_flags));
2009         HDmemset(minsizes, 0, sizeof(minsizes));
2010 
2011         /* Set SOHM info from file */
2012         H5F_SET_SOHM_ADDR(f, sohm_table.addr);
2013         H5F_SET_SOHM_VERS(f, sohm_table.version);
2014         H5F_SET_SOHM_NINDEXES(f, sohm_table.nindexes);
2015         HDassert(H5F_addr_defined(H5F_SOHM_ADDR(f)));
2016         HDassert(H5F_SOHM_NINDEXES(f) > 0 && H5F_SOHM_NINDEXES(f) <= H5O_SHMESG_MAX_NINDEXES);
2017 
2018         /* Set up user data for callback */
2019         cache_udata.f = f;
2020 
2021         /* Set the ring type in the DXPL */
2022         if(H5AC_set_ring(dxpl_id, H5AC_RING_USER, &dxpl, &orig_ring) < 0)
2023             HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "unable to set ring value")
2024 
2025         /* Read the rest of the SOHM table information from the cache */
2026         if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
2027             HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
2028 
2029         /* Get index conversion limits */
2030         sohm_l2b = (unsigned)table->indexes[0].list_max;
2031         sohm_b2l = (unsigned)table->indexes[0].btree_min;
2032 
2033         /* Iterate through all indices */
2034         for(u = 0; u < table->num_indexes; ++u) {
2035             /* Pack information about the individual SOHM index */
2036             index_flags[u] = table->indexes[u].mesg_types;
2037             minsizes[u] = (unsigned)table->indexes[u].min_mesg_size;
2038 
2039             /* Sanity check */
2040             HDassert(sohm_l2b == table->indexes[u].list_max);
2041             HDassert(sohm_b2l == table->indexes[u].btree_min);
2042 
2043             /* Check for sharing attributes in this file, which means that creation
2044              *  indices must be tracked on object header message in the file.
2045              */
2046             if(index_flags[u] & H5O_SHMESG_ATTR_FLAG)
2047                 H5F_SET_STORE_MSG_CRT_IDX(f, TRUE);
2048         } /* end for */
2049 
2050         /* Set values in the property list */
2051         tmp_sohm_nindexes = H5F_SOHM_NINDEXES(f);
2052         if(H5P_set(fc_plist, H5F_CRT_SHMSG_NINDEXES_NAME, &tmp_sohm_nindexes) < 0)
2053             HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "can't set number of SOHM indexes")
2054         if(H5P_set(fc_plist, H5F_CRT_SHMSG_INDEX_TYPES_NAME, index_flags) < 0)
2055             HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "can't set type flags for indexes")
2056         if(H5P_set(fc_plist, H5F_CRT_SHMSG_INDEX_MINSIZE_NAME, minsizes) < 0)
2057             HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "can't set type flags for indexes")
2058         if(H5P_set(fc_plist, H5F_CRT_SHMSG_LIST_MAX_NAME, &sohm_l2b) < 0)
2059             HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't set SOHM cutoff in property list")
2060         if(H5P_set(fc_plist, H5F_CRT_SHMSG_BTREE_MIN_NAME, &sohm_b2l) < 0)
2061             HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't set SOHM cutoff in property list")
2062     } /* end if */
2063     else {
2064         /* No SOHM info in file */
2065         H5F_SET_SOHM_ADDR(f, HADDR_UNDEF);
2066         H5F_SET_SOHM_VERS(f, 0);
2067         H5F_SET_SOHM_NINDEXES(f, 0);
2068 
2069         /* Shared object header messages are disabled */
2070         tmp_sohm_nindexes = H5F_SOHM_NINDEXES(f);
2071         if(H5P_set(fc_plist, H5F_CRT_SHMSG_NINDEXES_NAME, &tmp_sohm_nindexes) < 0)
2072             HGOTO_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "can't set number of SOHM indexes")
2073     } /* end else */
2074 
2075 done:
2076     /* Reset the ring in the DXPL */
2077     if(H5AC_reset_ring(dxpl, orig_ring) < 0)
2078         HDONE_ERROR(H5E_SOHM, H5E_CANTSET, FAIL, "unable to set property value")
2079 
2080     /* Release the master SOHM table if we took it out of the cache */
2081     if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
2082 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
2083 
2084     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
2085 } /* end H5SM_get_info() */
2086 
2087 
2088 /*-------------------------------------------------------------------------
2089  * Function:    H5SM_reconstitute
2090  *
2091  * Purpose:     Reconstitute a shared object header message structure from
2092  *              a plain heap ID.
2093  *
2094  * Return:      Non-negative on success/Negative on failure
2095  *
2096  * Programmer:  Quincey Koziol
2097  *              Monday, December 18, 2006
2098  *
2099  *-------------------------------------------------------------------------
2100  */
2101 herr_t
H5SM_reconstitute(H5O_shared_t * sh_mesg,H5F_t * f,unsigned msg_type_id,H5O_fheap_id_t heap_id)2102 H5SM_reconstitute(H5O_shared_t *sh_mesg, H5F_t *f, unsigned msg_type_id,
2103     H5O_fheap_id_t heap_id)
2104 {
2105     FUNC_ENTER_NOAPI_NOINIT_NOERR
2106 
2107     /* Sanity check args */
2108     HDassert(sh_mesg);
2109 
2110     /* Set flag for shared message */
2111     sh_mesg->type = H5O_SHARE_TYPE_SOHM;
2112     sh_mesg->file = f;
2113     sh_mesg->msg_type_id = msg_type_id;
2114     sh_mesg->u.heap_id = heap_id;
2115 
2116     FUNC_LEAVE_NOAPI(SUCCEED)
2117 } /* end H5SM_reconstitute() */
2118 
2119 
2120 /*-------------------------------------------------------------------------
2121  * Function:	H5SM_get_refcount_bt2_cb
2122  *
2123  * Purpose:	v2 B-tree 'find' callback to retrieve the record for a message
2124  *
2125  * Return:	SUCCEED/FAIL
2126  *
2127  * Programmer:	Quincey Koziol
2128  *              Tuesday, December 19, 2006
2129  *
2130  *-------------------------------------------------------------------------
2131  */
2132 static herr_t
H5SM_get_refcount_bt2_cb(const void * _record,void * _op_data)2133 H5SM_get_refcount_bt2_cb(const void *_record, void *_op_data)
2134 {
2135     const H5SM_sohm_t *record = (const H5SM_sohm_t *)_record;  /* v2 B-tree record for message */
2136     H5SM_sohm_t *op_data = (H5SM_sohm_t *)_op_data;       /* "op data" from v2 B-tree find */
2137 
2138     FUNC_ENTER_NOAPI_NOINIT_NOERR
2139 
2140     /*
2141      * Check arguments.
2142      */
2143     HDassert(record);
2144     HDassert(op_data);
2145 
2146     /* Make a copy of the record */
2147     *op_data = *record;
2148 
2149     FUNC_LEAVE_NOAPI(SUCCEED)
2150 } /* end H5SM_get_refcount_bt2_cb() */
2151 
2152 
2153 /*-------------------------------------------------------------------------
2154  * Function:    H5SM_get_refcount
2155  *
2156  * Purpose:     Retrieve the reference count for a message shared in the heap
2157  *
2158  * Return:      Non-negative on success/Negative on failure
2159  *
2160  * Programmer:  Quincey Koziol
2161  *              Tuesday, December 19, 2006
2162  *
2163  *-------------------------------------------------------------------------
2164  */
2165 herr_t
H5SM_get_refcount(H5F_t * f,hid_t dxpl_id,unsigned type_id,const H5O_shared_t * sh_mesg,hsize_t * ref_count)2166 H5SM_get_refcount(H5F_t *f, hid_t dxpl_id, unsigned type_id,
2167     const H5O_shared_t *sh_mesg, hsize_t *ref_count)
2168 {
2169     H5HF_t *fheap = NULL;               /* Fractal heap that contains shared messages */
2170     H5B2_t *bt2 = NULL;                 /* v2 B-tree handle for index */
2171     H5SM_master_table_t *table = NULL;  /* SOHM master table */
2172     H5SM_table_cache_ud_t tbl_cache_udata;  /* User-data for callback */
2173     H5SM_list_t *list = NULL;           /* SOHM index list for message type (if in list form) */
2174     H5SM_index_header_t *header=NULL;   /* Index header for message type */
2175     H5SM_mesg_key_t key;                /* Key for looking up message */
2176     H5SM_sohm_t message;                /* Shared message returned from callback */
2177     ssize_t index_num;                  /* Table index for message type */
2178     size_t buf_size;                    /* Size of the encoded message */
2179     void * encoding_buf = NULL;         /* Buffer for encoded message */
2180     herr_t ret_value = SUCCEED;         /* Return value */
2181 
2182     FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
2183 
2184     /* Sanity check */
2185     HDassert(f);
2186     HDassert(sh_mesg);
2187     HDassert(ref_count);
2188 
2189     /* Set up user data for callback */
2190     tbl_cache_udata.f = f;
2191 
2192     /* Look up the master SOHM table */
2193     if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &tbl_cache_udata, H5AC__READ_ONLY_FLAG)))
2194 	HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
2195 
2196     /* Find the correct index and find the message in it */
2197     if((index_num = H5SM_get_index(table, type_id)) < 0)
2198 	HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "unable to find correct SOHM index")
2199     header = &(table->indexes[index_num]);
2200 
2201     /* Open the heap for this message type */
2202     if(NULL == (fheap = H5HF_open(f, dxpl_id, header->heap_addr)))
2203 	HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
2204 
2205     /* Set up a SOHM message to correspond to the shared message passed in */
2206     key.message.location = H5SM_IN_HEAP;
2207     key.message.u.heap_loc.fheap_id = sh_mesg->u.heap_id;
2208     key.message.u.heap_loc.ref_count = 0; /* Ref count isn't needed to find message */
2209 
2210     /* Get the encoded message */
2211     if(H5SM_read_mesg(f, &key.message, fheap, NULL, dxpl_id, &buf_size, &encoding_buf) < 0)
2212 	HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
2213 
2214     /* Set up key for message to locate */
2215     key.file = f;
2216     key.dxpl_id = dxpl_id;
2217     key.fheap = fheap;
2218     key.encoding = encoding_buf;
2219     key.encoding_size = buf_size;
2220     key.message.hash = H5_checksum_lookup3(encoding_buf, buf_size, type_id);
2221 
2222     /* Try to find the message in the index */
2223     if(header->index_type == H5SM_LIST) {
2224         H5SM_list_cache_ud_t lst_cache_udata;  /* User-data for metadata cache callback */
2225         size_t list_pos;        /* Position of the message in the list */
2226 
2227         /* Set up user data for metadata cache callback */
2228         lst_cache_udata.f = f;
2229         lst_cache_udata.header = header;
2230 
2231         /* If the index is stored as a list, get it from the cache */
2232         if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, &lst_cache_udata, H5AC__READ_ONLY_FLAG)))
2233 	    HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index")
2234 
2235         /* Find the message in the list */
2236         if(H5SM__find_in_list(list, &key, NULL, &list_pos) < 0)
2237             HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "unable to search for message in list")
2238         if(list_pos == UFAIL)
2239 	    HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "message not in index")
2240 
2241         /* Copy the message */
2242         message = list->messages[list_pos];
2243     } /* end if */
2244     else {
2245         htri_t msg_exists;      /* Whether the message exists in the v2 B-tree */
2246 
2247         /* Index is a B-tree */
2248         HDassert(header->index_type == H5SM_BTREE);
2249 
2250         /* Open the index v2 B-tree */
2251         if(NULL == (bt2 = H5B2_open(f, dxpl_id, header->index_addr, f)))
2252             HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
2253 
2254         /* Look up the message in the v2 B-tree */
2255         if((msg_exists = H5B2_find(bt2, dxpl_id, &key, H5SM_get_refcount_bt2_cb, &message)) < 0)
2256             HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "error finding message in index")
2257         if(!msg_exists)
2258 	    HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "message not in index")
2259     } /* end else */
2260 
2261     /* Set the refcount for the message */
2262     HDassert(message.location == H5SM_IN_HEAP);
2263     *ref_count = message.u.heap_loc.ref_count;
2264 
2265 done:
2266     /* Release resources */
2267     if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__NO_FLAGS_SET) < 0)
2268 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM index")
2269     if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
2270 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
2271     if(fheap && H5HF_close(fheap, dxpl_id) < 0)
2272         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
2273     if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
2274         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
2275     if(encoding_buf)
2276         encoding_buf = H5MM_xfree(encoding_buf);
2277 
2278     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
2279 } /* end H5SM_get_refcount() */
2280 
2281 
2282 /*-------------------------------------------------------------------------
2283  * Function:	H5SM_read_iter_op
2284  *
2285  * Purpose:	OH iteration callback to get the encoded version of a message
2286  *              by index.
2287  *
2288  *              The buffer needs to be freed.
2289  *
2290  * Return:	0 if this is not the message we're searching for
2291  *              1 if this is the message we're searching for (with encoded
2292  *                      value returned in udata)
2293  *              negative on error
2294  *
2295  * Programmer:	James Laird
2296  *              Wednesday, February 21, 2006
2297  *
2298  *-------------------------------------------------------------------------
2299  */
2300 static herr_t
H5SM_read_iter_op(H5O_t * oh,H5O_mesg_t * mesg,unsigned sequence,unsigned H5_ATTR_UNUSED * oh_modified,void * _udata)2301 H5SM_read_iter_op(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, unsigned sequence,
2302     unsigned H5_ATTR_UNUSED *oh_modified, void *_udata/*in,out*/)
2303 {
2304     H5SM_read_udata_t *udata = (H5SM_read_udata_t *) _udata;
2305     herr_t ret_value = H5_ITER_CONT;
2306 
2307     FUNC_ENTER_NOAPI_NOINIT
2308 
2309     /*
2310      * Check arguments.
2311      */
2312     HDassert(oh);
2313     HDassert(mesg);
2314     HDassert(udata);
2315     HDassert(NULL == udata->encoding_buf);
2316 
2317     /* Check the creation index for this message */
2318     if(sequence == udata->idx) {
2319         /* Check if the message is dirty & flush it to the object header if so */
2320         if(mesg->dirty)
2321             if(H5O_msg_flush(udata->file, oh, mesg) < 0)
2322                 HGOTO_ERROR(H5E_SOHM, H5E_CANTENCODE, H5_ITER_ERROR, "unable to encode object header message")
2323 
2324         /* Get the message's encoded size */
2325         udata->buf_size = mesg->raw_size;
2326         HDassert(udata->buf_size);
2327 
2328         /* Allocate buffer to return the message in */
2329         if(NULL == (udata->encoding_buf = H5MM_malloc(udata->buf_size)))
2330             HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, H5_ITER_ERROR, "memory allocation failed")
2331 
2332         /* Copy the encoded message into the buffer to return */
2333         HDmemcpy(udata->encoding_buf, mesg->raw, udata->buf_size);
2334 
2335         /* Found the message we were looking for */
2336         ret_value = H5_ITER_STOP;
2337     } /* end if */
2338 
2339 done:
2340     FUNC_LEAVE_NOAPI(ret_value)
2341 } /* end H5SM_read_iter_op() */
2342 
2343 
2344 /*-------------------------------------------------------------------------
2345  * Function:	H5SM_read_mesg_fh_cb
2346  *
2347  * Purpose:	Callback for H5HF_op, used in H5SM_read_mesg below.
2348  *              Makes a copy of the message in the heap data, returned in the
2349  *              UDATA struct.
2350  *
2351  * Return:	Negative on error, non-negative on success
2352  *
2353  * Programmer:	Quincey Koziol
2354  *              Tuesday, June 26, 2007
2355  *
2356  *-------------------------------------------------------------------------
2357  */
2358 static herr_t
H5SM_read_mesg_fh_cb(const void * obj,size_t obj_len,void * _udata)2359 H5SM_read_mesg_fh_cb(const void *obj, size_t obj_len, void *_udata)
2360 {
2361     H5SM_read_udata_t *udata = (H5SM_read_udata_t *)_udata;
2362     herr_t ret_value = SUCCEED;
2363 
2364     FUNC_ENTER_NOAPI_NOINIT
2365 
2366     /* Allocate a buffer to hold the message */
2367     if(NULL == (udata->encoding_buf = H5MM_malloc(obj_len)))
2368         HGOTO_ERROR(H5E_SOHM, H5E_NOSPACE, FAIL, "memory allocation failed")
2369 
2370     /* Copy the message from the heap */
2371     HDmemcpy(udata->encoding_buf, obj, obj_len);
2372     udata->buf_size = obj_len;
2373 
2374 done:
2375     FUNC_LEAVE_NOAPI(ret_value)
2376 } /* end H5SM_read_mesg_fh_cb() */
2377 
2378 
2379 /*-------------------------------------------------------------------------
2380  * Function:	H5SM_read_mesg
2381  *
2382  * Purpose:	Given an H5SM_sohm_t sohm, encodes the message into a buffer.
2383  *              This buffer should then be freed.
2384  *
2385  * Return:	Non-negative on success/negative on error
2386  *
2387  * Programmer:	James Laird
2388  *              Wednesday, February 21, 2006
2389  *
2390  *-------------------------------------------------------------------------
2391  */
2392 static herr_t
H5SM_read_mesg(H5F_t * f,const H5SM_sohm_t * mesg,H5HF_t * fheap,H5O_t * open_oh,hid_t dxpl_id,size_t * encoding_size,void ** encoded_mesg)2393 H5SM_read_mesg(H5F_t *f, const H5SM_sohm_t *mesg, H5HF_t *fheap,
2394     H5O_t *open_oh, hid_t dxpl_id, size_t *encoding_size /*out*/,
2395     void ** encoded_mesg /*out*/)
2396 {
2397     H5SM_read_udata_t udata;    /* User data for callbacks */
2398     H5O_loc_t oloc;             /* Object location for message in object header */
2399     H5O_t *oh = NULL;           /* Object header for message in object header */
2400     herr_t ret_value = SUCCEED;
2401 
2402     FUNC_ENTER_NOAPI_NOINIT_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
2403 
2404     HDassert(f);
2405     HDassert(mesg);
2406     HDassert(fheap);
2407 
2408     /* Set up user data for message iteration */
2409     udata.file = f;
2410     udata.idx = mesg->u.mesg_loc.index;
2411     udata.encoding_buf = NULL;
2412     udata.idx = 0;
2413 
2414     /* Get the message size and encoded message for the message to be deleted,
2415      * either from its OH or from the heap.
2416      */
2417     if(mesg->location == H5SM_IN_OH) {
2418         /* Read message from object header */
2419         const H5O_msg_class_t *type = NULL;    /* Actual H5O class type for the ID */
2420         H5O_mesg_operator_t op;         /* Wrapper for operator */
2421 
2422         type = H5O_msg_class_g[mesg->msg_type_id];    /* map the type ID to the actual type object */
2423         HDassert(type);
2424 
2425         /* Reset object location for operation */
2426         if(H5O_loc_reset(&oloc) < 0)
2427             HGOTO_ERROR(H5E_SOHM, H5E_CANTRESET, FAIL, "unable to initialize location")
2428 
2429         if(NULL == open_oh || mesg->u.mesg_loc.oh_addr != H5O_OH_GET_ADDR(open_oh)) {
2430             /* Open the object in the file */
2431             oloc.file = f;
2432             oloc.addr = mesg->u.mesg_loc.oh_addr;
2433             if(H5O_open(&oloc) < 0)
2434 	        HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, FAIL, "unable to open object header")
2435 
2436             /* Load the object header from the cache */
2437             if(NULL == (oh = H5O_protect(&oloc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
2438 	        HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load object header")
2439         } /* end if */
2440         else
2441             oh = open_oh;
2442 
2443         /* Use the "real" iterate routine so it doesn't try to protect the OH */
2444         op.op_type = H5O_MESG_OP_LIB;
2445         op.u.lib_op = H5SM_read_iter_op;
2446         if((ret_value = H5O_msg_iterate_real(f, oh, type, &op, &udata, dxpl_id)) < 0)
2447             HGOTO_ERROR(H5E_SOHM, H5E_BADITER, FAIL, "unable to iterate over object header messages")
2448     } /* end if */
2449     else {
2450         HDassert(mesg->location == H5SM_IN_HEAP);
2451 
2452         /* Copy the message from the heap */
2453         if(H5HF_op(fheap, dxpl_id, &(mesg->u.heap_loc.fheap_id), H5SM_read_mesg_fh_cb, &udata) < 0)
2454             HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, FAIL, "can't read message from fractal heap.")
2455     } /* end else */
2456     HDassert(udata.encoding_buf);
2457     HDassert(udata.buf_size);
2458 
2459     /* Record the returned values */
2460     *encoded_mesg = udata.encoding_buf;
2461     *encoding_size = udata.buf_size;
2462 
2463 done:
2464     /* Close the object header if we opened one and had an error */
2465     if(oh && oh != open_oh) {
2466         if(oh && H5O_unprotect(&oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
2467             HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
2468         if(H5O_close(&oloc, NULL) < 0)
2469             HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "unable to close object header")
2470     } /* end if */
2471 
2472     /* Release the encoding buffer on error */
2473     if(ret_value < 0 && udata.encoding_buf)
2474         udata.encoding_buf = H5MM_xfree(udata.encoding_buf);
2475 
2476     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
2477 } /* end H5SM_read_mesg */
2478 
2479 
2480 /*-------------------------------------------------------------------------
2481  * Function:	H5SM_table_free
2482  *
2483  * Purpose:	Frees memory used by the SOHM table.
2484  *
2485  * Return:	Non-negative on success/Negative on failure
2486  *
2487  * Programmer:	James Laird
2488  *		November 6, 2006
2489  *
2490  *-------------------------------------------------------------------------
2491  */
2492 herr_t
H5SM_table_free(H5SM_master_table_t * table)2493 H5SM_table_free(H5SM_master_table_t *table)
2494 {
2495     FUNC_ENTER_NOAPI_NOINIT_NOERR
2496 
2497     /* Sanity check */
2498     HDassert(table);
2499     HDassert(table->indexes);
2500 
2501     table->indexes = H5FL_ARR_FREE(H5SM_index_header_t, table->indexes);
2502 
2503     table = H5FL_FREE(H5SM_master_table_t, table);
2504 
2505     FUNC_LEAVE_NOAPI(SUCCEED)
2506 } /* end H5SM_table_free() */
2507 
2508 
2509 /*-------------------------------------------------------------------------
2510  * Function:	H5SM_list_free
2511  *
2512  * Purpose:	Frees all memory used by the list.
2513  *
2514  * Return:	Non-negative on success/Negative on failure
2515  *
2516  * Programmer:	James Laird
2517  *		November 6, 2006
2518  *
2519  *-------------------------------------------------------------------------
2520  */
2521 herr_t
H5SM_list_free(H5SM_list_t * list)2522 H5SM_list_free(H5SM_list_t *list)
2523 {
2524     FUNC_ENTER_NOAPI_NOINIT_NOERR
2525 
2526     HDassert(list);
2527     HDassert(list->messages);
2528 
2529     list->messages = H5FL_ARR_FREE(H5SM_sohm_t, list->messages);
2530 
2531     list = H5FL_FREE(H5SM_list_t, list);
2532 
2533     FUNC_LEAVE_NOAPI(SUCCEED)
2534 } /* end H5SM_list_free() */
2535 
2536 
2537 /*-------------------------------------------------------------------------
2538  * Function:    H5SM_table_debug
2539  *
2540  * Purpose:     Print debugging information for the master table.
2541  *
2542  *              If table_vers and num_indexes are not UFAIL, they are used
2543  *              instead of the values in the superblock.
2544  *
2545  * Return:      Non-negative on success/Negative on failure
2546  *
2547  * Programmer:  James Laird
2548  *              Thursday, January 18, 2007
2549  *
2550  *-------------------------------------------------------------------------
2551  */
2552 herr_t
H5SM_table_debug(H5F_t * f,hid_t dxpl_id,haddr_t table_addr,FILE * stream,int indent,int fwidth,unsigned table_vers,unsigned num_indexes)2553 H5SM_table_debug(H5F_t *f, hid_t dxpl_id, haddr_t table_addr,
2554                          FILE *stream, int indent, int fwidth,
2555                          unsigned table_vers, unsigned num_indexes)
2556 {
2557     H5SM_master_table_t *table = NULL;  /* SOHM master table */
2558     H5SM_table_cache_ud_t cache_udata;  /* User-data for callback */
2559     unsigned x;                         /* Counter variable */
2560     herr_t ret_value = SUCCEED;         /* Return value */
2561 
2562     FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
2563 
2564     HDassert(f);
2565     HDassert(table_addr != HADDR_UNDEF);
2566     HDassert(stream);
2567     HDassert(indent >= 0);
2568     HDassert(fwidth >= 0);
2569 
2570     /* If table_vers and num_indexes are UFAIL, replace them with values from
2571      * userblock
2572      */
2573     if(table_vers == UFAIL)
2574         table_vers = H5F_SOHM_VERS(f);
2575     else if(table_vers != H5F_SOHM_VERS(f))
2576 	HDfprintf(stream, "*** SOHM TABLE VERSION DOESN'T MATCH VERSION IN SUPERBLOCK!\n");
2577     if(num_indexes == UFAIL)
2578         num_indexes = H5F_SOHM_NINDEXES(f);
2579     else if(num_indexes != H5F_SOHM_NINDEXES(f))
2580 	HDfprintf(stream, "*** NUMBER OF SOHM INDEXES DOESN'T MATCH VALUE IN SUPERBLOCK!\n");
2581 
2582     /* Check arguments.  Version must be 0, the only version implemented so far */
2583     if(table_vers > HDF5_SHAREDHEADER_VERSION)
2584         HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, FAIL, "unknown shared message table version")
2585     if(num_indexes == 0 || num_indexes > H5O_SHMESG_MAX_NINDEXES)
2586         HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, FAIL, "number of indexes must be between 1 and H5O_SHMESG_MAX_NINDEXES")
2587 
2588     /* Set up user data for callback */
2589     cache_udata.f = f;
2590 
2591     /* Look up the master SOHM table */
2592     if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
2593 	HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
2594 
2595     HDfprintf(stream, "%*sShared Message Master Table...\n", indent, "");
2596     for(x = 0; x < num_indexes; ++x) {
2597         HDfprintf(stream, "%*sIndex %d...\n", indent, "", x);
2598         HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth,
2599                 "SOHM Index Type:",
2600                 (table->indexes[x].index_type == H5SM_LIST ? "List" :
2601                 (table->indexes[x].index_type == H5SM_BTREE ? "B-Tree" : "Unknown")));
2602 
2603         HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", fwidth,
2604                 "Address of index:", table->indexes[x].index_addr);
2605         HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", fwidth,
2606                 "Address of index's heap:", table->indexes[x].heap_addr);
2607         HDfprintf(stream, "%*s%-*s 0x%08x\n", indent + 3, "", fwidth,
2608                 "Message type flags:", table->indexes[x].mesg_types);
2609         HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", fwidth,
2610                 "Minimum size of messages:", table->indexes[x].min_mesg_size);
2611         HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", fwidth,
2612                 "Number of messages:", table->indexes[x].num_messages);
2613         HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", fwidth,
2614                 "Maximum list size:", table->indexes[x].list_max);
2615         HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", fwidth,
2616                 "Minimum B-tree size:", table->indexes[x].btree_min);
2617     } /* end for */
2618 
2619 done:
2620     if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, table, H5AC__NO_FLAGS_SET) < 0)
2621 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
2622 
2623     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
2624 } /* end H5SM_table_debug() */
2625 
2626 
2627 /*-------------------------------------------------------------------------
2628  * Function:    H5SM_list_debug
2629  *
2630  * Purpose:     Print debugging information for a SOHM list.
2631  *
2632  *              Relies on the list version and number of messages passed in.
2633  *
2634  * Return:      Non-negative on success/Negative on failure
2635  *
2636  * Programmer:  James Laird
2637  *              Thursday, January 18, 2007
2638  *
2639  *-------------------------------------------------------------------------
2640  */
2641 herr_t
H5SM_list_debug(H5F_t * f,hid_t dxpl_id,haddr_t list_addr,FILE * stream,int indent,int fwidth,haddr_t table_addr)2642 H5SM_list_debug(H5F_t *f, hid_t dxpl_id, haddr_t list_addr, FILE *stream,
2643     int indent, int fwidth, haddr_t table_addr)
2644 {
2645     H5SM_master_table_t *table = NULL;  /* SOHM master table */
2646     H5SM_list_t *list = NULL;           /* SOHM index list for message type (if in list form) */
2647     H5SM_list_cache_ud_t lst_cache_udata;   /* List user-data for metadata cache callback */
2648     H5SM_table_cache_ud_t tbl_cache_udata;  /* Table user-data for metadata cache callback */
2649     H5HF_t *fh = NULL;                  /* Fractal heap for SOHM messages */
2650     unsigned index_num;                 /* Index of list, within master table */
2651     unsigned x;                         /* Counter variable */
2652     herr_t ret_value = SUCCEED;         /* Return value */
2653 
2654     FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
2655 
2656     HDassert(f);
2657     HDassert(list_addr != HADDR_UNDEF);
2658     HDassert(stream);
2659     HDassert(indent >= 0);
2660     HDassert(fwidth >= 0);
2661 
2662     /* Set up user data for callback */
2663     tbl_cache_udata.f = f;
2664 
2665     /* Look up the master SOHM table */
2666     if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, &tbl_cache_udata, H5AC__READ_ONLY_FLAG)))
2667 	HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
2668 
2669     /* Determine which index the list is part of */
2670     index_num = table->num_indexes;
2671     for(x = 0; x < table->num_indexes; x++) {
2672         if(H5F_addr_eq(table->indexes[x].index_addr, list_addr)) {
2673             index_num = x;
2674             break;
2675         } /* end if */
2676     } /* end for */
2677     if(x == table->num_indexes)
2678         HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, FAIL, "list address doesn't match address for any indices in table")
2679 
2680     /* Set up user data for metadata cache callback */
2681     lst_cache_udata.f = f;
2682     lst_cache_udata.header = &(table->indexes[index_num]);
2683 
2684     /* Get the list from the cache */
2685     if(NULL == (list = (H5SM_list_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, list_addr, &lst_cache_udata, H5AC__READ_ONLY_FLAG)))
2686 	HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index")
2687 
2688     /* Open the heap, if one exists */
2689     if(H5F_addr_defined(table->indexes[index_num].heap_addr))
2690         if(NULL == (fh = H5HF_open(f, dxpl_id, table->indexes[index_num].heap_addr)))
2691             HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open SOHM heap")
2692 
2693     HDfprintf(stream, "%*sShared Message List Index...\n", indent, "");
2694     for(x = 0; x < table->indexes[index_num].num_messages; ++x) {
2695         HDfprintf(stream, "%*sShared Object Header Message %d...\n", indent, "", x);
2696         HDfprintf(stream, "%*s%-*s %08lu\n", indent + 3, "", fwidth,
2697                 "Hash value:", (unsigned long)list->messages[x].hash);
2698         if(list->messages[x].location == H5SM_IN_HEAP) {
2699             HDassert(fh);
2700 
2701             HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth,
2702                     "Location:", "in heap");
2703             HDfprintf(stream, "%*s%-*s 0x%Zx\n", indent + 3, "", fwidth,
2704                     "Heap ID:", list->messages[x].u.heap_loc.fheap_id);
2705             HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", fwidth,
2706                     "Reference count:", list->messages[x].u.heap_loc.ref_count);
2707         } /* end if */
2708         else if(list->messages[x].location == H5SM_IN_OH) {
2709             HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth,
2710                     "Location:", "in object header");
2711             HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", fwidth,
2712                     "Object header address:", list->messages[x].u.mesg_loc.oh_addr);
2713             HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", fwidth,
2714                     "Message creation index:", list->messages[x].u.mesg_loc.oh_addr);
2715             HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", fwidth,
2716                     "Message type ID:", list->messages[x].msg_type_id);
2717         } /* end if */
2718         else
2719             HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", fwidth,
2720                     "Location:", "invalid");
2721     } /* end for */
2722 
2723 done:
2724     if(fh && H5HF_close(fh, dxpl_id) < 0)
2725 	HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "unable to close SOHM heap")
2726     if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, list_addr, list, H5AC__NO_FLAGS_SET) < 0)
2727 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM index")
2728     if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, table, H5AC__NO_FLAGS_SET) < 0)
2729 	HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
2730 
2731     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
2732 } /* end H5SM_list_debug() */
2733 
2734 
2735 /*-------------------------------------------------------------------------
2736  * Function:    H5SM_ih_size
2737  *
2738  * Purpose:     Loop through the master SOHM table (if there is one) to:
2739  *			1. collect storage used for header
2740  *                      1. collect storage used for B-tree and List
2741  *			   (include btree storage used by huge objects in fractal heap)
2742  *                      2. collect fractal heap storage
2743  *
2744  * Return:      Non-negative on success/Negative on failure
2745  *
2746  * Programmer:  Vailin Choi
2747  *              June 19, 2007
2748  *
2749  *-------------------------------------------------------------------------
2750  */
2751 herr_t
H5SM_ih_size(H5F_t * f,hid_t dxpl_id,hsize_t * hdr_size,H5_ih_info_t * ih_info)2752 H5SM_ih_size(H5F_t *f, hid_t dxpl_id, hsize_t *hdr_size, H5_ih_info_t *ih_info)
2753 {
2754     H5SM_master_table_t *table = NULL;          /* SOHM master table */
2755     H5SM_table_cache_ud_t cache_udata;          /* User-data for callback */
2756     H5HF_t              *fheap = NULL;          /* Fractal heap handle */
2757     H5B2_t              *bt2 = NULL;            /* v2 B-tree handle for index */
2758     unsigned             u;                     /* Local index variable */
2759     herr_t               ret_value = SUCCEED;   /* Return value */
2760 
2761     FUNC_ENTER_NOAPI_TAG(dxpl_id, H5AC__SOHM_TAG, FAIL)
2762 
2763     /* Sanity check */
2764     HDassert(f);
2765     HDassert(H5F_addr_defined(H5F_SOHM_ADDR(f)));
2766     HDassert(hdr_size);
2767     HDassert(ih_info);
2768 
2769     /* Set up user data for callback */
2770     cache_udata.f = f;
2771 
2772     /* Look up the master SOHM table */
2773     if(NULL == (table = (H5SM_master_table_t *)H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), &cache_udata, H5AC__READ_ONLY_FLAG)))
2774 	HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
2775 
2776     /* Get SOHM header size */
2777     *hdr_size = table->table_size;
2778 
2779     /* Loop over all the indices for shared messages */
2780     for(u = 0; u < table->num_indexes; u++) {
2781         /* Get index storage size (for either B-tree or list) */
2782 	if(table->indexes[u].index_type == H5SM_BTREE) {
2783 	    if(H5F_addr_defined(table->indexes[u].index_addr)) {
2784                 /* Open the index v2 B-tree */
2785                 if(NULL == (bt2 = H5B2_open(f, dxpl_id, table->indexes[u].index_addr, f)))
2786                     HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for SOHM index")
2787 
2788 		if(H5B2_size(bt2, dxpl_id, &(ih_info->index_size)) < 0)
2789                     HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't retrieve B-tree storage info")
2790 
2791                 /* Close the v2 B-tree */
2792                 if(H5B2_close(bt2, dxpl_id) < 0)
2793                     HGOTO_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
2794                 bt2 = NULL;
2795             } /* end if */
2796         } /* end if */
2797         else {
2798             HDassert(table->indexes[u].index_type == H5SM_LIST);
2799 	    ih_info->index_size += table->indexes[u].list_size;
2800         } /* end else */
2801 
2802         /* Check for heap for this index */
2803 	if(H5F_addr_defined(table->indexes[u].heap_addr)) {
2804             /* Open the fractal heap for this index */
2805             if(NULL == (fheap = H5HF_open(f, dxpl_id, table->indexes[u].heap_addr)))
2806                 HGOTO_ERROR(H5E_SOHM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
2807 
2808             /* Get heap storage size */
2809 	    if(H5HF_size(fheap, dxpl_id, &(ih_info->heap_size)) < 0)
2810 		HGOTO_ERROR(H5E_SOHM, H5E_CANTGET, FAIL, "can't retrieve fractal heap storage info")
2811 
2812             /* Close the fractal heap */
2813             if(H5HF_close(fheap, dxpl_id) < 0)
2814                 HGOTO_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
2815             fheap = NULL;
2816         } /* end if */
2817     } /* end for */
2818 
2819 done:
2820     /* Release resources */
2821     if(fheap && H5HF_close(fheap, dxpl_id) < 0)
2822         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close fractal heap")
2823     if(bt2 && H5B2_close(bt2, dxpl_id) < 0)
2824         HDONE_ERROR(H5E_SOHM, H5E_CANTCLOSEOBJ, FAIL, "can't close v2 B-tree for SOHM index")
2825     if(table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, H5F_SOHM_ADDR(f), table, H5AC__NO_FLAGS_SET) < 0)
2826         HDONE_ERROR(H5E_SOHM, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM master table")
2827 
2828     FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL)
2829 } /* end H5SM_ih_size() */
2830 
2831