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