1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the files COPYING and Copyright.html. COPYING can be found at the root *
9 * of the source code distribution tree; Copyright.html can be found at the *
10 * root level of an installed copy of the electronic HDF5 document set and *
11 * is linked from the top-level documents page. It can also be found at *
12 * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
13 * access to either file, you may request a copy from help@hdfgroup.org. *
14 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /*-------------------------------------------------------------------------
17 *
18 * Created: H5AC.c
19 * Jul 9 1997
20 * Robb Matzke <matzke@llnl.gov>
21 *
22 * Purpose: Functions in this file implement a cache for
23 * things which exist on disk. All "things" associated
24 * with a particular HDF file share the same cache; each
25 * HDF file has it's own cache.
26 *
27 *-------------------------------------------------------------------------
28 */
29
30 #define H5AC_PACKAGE /*suppress error about including H5ACpkg */
31 #define H5C_PACKAGE /*suppress error about including H5Cpkg */
32 #define H5F_PACKAGE /*suppress error about including H5Fpkg */
33
34 /* Interface initialization */
35 #define H5_INTERFACE_INIT_FUNC H5AC_init_interface
36
37 #ifdef H5_HAVE_PARALLEL
38 #include <mpi.h>
39 #endif /* H5_HAVE_PARALLEL */
40
41 #include "H5private.h" /* Generic Functions */
42 #include "H5ACpkg.h" /* Metadata cache */
43 #include "H5Cpkg.h" /* Cache */
44 #include "H5Dprivate.h" /* Dataset functions */
45 #include "H5Eprivate.h" /* Error handling */
46 #include "H5Fpkg.h" /* Files */
47 #include "H5FDprivate.h" /* File drivers */
48 #include "H5FLprivate.h" /* Free Lists */
49 #include "H5Iprivate.h" /* IDs */
50 #include "H5MMprivate.h" /* Memory management */
51 #include "H5Pprivate.h" /* Property lists */
52
53
54 #ifdef H5_HAVE_PARALLEL
55
56 /* Declare a free list to manage the H5AC_aux_t struct */
57 H5FL_DEFINE_STATIC(H5AC_aux_t);
58
59 #endif /* H5_HAVE_PARALLEL */
60
61 /****************************************************************************
62 *
63 * structure H5AC_slist_entry_t
64 *
65 * The dirty entry list maintained via the d_slist_ptr field of H5AC_aux_t
66 * and the cleaned entry list maintained via the c_slist_ptr field of
67 * H5AC_aux_t are just lists of the file offsets of the dirty/cleaned
68 * entries. Unfortunately, the slist code makes us define a dynamically
69 * allocated structure to store these offsets in. This structure serves
70 * that purpose. Its fields are as follows:
71 *
72 * magic: Unsigned 32 bit integer always set to
73 * H5AC__H5AC_SLIST_ENTRY_T_MAGIC. This field is used to
74 * validate pointers to instances of H5AC_slist_entry_t.
75 *
76 * addr: file offset of a metadata entry. Entries are added to this
77 * list (if they aren't there already) when they are marked
78 * dirty in an unprotect, inserted, or moved. They are
79 * removed when they appear in a clean entries broadcast.
80 *
81 ****************************************************************************/
82
83 #ifdef H5_HAVE_PARALLEL
84
85 #define H5AC__H5AC_SLIST_ENTRY_T_MAGIC 0x00D0A02
86
87 typedef struct H5AC_slist_entry_t
88 {
89 uint32_t magic;
90
91 haddr_t addr;
92 } H5AC_slist_entry_t;
93
94 /* Declare a free list to manage the H5AC_slist_entry_t struct */
95 H5FL_DEFINE_STATIC(H5AC_slist_entry_t);
96
97 #endif /* H5_HAVE_PARALLEL */
98
99
100 /*
101 * Private file-scope variables.
102 */
103
104 /* Default dataset transfer property list for metadata I/O calls */
105 /* (Collective set, "block before metadata write" set and "library internal" set) */
106 /* (Global variable definition, declaration is in H5ACprivate.h also) */
107 hid_t H5AC_dxpl_id=(-1);
108
109 /* Private dataset transfer property list for metadata I/O calls */
110 /* (Collective set and "library internal" set) */
111 /* (Static variable definition) */
112 static hid_t H5AC_noblock_dxpl_id=(-1);
113
114 /* Dataset transfer property list for independent metadata I/O calls */
115 /* (just "library internal" set - i.e. independent transfer mode) */
116 /* (Global variable definition, declaration is in H5ACprivate.h also) */
117 hid_t H5AC_ind_dxpl_id=(-1);
118
119
120 /*
121 * Private file-scope function declarations:
122 */
123
124 static herr_t H5AC_check_if_write_permitted(const H5F_t *f,
125 hid_t dxpl_id,
126 hbool_t * write_permitted_ptr);
127
128 static herr_t H5AC_ext_config_2_int_config(H5AC_cache_config_t * ext_conf_ptr,
129 H5C_auto_size_ctl_t * int_conf_ptr);
130
131 #ifdef H5_HAVE_PARALLEL
132 static herr_t H5AC_broadcast_candidate_list(H5AC_t * cache_ptr,
133 int * num_entries_ptr,
134 haddr_t ** haddr_buf_ptr_ptr);
135
136 static herr_t H5AC_broadcast_clean_list(H5AC_t * cache_ptr);
137
138 static herr_t H5AC_construct_candidate_list(H5AC_t * cache_ptr,
139 H5AC_aux_t * aux_ptr,
140 int sync_point_op);
141
142 static herr_t H5AC_copy_candidate_list_to_buffer(H5AC_t * cache_ptr,
143 int * num_entries_ptr,
144 haddr_t ** haddr_buf_ptr_ptr,
145 size_t * MPI_Offset_buf_size_ptr,
146 MPI_Offset ** MPI_Offset_buf_ptr_ptr);
147
148 static herr_t H5AC_flush_entries(H5F_t *f);
149
150 static herr_t H5AC_log_deleted_entry(H5AC_t * cache_ptr,
151 H5AC_info_t * entry_ptr,
152 haddr_t addr,
153 unsigned int flags);
154
155 static herr_t H5AC_log_dirtied_entry(const H5AC_info_t * entry_ptr,
156 haddr_t addr);
157
158 static herr_t H5AC_log_flushed_entry(H5C_t * cache_ptr,
159 haddr_t addr,
160 hbool_t was_dirty,
161 unsigned flags,
162 int type_id);
163
164 static herr_t H5AC_log_moved_entry(const H5F_t * f,
165 haddr_t old_addr,
166 haddr_t new_addr);
167
168 static herr_t H5AC_log_inserted_entry(H5F_t * f,
169 H5AC_t * cache_ptr,
170 H5AC_info_t * entry_ptr);
171
172 static herr_t H5AC_propagate_and_apply_candidate_list(H5F_t * f,
173 hid_t dxpl_id,
174 H5AC_t * cache_ptr);
175
176 static herr_t H5AC_propagate_flushed_and_still_clean_entries_list(H5F_t * f,
177 hid_t dxpl_id,
178 H5AC_t * cache_ptr);
179
180 static herr_t H5AC_receive_candidate_list(H5AC_t * cache_ptr,
181 int * num_entries_ptr,
182 haddr_t ** haddr_buf_ptr_ptr);
183
184 static herr_t H5AC_receive_and_apply_clean_list(H5F_t * f,
185 hid_t primary_dxpl_id,
186 hid_t secondary_dxpl_id,
187 H5AC_t * cache_ptr);
188
189 static herr_t H5AC_tidy_cache_0_lists(H5AC_t * cache_ptr,
190 int num_candidates,
191 haddr_t * candidates_list_ptr);
192
193 herr_t H5AC_rsp__dist_md_write__flush(H5F_t *f,
194 hid_t dxpl_id,
195 H5AC_t * cache_ptr);
196
197 herr_t H5AC_rsp__dist_md_write__flush_to_min_clean(H5F_t *f,
198 hid_t dxpl_id,
199 H5AC_t * cache_ptr);
200
201 herr_t H5AC_rsp__p0_only__flush(H5F_t *f,
202 hid_t dxpl_id,
203 H5AC_t * cache_ptr);
204
205 herr_t H5AC_rsp__p0_only__flush_to_min_clean(H5F_t *f,
206 hid_t dxpl_id,
207 H5AC_t * cache_ptr);
208
209 static herr_t H5AC_run_sync_point(H5F_t *f,
210 hid_t dxpl_id,
211 int sync_point_op);
212
213 #endif /* H5_HAVE_PARALLEL */
214
215
216 /*-------------------------------------------------------------------------
217 * Function: H5AC_init
218 *
219 * Purpose: Initialize the interface from some other layer.
220 *
221 * Return: Success: non-negative
222 *
223 * Failure: negative
224 *
225 * Programmer: Quincey Koziol
226 * Saturday, January 18, 2003
227 *
228 *-------------------------------------------------------------------------
229 */
230 herr_t
H5AC_init(void)231 H5AC_init(void)
232 {
233 herr_t ret_value=SUCCEED; /* Return value */
234
235 FUNC_ENTER_NOAPI(FAIL)
236 /* FUNC_ENTER() does all the work */
237
238 done:
239 FUNC_LEAVE_NOAPI(ret_value)
240 }
241
242
243 /*-------------------------------------------------------------------------
244 * Function: H5AC_init_interface
245 *
246 * Purpose: Initialize interface-specific information
247 *
248 * Return: Non-negative on success/Negative on failure
249 *
250 * Programmer: Quincey Koziol
251 * Thursday, July 18, 2002
252 *
253 *-------------------------------------------------------------------------
254 */
255 static herr_t
H5AC_init_interface(void)256 H5AC_init_interface(void)
257 {
258 #ifdef H5_HAVE_PARALLEL
259 H5P_genclass_t *xfer_pclass; /* Dataset transfer property list class object */
260 H5P_genplist_t *xfer_plist; /* Dataset transfer property list object */
261 unsigned block_before_meta_write; /* "block before meta write" property value */
262 unsigned coll_meta_write; /* "collective metadata write" property value */
263 unsigned library_internal=1; /* "library internal" property value */
264 H5FD_mpio_xfer_t xfer_mode; /* I/O transfer mode property value */
265 herr_t ret_value=SUCCEED; /* Return value */
266
267 FUNC_ENTER_NOAPI_NOINIT
268
269 /* Sanity check */
270 HDassert(H5P_CLS_DATASET_XFER_g!=(-1));
271
272 /* Get the dataset transfer property list class object */
273 if (NULL == (xfer_pclass = H5I_object(H5P_CLS_DATASET_XFER_g)))
274 HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get property list class")
275
276
277 /* Get an ID for the blocking, collective H5AC dxpl */
278 if ((H5AC_dxpl_id=H5P_create_id(xfer_pclass,FALSE)) < 0)
279 HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to register property list")
280
281 /* Get the property list object */
282 if (NULL == (xfer_plist = H5I_object(H5AC_dxpl_id)))
283 HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object")
284
285 /* Insert 'block before metadata write' property */
286 block_before_meta_write=1;
287 if(H5P_insert(xfer_plist,H5AC_BLOCK_BEFORE_META_WRITE_NAME,H5AC_BLOCK_BEFORE_META_WRITE_SIZE,&block_before_meta_write,NULL,NULL,NULL,NULL,NULL,NULL)<0)
288 HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property")
289
290 /* Insert 'library internal' property */
291 if(H5P_insert(xfer_plist,H5AC_LIBRARY_INTERNAL_NAME,H5AC_LIBRARY_INTERNAL_SIZE,&library_internal,NULL,NULL,NULL,NULL,NULL,NULL)<0)
292 HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property")
293
294 /* Insert 'collective metadata write' property */
295 coll_meta_write = 1;
296 if(H5P_insert(xfer_plist, H5AC_COLLECTIVE_META_WRITE_NAME, H5AC_COLLECTIVE_META_WRITE_SIZE, &coll_meta_write,
297 NULL, NULL, NULL, NULL, NULL, NULL) < 0)
298 HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property")
299
300
301 /* Get an ID for the non-blocking, collective H5AC dxpl */
302 if ((H5AC_noblock_dxpl_id=H5P_create_id(xfer_pclass,FALSE)) < 0)
303 HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to register property list")
304
305 /* Get the property list object */
306 if (NULL == (xfer_plist = H5I_object(H5AC_noblock_dxpl_id)))
307 HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object")
308
309 /* Insert 'block before metadata write' property */
310 block_before_meta_write=0;
311 if(H5P_insert(xfer_plist,H5AC_BLOCK_BEFORE_META_WRITE_NAME,H5AC_BLOCK_BEFORE_META_WRITE_SIZE,&block_before_meta_write,NULL,NULL,NULL,NULL,NULL,NULL)<0)
312 HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property")
313
314 /* Insert 'library internal' property */
315 if(H5P_insert(xfer_plist,H5AC_LIBRARY_INTERNAL_NAME,H5AC_LIBRARY_INTERNAL_SIZE,&library_internal,NULL,NULL,NULL,NULL,NULL,NULL)<0)
316 HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property")
317
318 /* Insert 'collective metadata write' property */
319 coll_meta_write = 1;
320 if(H5P_insert(xfer_plist, H5AC_COLLECTIVE_META_WRITE_NAME, H5AC_COLLECTIVE_META_WRITE_SIZE, &coll_meta_write,
321 NULL, NULL, NULL, NULL, NULL, NULL) < 0)
322 HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property")
323
324
325 /* Get an ID for the non-blocking, independent H5AC dxpl */
326 if ((H5AC_ind_dxpl_id=H5P_create_id(xfer_pclass,FALSE)) < 0)
327 HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to register property list")
328
329 /* Get the property list object */
330 if (NULL == (xfer_plist = H5I_object(H5AC_ind_dxpl_id)))
331 HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object")
332
333 /* Insert 'block before metadata write' property */
334 block_before_meta_write=0;
335 if(H5P_insert(xfer_plist,H5AC_BLOCK_BEFORE_META_WRITE_NAME,H5AC_BLOCK_BEFORE_META_WRITE_SIZE,&block_before_meta_write,NULL,NULL,NULL,NULL,NULL,NULL)<0)
336 HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property")
337
338 /* Insert 'library internal' property */
339 if(H5P_insert(xfer_plist,H5AC_LIBRARY_INTERNAL_NAME,H5AC_LIBRARY_INTERNAL_SIZE,&library_internal,NULL,NULL,NULL,NULL,NULL,NULL)<0)
340 HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property")
341
342 /* Insert 'collective metadata write' property */
343 coll_meta_write = 0;
344 if(H5P_insert(xfer_plist, H5AC_COLLECTIVE_META_WRITE_NAME, H5AC_COLLECTIVE_META_WRITE_SIZE, &coll_meta_write,
345 NULL, NULL, NULL, NULL, NULL, NULL) < 0)
346 HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property")
347
348 done:
349 FUNC_LEAVE_NOAPI(ret_value)
350
351 #else /* H5_HAVE_PARALLEL */
352 FUNC_ENTER_NOAPI_NOINIT_NOERR
353
354 /* Sanity check */
355 HDassert(H5P_LST_DATASET_XFER_g!=(-1));
356
357 H5AC_dxpl_id = H5P_DATASET_XFER_DEFAULT;
358 H5AC_noblock_dxpl_id = H5P_DATASET_XFER_DEFAULT;
359 H5AC_ind_dxpl_id = H5P_DATASET_XFER_DEFAULT;
360
361 FUNC_LEAVE_NOAPI(SUCCEED)
362 #endif /* H5_HAVE_PARALLEL */
363 } /* end H5AC_init_interface() */
364
365
366 /*-------------------------------------------------------------------------
367 * Function: H5AC_term_interface
368 *
369 * Purpose: Terminate this interface.
370 *
371 * Return: Success: Positive if anything was done that might
372 * affect other interfaces; zero otherwise.
373 *
374 * Failure: Negative.
375 *
376 * Programmer: Quincey Koziol
377 * Thursday, July 18, 2002
378 *
379 *-------------------------------------------------------------------------
380 */
381 int
H5AC_term_interface(void)382 H5AC_term_interface(void)
383 {
384 int n = 0;
385
386 FUNC_ENTER_NOAPI_NOINIT_NOERR
387
388 if (H5_interface_initialize_g) {
389 #ifdef H5_HAVE_PARALLEL
390 if(H5AC_dxpl_id > 0 || H5AC_noblock_dxpl_id > 0 || H5AC_ind_dxpl_id > 0) {
391 /* Indicate more work to do */
392 n = 1; /* H5I */
393
394 /* Close H5AC dxpl */
395 if(H5I_dec_ref(H5AC_dxpl_id) < 0 ||
396 H5I_dec_ref(H5AC_noblock_dxpl_id) < 0 ||
397 H5I_dec_ref(H5AC_ind_dxpl_id) < 0)
398 H5E_clear_stack(NULL); /*ignore error*/
399 else {
400 /* Reset static IDs */
401 H5AC_dxpl_id = (-1);
402 H5AC_noblock_dxpl_id = (-1);
403 H5AC_ind_dxpl_id = (-1);
404
405 /* Reset interface initialization flag */
406 H5_interface_initialize_g = 0;
407 } /* end else */
408 } /* end if */
409 else
410 #else /* H5_HAVE_PARALLEL */
411 /* Reset static IDs */
412 H5AC_dxpl_id=(-1);
413 H5AC_noblock_dxpl_id=(-1);
414 H5AC_ind_dxpl_id=(-1);
415 #endif /* H5_HAVE_PARALLEL */
416 /* Reset interface initialization flag */
417 H5_interface_initialize_g = 0;
418 } /* end if */
419
420 FUNC_LEAVE_NOAPI(n)
421 } /* end H5AC_term_interface() */
422
423 static const char * H5AC_entry_type_names[H5AC_NTYPES] =
424 {
425 "B-tree nodes",
426 "symbol table nodes",
427 "local heap prefixes",
428 "local heap data blocks",
429 "global heaps",
430 "object headers",
431 "object header chunks",
432 "v2 B-tree headers",
433 "v2 B-tree internal nodes",
434 "v2 B-tree leaf nodes",
435 "fractal heap headers",
436 "fractal heap direct blocks",
437 "fractal heap indirect blocks",
438 "free space headers",
439 "free space sections",
440 "shared OH message master table",
441 "shared OH message index",
442 "superblock",
443 "test entry" /* for testing only -- not used for actual files */
444 };
445
446
447 /*-------------------------------------------------------------------------
448 * Function: H5AC_create
449 *
450 * Purpose: Initialize the cache just after a file is opened. The
451 * SIZE_HINT is the number of cache slots desired. If you
452 * pass an invalid value then H5AC_NSLOTS is used. You can
453 * turn off caching by using 1 for the SIZE_HINT value.
454 *
455 * Return: Success: Number of slots actually used.
456 *
457 * Failure: Negative
458 *
459 * Programmer: Robb Matzke
460 * matzke@llnl.gov
461 * Jul 9 1997
462 *
463 *-------------------------------------------------------------------------
464 */
465 herr_t
H5AC_create(const H5F_t * f,H5AC_cache_config_t * config_ptr)466 H5AC_create(const H5F_t *f,
467 H5AC_cache_config_t *config_ptr)
468 {
469 #ifdef H5_HAVE_PARALLEL
470 char prefix[H5C__PREFIX_LEN] = "";
471 H5AC_aux_t * aux_ptr = NULL;
472 #endif /* H5_HAVE_PARALLEL */
473 herr_t ret_value = SUCCEED; /* Return value */
474
475 FUNC_ENTER_NOAPI(FAIL)
476
477 HDassert(f);
478 HDassert(NULL == f->shared->cache);
479 HDassert(config_ptr != NULL) ;
480 HDcompile_assert(NELMTS(H5AC_entry_type_names) == H5AC_NTYPES);
481 HDcompile_assert(H5C__MAX_NUM_TYPE_IDS == H5AC_NTYPES);
482
483 if(H5AC_validate_config(config_ptr) < 0)
484 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Bad cache configuration")
485
486 #ifdef H5_HAVE_PARALLEL
487 if(IS_H5FD_MPI(f)) {
488 MPI_Comm mpi_comm;
489 int mpi_rank;
490 int mpi_size;
491
492 if(MPI_COMM_NULL == (mpi_comm = H5F_mpi_get_comm(f)))
493 HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get MPI communicator")
494
495 if((mpi_rank = H5F_mpi_get_rank(f)) < 0)
496 HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get mpi rank")
497
498 if((mpi_size = H5F_mpi_get_size(f)) < 0)
499 HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get mpi size")
500
501 if(NULL == (aux_ptr = H5FL_CALLOC(H5AC_aux_t)))
502 HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "Can't allocate H5AC auxilary structure.")
503
504 aux_ptr->magic = H5AC__H5AC_AUX_T_MAGIC;
505 aux_ptr->mpi_comm = mpi_comm;
506 aux_ptr->mpi_rank = mpi_rank;
507 aux_ptr->mpi_size = mpi_size;
508 aux_ptr->write_permitted = FALSE;
509 aux_ptr->dirty_bytes_threshold = H5AC__DEFAULT_DIRTY_BYTES_THRESHOLD;
510 aux_ptr->dirty_bytes = 0;
511 aux_ptr->metadata_write_strategy = H5AC__DEFAULT_METADATA_WRITE_STRATEGY;
512 #if H5AC_DEBUG_DIRTY_BYTES_CREATION
513 aux_ptr->dirty_bytes_propagations = 0;
514 aux_ptr->unprotect_dirty_bytes = 0;
515 aux_ptr->unprotect_dirty_bytes_updates = 0;
516 aux_ptr->insert_dirty_bytes = 0;
517 aux_ptr->insert_dirty_bytes_updates = 0;
518 aux_ptr->move_dirty_bytes = 0;
519 aux_ptr->move_dirty_bytes_updates = 0;
520 #endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
521 aux_ptr->d_slist_ptr = NULL;
522 aux_ptr->d_slist_len = 0;
523 aux_ptr->c_slist_ptr = NULL;
524 aux_ptr->c_slist_len = 0;
525 aux_ptr->candidate_slist_ptr = NULL;
526 aux_ptr->candidate_slist_len = 0;
527 aux_ptr->write_done = NULL;
528 aux_ptr->sync_point_done = NULL;
529
530 sprintf(prefix, "%d:", mpi_rank);
531
532 if(mpi_rank == 0) {
533 if(NULL == (aux_ptr->d_slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL)))
534 HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create dirtied entry list.")
535
536 if(NULL == (aux_ptr->c_slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL)))
537 HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create cleaned entry list.")
538 } /* end if */
539
540 /* construct the candidate slist for all processes.
541 * when the distributed strategy is selected as all processes
542 * will use it in the case of a flush.
543 */
544 if(NULL == (aux_ptr->candidate_slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL)))
545 HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create candidate entry list.")
546
547 if(aux_ptr != NULL) {
548 if(aux_ptr->mpi_rank == 0) {
549 f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE,
550 H5AC__DEFAULT_MIN_CLEAN_SIZE,
551 (H5AC_NTYPES - 1),
552 (const char **)H5AC_entry_type_names,
553 H5AC_check_if_write_permitted,
554 TRUE,
555 H5AC_log_flushed_entry,
556 (void *)aux_ptr);
557 } else {
558 f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE,
559 H5AC__DEFAULT_MIN_CLEAN_SIZE,
560 (H5AC_NTYPES - 1),
561 (const char **)H5AC_entry_type_names,
562 H5AC_check_if_write_permitted,
563 TRUE,
564 NULL,
565 (void *)aux_ptr);
566 }
567 } else {
568 f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE,
569 H5AC__DEFAULT_MIN_CLEAN_SIZE,
570 (H5AC_NTYPES - 1),
571 (const char **)H5AC_entry_type_names,
572 H5AC_check_if_write_permitted,
573 TRUE,
574 NULL,
575 NULL);
576 }
577 } else {
578 #endif /* H5_HAVE_PARALLEL */
579 /* The default max cache size and min clean size will frequently be
580 * overwritten shortly by the subsequent set resize config call.
581 * -- JRM
582 */
583 f->shared->cache = H5C_create(H5AC__DEFAULT_MAX_CACHE_SIZE,
584 H5AC__DEFAULT_MIN_CLEAN_SIZE,
585 (H5AC_NTYPES - 1),
586 (const char **)H5AC_entry_type_names,
587 H5AC_check_if_write_permitted,
588 TRUE,
589 NULL,
590 NULL);
591 #ifdef H5_HAVE_PARALLEL
592 }
593 #endif /* H5_HAVE_PARALLEL */
594
595 if(NULL == f->shared->cache)
596 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
597
598 #ifdef H5_HAVE_PARALLEL
599 if(aux_ptr != NULL) {
600 if(H5C_set_prefix(f->shared->cache, prefix) < 0)
601 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "H5C_set_prefix() failed")
602 } /* end if */
603 #endif /* H5_HAVE_PARALLEL */
604
605 if(H5AC_set_cache_auto_resize_config(f->shared->cache, config_ptr) < 0)
606 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "auto resize configuration failed")
607
608 done:
609 #ifdef H5_HAVE_PARALLEL
610 /* if there is a failure, try to tidy up the auxilary structure */
611 if(ret_value < 0) {
612 if(aux_ptr != NULL) {
613 if(aux_ptr->d_slist_ptr != NULL)
614 H5SL_close(aux_ptr->d_slist_ptr);
615
616 if(aux_ptr->c_slist_ptr != NULL)
617 H5SL_close(aux_ptr->c_slist_ptr);
618
619 if(aux_ptr->candidate_slist_ptr != NULL)
620 H5SL_close(aux_ptr->candidate_slist_ptr);
621
622 aux_ptr->magic = 0;
623 aux_ptr = H5FL_FREE(H5AC_aux_t, aux_ptr);
624 } /* end if */
625 } /* end if */
626 #endif /* H5_HAVE_PARALLEL */
627
628 FUNC_LEAVE_NOAPI(ret_value)
629 } /* H5AC_create() */
630
631
632 /*-------------------------------------------------------------------------
633 * Function: H5AC_dest
634 *
635 * Purpose: Flushes all data to disk and destroys the cache.
636 * This function fails if any object are protected since the
637 * resulting file might not be consistent.
638 *
639 * Return: Non-negative on success/Negative on failure
640 *
641 * Programmer: Robb Matzke
642 * matzke@llnl.gov
643 * Jul 9 1997
644 *
645 *-------------------------------------------------------------------------
646 */
647 herr_t
H5AC_dest(H5F_t * f,hid_t dxpl_id)648 H5AC_dest(H5F_t *f, hid_t dxpl_id)
649 {
650 #ifdef H5_HAVE_PARALLEL
651 H5AC_aux_t * aux_ptr = NULL;
652 #endif /* H5_HAVE_PARALLEL */
653 herr_t ret_value = SUCCEED; /* Return value */
654
655 FUNC_ENTER_NOAPI(FAIL)
656
657 /* Sanity check */
658 HDassert(f);
659 HDassert(f->shared->cache);
660
661 #if H5AC_DUMP_STATS_ON_CLOSE
662 /* Dump debugging info */
663 H5AC_stats(f);
664 #endif /* H5AC_DUMP_STATS_ON_CLOSE */
665
666 #if H5AC__TRACE_FILE_ENABLED
667 if(H5AC_close_trace_file(f->shared->cache) < 0)
668 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_close_trace_file() failed.")
669 #endif /* H5AC__TRACE_FILE_ENABLED */
670
671 #ifdef H5_HAVE_PARALLEL
672 aux_ptr = (struct H5AC_aux_t *)(f->shared->cache->aux_ptr);
673 if(aux_ptr)
674 /* Sanity check */
675 HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
676
677 /* Attempt to flush all entries from rank 0 & Bcast clean list to other ranks */
678 if(H5AC_flush_entries(f) < 0)
679 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush.")
680 #endif /* H5_HAVE_PARALLEL */
681
682 /* Destroy the cache */
683 if(H5C_dest(f, dxpl_id, H5AC_noblock_dxpl_id) < 0)
684 HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "can't destroy cache")
685 f->shared->cache = NULL;
686
687 #ifdef H5_HAVE_PARALLEL
688 if(aux_ptr != NULL) {
689 if(aux_ptr->d_slist_ptr != NULL)
690 H5SL_close(aux_ptr->d_slist_ptr);
691 if(aux_ptr->c_slist_ptr != NULL)
692 H5SL_close(aux_ptr->c_slist_ptr);
693 if(aux_ptr->candidate_slist_ptr != NULL)
694 H5SL_close(aux_ptr->candidate_slist_ptr);
695 aux_ptr->magic = 0;
696 H5FL_FREE(H5AC_aux_t, aux_ptr);
697 aux_ptr = NULL;
698 } /* end if */
699 #endif /* H5_HAVE_PARALLEL */
700
701 done:
702 FUNC_LEAVE_NOAPI(ret_value)
703 } /* H5AC_dest() */
704
705
706 /*-------------------------------------------------------------------------
707 * Function: H5AC_expunge_entry
708 *
709 * Purpose: Expunge the target entry from the cache without writing it
710 * to disk even if it is dirty. The entry must not be either
711 * pinned or protected.
712 *
713 * Return: Non-negative on success/Negative on failure
714 *
715 * Programmer: John Mainzer
716 * 6/30/06
717 *
718 *-------------------------------------------------------------------------
719 */
720 herr_t
H5AC_expunge_entry(H5F_t * f,hid_t dxpl_id,const H5AC_class_t * type,haddr_t addr,unsigned flags)721 H5AC_expunge_entry(H5F_t *f,
722 hid_t dxpl_id,
723 const H5AC_class_t *type,
724 haddr_t addr,
725 unsigned flags)
726 {
727 herr_t result;
728 #if H5AC__TRACE_FILE_ENABLED
729 char trace[128] = "";
730 FILE * trace_file_ptr = NULL;
731 #endif /* H5AC__TRACE_FILE_ENABLED */
732 herr_t ret_value = SUCCEED; /* Return value */
733
734 FUNC_ENTER_NOAPI(FAIL)
735
736 HDassert(f);
737 HDassert(f->shared);
738 HDassert(f->shared->cache);
739 HDassert(type);
740 HDassert(type->clear);
741 HDassert(type->dest);
742 HDassert(H5F_addr_defined(addr));
743
744 #if H5AC__TRACE_FILE_ENABLED
745 {
746 H5AC_t * cache_ptr = f->shared->cache;
747
748 /* For the expunge entry call, only the addr, and type id are really
749 * necessary in the trace file. Write the return value to catch occult
750 * errors.
751 */
752 if ( ( cache_ptr != NULL ) &&
753 ( H5C_get_trace_file_ptr(cache_ptr, &trace_file_ptr) >= 0 ) &&
754 ( trace_file_ptr != NULL ) ) {
755
756 sprintf(trace, "H5AC_expunge_entry 0x%lx %d",
757 (unsigned long)addr,
758 (int)(type->id));
759 }
760 }
761 #endif /* H5AC__TRACE_FILE_ENABLED */
762
763 result = H5C_expunge_entry(f,
764 dxpl_id,
765 H5AC_noblock_dxpl_id,
766 type,
767 addr,
768 flags);
769
770 if ( result < 0 ) {
771
772 HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, \
773 "H5C_expunge_entry() failed.")
774 }
775
776 done:
777
778 #if H5AC__TRACE_FILE_ENABLED
779 if ( trace_file_ptr != NULL ) {
780
781 HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
782 }
783 #endif /* H5AC__TRACE_FILE_ENABLED */
784
785 FUNC_LEAVE_NOAPI(ret_value)
786
787 } /* H5AC_expunge_entry() */
788
789
790 /*-------------------------------------------------------------------------
791 * Function: H5AC_flush
792 *
793 * Purpose: Flush (and possibly destroy) the metadata cache associated
794 * with the specified file.
795 *
796 * If the cache contains protected entries, the function will
797 * fail, as protected entries cannot be flushed. However
798 * all unprotected entries should be flushed before the
799 * function returns failure.
800 *
801 * Return: Non-negative on success/Negative on failure if there was a
802 * request to flush all items and something was protected.
803 *
804 * Programmer: Robb Matzke
805 * matzke@llnl.gov
806 * Jul 9 1997
807 *
808 *-------------------------------------------------------------------------
809 */
810 herr_t
H5AC_flush(H5F_t * f,hid_t dxpl_id)811 H5AC_flush(H5F_t *f, hid_t dxpl_id)
812 {
813 #if H5AC__TRACE_FILE_ENABLED
814 char trace[128] = "";
815 FILE * trace_file_ptr = NULL;
816 #endif /* H5AC__TRACE_FILE_ENABLED */
817 herr_t ret_value = SUCCEED; /* Return value */
818
819 FUNC_ENTER_NOAPI(FAIL)
820
821 HDassert(f);
822 HDassert(f->shared);
823 HDassert(f->shared->cache);
824
825 #if H5AC__TRACE_FILE_ENABLED
826 /* For the flush, only the flags are really necessary in the trace file.
827 * Write the result to catch occult errors.
828 */
829 if((f != NULL) &&
830 (f->shared != NULL) &&
831 (f->shared->cache != NULL) &&
832 (H5C_get_trace_file_ptr(f->shared->cache, &trace_file_ptr) >= 0) &&
833 (trace_file_ptr != NULL))
834 sprintf(trace, "H5AC_flush");
835 #endif /* H5AC__TRACE_FILE_ENABLED */
836
837 #ifdef H5_HAVE_PARALLEL
838 /* Attempt to flush all entries from rank 0 & Bcast clean list to other ranks */
839 if(H5AC_flush_entries(f) < 0)
840 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush.")
841 #endif /* H5_HAVE_PARALLEL */
842
843 /* Flush the cache */
844 if(H5C_flush_cache(f, dxpl_id, H5AC_noblock_dxpl_id, H5AC__NO_FLAGS_SET) < 0)
845 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush cache.")
846
847 done:
848 #if H5AC__TRACE_FILE_ENABLED
849 if(trace_file_ptr != NULL)
850 HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
851 #endif /* H5AC__TRACE_FILE_ENABLED */
852
853 FUNC_LEAVE_NOAPI(ret_value)
854 } /* H5AC_flush() */
855
856
857 /*-------------------------------------------------------------------------
858 * Function: H5AC_get_entry_status
859 *
860 * Purpose: Given a file address, determine whether the metadata
861 * cache contains an entry at that location. If it does,
862 * also determine whether the entry is dirty, protected,
863 * pinned, etc. and return that information to the caller
864 * in *status_ptr.
865 *
866 * If the specified entry doesn't exist, set *status_ptr
867 * to zero.
868 *
869 * On error, the value of *status_ptr is undefined.
870 *
871 * Return: Non-negative on success/Negative on failure
872 *
873 * Programmer: John Mainzer
874 * 4/27/06
875 *
876 *-------------------------------------------------------------------------
877 */
878 herr_t
H5AC_get_entry_status(const H5F_t * f,haddr_t addr,unsigned * status_ptr)879 H5AC_get_entry_status(const H5F_t *f,
880 haddr_t addr,
881 unsigned * status_ptr)
882 {
883 hbool_t in_cache;
884 hbool_t is_dirty;
885 hbool_t is_protected;
886 hbool_t is_pinned;
887 size_t entry_size;
888 unsigned status = 0;
889 herr_t ret_value = SUCCEED; /* Return value */
890
891 FUNC_ENTER_NOAPI(FAIL)
892
893 if((f == NULL) || (!H5F_addr_defined(addr)) || (status_ptr == NULL))
894 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad param(s) on entry.")
895
896 if(H5C_get_entry_status(f, addr, &entry_size, &in_cache, &is_dirty,
897 &is_protected, &is_pinned) < 0)
898 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_entry_status() failed.")
899
900 if(in_cache) {
901 status |= H5AC_ES__IN_CACHE;
902 if(is_dirty)
903 status |= H5AC_ES__IS_DIRTY;
904 if(is_protected)
905 status |= H5AC_ES__IS_PROTECTED;
906 if(is_pinned)
907 status |= H5AC_ES__IS_PINNED;
908 } /* end if */
909
910 *status_ptr = status;
911
912 done:
913 FUNC_LEAVE_NOAPI(ret_value)
914 } /* H5AC_get_entry_status() */
915
916
917 /*-------------------------------------------------------------------------
918 * Function: H5AC_insert_entry
919 *
920 * Purpose: Adds the specified thing to the cache. The thing need not
921 * exist on disk yet, but it must have an address and disk
922 * space reserved.
923 *
924 * Return: Non-negative on success/Negative on failure
925 *
926 * Programmer: Robb Matzke
927 * matzke@llnl.gov
928 * Jul 9 1997
929 *
930 *-------------------------------------------------------------------------
931 */
932 herr_t
H5AC_insert_entry(H5F_t * f,hid_t dxpl_id,const H5AC_class_t * type,haddr_t addr,void * thing,unsigned int flags)933 H5AC_insert_entry(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr, void *thing, unsigned int flags)
934 {
935 #if H5AC__TRACE_FILE_ENABLED
936 char trace[128] = "";
937 size_t trace_entry_size = 0;
938 FILE * trace_file_ptr = NULL;
939 #endif /* H5AC__TRACE_FILE_ENABLED */
940 herr_t ret_value = SUCCEED; /* Return value */
941
942 FUNC_ENTER_NOAPI(FAIL)
943
944 HDassert(f);
945 HDassert(f->shared);
946 HDassert(f->shared->cache);
947 HDassert(type);
948 HDassert(type->flush);
949 HDassert(type->size);
950 HDassert(H5F_addr_defined(addr));
951 HDassert(thing);
952
953 /* Check for invalid access request */
954 if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR))
955 HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "no write intent on file")
956
957 #if H5AC__TRACE_FILE_ENABLED
958 /* For the insert, only the addr, size, type id and flags are really
959 * necessary in the trace file. Write the result to catch occult
960 * errors.
961 *
962 * Note that some data is not available right now -- put what we can
963 * in the trace buffer now, and fill in the rest at the end.
964 */
965 if ( ( f != NULL ) &&
966 ( f->shared != NULL ) &&
967 ( f->shared->cache != NULL ) &&
968 ( H5C_get_trace_file_ptr(f->shared->cache, &trace_file_ptr) >= 0) &&
969 ( trace_file_ptr != NULL ) ) {
970
971 sprintf(trace, "H5AC_insert_entry 0x%lx %d 0x%x",
972 (unsigned long)addr,
973 type->id,
974 flags);
975 }
976 #endif /* H5AC__TRACE_FILE_ENABLED */
977
978 /* Insert entry into metadata cache */
979 if(H5C_insert_entry(f, dxpl_id, H5AC_noblock_dxpl_id, type, addr, thing, flags) < 0)
980 HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5C_insert_entry() failed")
981
982 #if H5AC__TRACE_FILE_ENABLED
983 if(trace_file_ptr != NULL) {
984 /* make note of the entry size */
985 trace_entry_size = ((H5C_cache_entry_t *)thing)->size;
986 }
987 #endif /* H5AC__TRACE_FILE_ENABLED */
988
989 #ifdef H5_HAVE_PARALLEL
990 {
991 H5AC_aux_t *aux_ptr;
992
993 if(NULL != (aux_ptr = (H5AC_aux_t *)f->shared->cache->aux_ptr)) {
994 /* Log the new entry */
995 if(H5AC_log_inserted_entry(f, f->shared->cache, (H5AC_info_t *)thing) < 0)
996 HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5AC_log_inserted_entry() failed")
997
998 /* Check if we should try to flush */
999 if(aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold)
1000 if(H5AC_run_sync_point(f, H5AC_noblock_dxpl_id, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0)
1001 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point.")
1002 } /* end if */
1003 }
1004 #endif /* H5_HAVE_PARALLEL */
1005
1006 done:
1007 #if H5AC__TRACE_FILE_ENABLED
1008 if(trace_file_ptr != NULL) {
1009 HDfprintf(trace_file_ptr, "%s %d %d\n", trace,
1010 (int)trace_entry_size,
1011 (int)ret_value);
1012 }
1013 #endif /* H5AC__TRACE_FILE_ENABLED */
1014
1015 FUNC_LEAVE_NOAPI(ret_value)
1016 } /* H5AC_insert_entry() */
1017
1018
1019 /*-------------------------------------------------------------------------
1020 * Function: H5AC_mark_entry_dirty
1021 *
1022 * Purpose: Mark a pinned or protected entry as dirty. The target
1023 * entry MUST be either pinned, protected, or both.
1024 *
1025 * Return: Non-negative on success/Negative on failure
1026 *
1027 * Programmer: John Mainzer
1028 * 5/16/06
1029 *
1030 *-------------------------------------------------------------------------
1031 */
1032 herr_t
H5AC_mark_entry_dirty(void * thing)1033 H5AC_mark_entry_dirty(void *thing)
1034 {
1035 #if H5AC__TRACE_FILE_ENABLED
1036 char trace[128] = "";
1037 FILE * trace_file_ptr = NULL;
1038 #endif /* H5AC__TRACE_FILE_ENABLED */
1039 herr_t ret_value = SUCCEED; /* Return value */
1040
1041 FUNC_ENTER_NOAPI(FAIL)
1042
1043 /* Sanity check */
1044 HDassert(thing);
1045
1046 #if H5AC__TRACE_FILE_ENABLED
1047 /* For the mark pinned or protected entry dirty call, only the addr
1048 * is really necessary in the trace file. Write the result to catch
1049 * occult errors.
1050 */
1051 if((H5C_get_trace_file_ptr_from_entry(thing, &trace_file_ptr) >= 0) &&
1052 (NULL != trace_file_ptr))
1053 sprintf(trace, "%s 0x%lx", FUNC,
1054 (unsigned long)(((H5C_cache_entry_t *)thing)->addr));
1055 #endif /* H5AC__TRACE_FILE_ENABLED */
1056
1057 #ifdef H5_HAVE_PARALLEL
1058 {
1059 H5AC_info_t *entry_ptr = (H5AC_info_t *)thing;
1060 H5C_t *cache_ptr = entry_ptr->cache_ptr;
1061
1062 HDassert(cache_ptr);
1063 HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
1064
1065 if((!entry_ptr->is_dirty) && (!entry_ptr->is_protected) &&
1066 (entry_ptr->is_pinned) && (NULL != cache_ptr->aux_ptr)) {
1067 if(H5AC_log_dirtied_entry(entry_ptr, entry_ptr->addr) < 0)
1068 HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't log dirtied entry")
1069 } /* end if */
1070 }
1071 #endif /* H5_HAVE_PARALLEL */
1072
1073 if(H5C_mark_entry_dirty(thing) < 0)
1074 HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't mark pinned or protected entry dirty")
1075
1076 done:
1077 #if H5AC__TRACE_FILE_ENABLED
1078 if(trace_file_ptr)
1079 HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
1080 #endif /* H5AC__TRACE_FILE_ENABLED */
1081
1082 FUNC_LEAVE_NOAPI(ret_value)
1083 } /* H5AC_mark_entry_dirty() */
1084
1085
1086 /*-------------------------------------------------------------------------
1087 * Function: H5AC_move_entry
1088 *
1089 * Purpose: Use this function to notify the cache that an object's
1090 * file address changed.
1091 *
1092 * Return: Non-negative on success/Negative on failure
1093 *
1094 * Programmer: Robb Matzke
1095 * matzke@llnl.gov
1096 * Jul 9 1997
1097 *
1098 *-------------------------------------------------------------------------
1099 */
1100 herr_t
H5AC_move_entry(H5F_t * f,const H5AC_class_t * type,haddr_t old_addr,haddr_t new_addr)1101 H5AC_move_entry(H5F_t *f, const H5AC_class_t *type, haddr_t old_addr, haddr_t new_addr)
1102 {
1103 #if H5AC__TRACE_FILE_ENABLED
1104 char trace[128] = "";
1105 FILE * trace_file_ptr = NULL;
1106 #endif /* H5AC__TRACE_FILE_ENABLED */
1107 #ifdef H5_HAVE_PARALLEL
1108 H5AC_aux_t * aux_ptr;
1109 #endif /* H5_HAVE_PARALLEL */
1110 herr_t ret_value=SUCCEED; /* Return value */
1111
1112 FUNC_ENTER_NOAPI(FAIL)
1113
1114 HDassert(f);
1115 HDassert(f->shared->cache);
1116 HDassert(type);
1117 HDassert(H5F_addr_defined(old_addr));
1118 HDassert(H5F_addr_defined(new_addr));
1119 HDassert(H5F_addr_ne(old_addr, new_addr));
1120
1121 #if H5AC__TRACE_FILE_ENABLED
1122 /* For the move call, only the old addr and new addr are really
1123 * necessary in the trace file. Include the type id so we don't have to
1124 * look it up. Also write the result to catch occult errors.
1125 */
1126 if ( ( f != NULL ) &&
1127 ( f->shared != NULL ) &&
1128 ( f->shared->cache != NULL ) &&
1129 ( H5C_get_trace_file_ptr(f->shared->cache, &trace_file_ptr) >= 0) &&
1130 ( trace_file_ptr != NULL ) ) {
1131
1132 sprintf(trace, "H5AC_move_entry 0x%lx 0x%lx %d",
1133 (unsigned long)old_addr,
1134 (unsigned long)new_addr,
1135 (int)(type->id));
1136 }
1137 #endif /* H5AC__TRACE_FILE_ENABLED */
1138
1139 #ifdef H5_HAVE_PARALLEL
1140 /* Log moving the entry */
1141 if(NULL != (aux_ptr = (H5AC_aux_t *)f->shared->cache->aux_ptr)) {
1142 if(H5AC_log_moved_entry(f, old_addr, new_addr) < 0)
1143 HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "can't log moved entry")
1144 } /* end if */
1145 #endif /* H5_HAVE_PARALLEL */
1146
1147 if(H5C_move_entry(f->shared->cache, type, old_addr, new_addr) < 0)
1148 HGOTO_ERROR(H5E_CACHE, H5E_CANTMOVE, FAIL, "H5C_move_entry() failed.")
1149
1150 #ifdef H5_HAVE_PARALLEL
1151 /* Check if we should try to flush */
1152 if(NULL != aux_ptr && aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold) {
1153 if(H5AC_run_sync_point(f, H5AC_noblock_dxpl_id, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0)
1154 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point.")
1155 } /* end if */
1156 #endif /* H5_HAVE_PARALLEL */
1157
1158 done:
1159 #if H5AC__TRACE_FILE_ENABLED
1160 if(trace_file_ptr != NULL)
1161 HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
1162 #endif /* H5AC__TRACE_FILE_ENABLED */
1163
1164 FUNC_LEAVE_NOAPI(ret_value)
1165 } /* H5AC_move_entry() */
1166
1167
1168 /*-------------------------------------------------------------------------
1169 * Function: H5AC_pin_protected_entry()
1170 *
1171 * Purpose: Pin a protected cache entry. The entry must be protected
1172 * at the time of call, and must be unpinned.
1173 *
1174 * Return: Non-negative on success/Negative on failure
1175 *
1176 * Programmer: John Mainzer
1177 * 4/27/06
1178 *
1179 *-------------------------------------------------------------------------
1180 */
1181 herr_t
H5AC_pin_protected_entry(void * thing)1182 H5AC_pin_protected_entry(void *thing)
1183 {
1184 #if H5AC__TRACE_FILE_ENABLED
1185 char trace[128] = "";
1186 FILE * trace_file_ptr = NULL;
1187 #endif /* H5AC__TRACE_FILE_ENABLED */
1188 herr_t ret_value = SUCCEED; /* Return value */
1189
1190 FUNC_ENTER_NOAPI(FAIL)
1191
1192 /* Sanity check */
1193 HDassert(thing);
1194
1195 #if H5AC__TRACE_FILE_ENABLED
1196 /* For the pin protected entry call, only the addr is really necessary
1197 * in the trace file. Also write the result to catch occult errors.
1198 */
1199 if((H5C_get_trace_file_ptr_from_entry(thing, &trace_file_ptr) >= 0) &&
1200 (NULL != trace_file_ptr))
1201 sprintf(trace, "%s 0x%lx", FUNC,
1202 (unsigned long)(((H5C_cache_entry_t *)thing)->addr));
1203 #endif /* H5AC__TRACE_FILE_ENABLED */
1204
1205 if(H5C_pin_protected_entry(thing) < 0)
1206 HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "can't pin entry")
1207
1208 done:
1209 #if H5AC__TRACE_FILE_ENABLED
1210 if(trace_file_ptr)
1211 HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
1212 #endif /* H5AC__TRACE_FILE_ENABLED */
1213
1214 FUNC_LEAVE_NOAPI(ret_value)
1215 } /* H5AC_pin_protected_entry() */
1216
1217
1218 /*-------------------------------------------------------------------------
1219 * Function: H5AC_protect
1220 *
1221 * Purpose: If the target entry is not in the cache, load it. If
1222 * necessary, attempt to evict one or more entries to keep
1223 * the cache within its maximum size.
1224 *
1225 * Mark the target entry as protected, and return its address
1226 * to the caller. The caller must call H5AC_unprotect() when
1227 * finished with the entry.
1228 *
1229 * While it is protected, the entry may not be either evicted
1230 * or flushed -- nor may it be accessed by another call to
1231 * H5AC_protect. Any attempt to do so will result in a failure.
1232 *
1233 * Return: Success: Ptr to the object.
1234 * Failure: NULL
1235 *
1236 * Programmer: Robb Matzke
1237 * matzke@llnl.gov
1238 * Sep 2 1997
1239 *
1240 *-------------------------------------------------------------------------
1241 */
1242 void *
H5AC_protect(H5F_t * f,hid_t dxpl_id,const H5AC_class_t * type,haddr_t addr,void * udata,H5AC_protect_t rw)1243 H5AC_protect(H5F_t *f,
1244 hid_t dxpl_id,
1245 const H5AC_class_t *type,
1246 haddr_t addr,
1247 void *udata,
1248 H5AC_protect_t rw)
1249 {
1250 unsigned protect_flags = H5C__NO_FLAGS_SET;
1251 void * thing = (void *)NULL;
1252 #if H5AC__TRACE_FILE_ENABLED
1253 char trace[128] = "";
1254 size_t trace_entry_size = 0;
1255 FILE * trace_file_ptr = NULL;
1256 #endif /* H5AC__TRACE_FILE_ENABLED */
1257 void * ret_value; /* Return value */
1258
1259 FUNC_ENTER_NOAPI(NULL)
1260
1261 /* check args */
1262 HDassert(f);
1263 HDassert(f->shared);
1264 HDassert(f->shared->cache);
1265 HDassert(type);
1266 HDassert(type->flush);
1267 HDassert(type->load);
1268 HDassert(H5F_addr_defined(addr));
1269
1270 /* Check for invalid access request */
1271 if(0 == (H5F_INTENT(f) & H5F_ACC_RDWR) && rw == H5AC_WRITE)
1272 HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "no write intent on file")
1273
1274 #if H5AC__TRACE_FILE_ENABLED
1275 /* For the protect call, only the addr and type id is really necessary
1276 * in the trace file. Include the size of the entry protected as a
1277 * sanity check. Also indicate whether the call was successful to
1278 * catch occult errors.
1279 */
1280 if ( ( f != NULL ) &&
1281 ( f->shared != NULL ) &&
1282 ( f->shared->cache != NULL ) &&
1283 ( H5C_get_trace_file_ptr(f->shared->cache, &trace_file_ptr) >= 0) &&
1284 ( trace_file_ptr != NULL ) ) {
1285
1286 const char * rw_string;
1287
1288 if ( rw == H5AC_WRITE ) {
1289
1290 rw_string = "H5AC_WRITE";
1291
1292 } else if ( rw == H5AC_READ ) {
1293
1294 rw_string = "H5AC_READ";
1295
1296 } else {
1297
1298 rw_string = "???";
1299 }
1300
1301 sprintf(trace, "H5AC_protect 0x%lx %d %s",
1302 (unsigned long)addr,
1303 (int)(type->id),
1304 rw_string);
1305 }
1306 #endif /* H5AC__TRACE_FILE_ENABLED */
1307
1308 if ( rw == H5AC_READ ) {
1309
1310 protect_flags |= H5C__READ_ONLY_FLAG;
1311 }
1312
1313 thing = H5C_protect(f,
1314 dxpl_id,
1315 H5AC_noblock_dxpl_id,
1316 type,
1317 addr,
1318 udata,
1319 protect_flags);
1320
1321 if ( thing == NULL ) {
1322
1323 HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C_protect() failed.")
1324 }
1325
1326 #if H5AC__TRACE_FILE_ENABLED
1327 if ( trace_file_ptr != NULL ) {
1328
1329 /* make note of the entry size */
1330 trace_entry_size = ((H5C_cache_entry_t *)thing)->size;
1331 }
1332 #endif /* H5AC__TRACE_FILE_ENABLED */
1333
1334 /* Set return value */
1335 ret_value = thing;
1336
1337 done:
1338
1339 #if H5AC__TRACE_FILE_ENABLED
1340 if ( trace_file_ptr != NULL ) {
1341
1342 HDfprintf(trace_file_ptr, "%s %d %d\n", trace,
1343 (int)trace_entry_size,
1344 (int)(ret_value != NULL));
1345 }
1346 #endif /* H5AC__TRACE_FILE_ENABLED */
1347
1348 FUNC_LEAVE_NOAPI(ret_value)
1349
1350 } /* H5AC_protect() */
1351
1352
1353 /*-------------------------------------------------------------------------
1354 * Function: H5AC_resize_entry
1355 *
1356 * Purpose: Resize a pinned or protected entry.
1357 *
1358 * Return: Non-negative on success/Negative on failure
1359 *
1360 * Programmer: John Mainzer
1361 * 7/5/06
1362 *
1363 *-------------------------------------------------------------------------
1364 */
1365 herr_t
H5AC_resize_entry(void * thing,size_t new_size)1366 H5AC_resize_entry(void *thing, size_t new_size)
1367 {
1368 #if H5AC__TRACE_FILE_ENABLED
1369 char trace[128] = "";
1370 FILE * trace_file_ptr = NULL;
1371 #endif /* H5AC__TRACE_FILE_ENABLED */
1372 herr_t ret_value = SUCCEED; /* Return value */
1373
1374 FUNC_ENTER_NOAPI(FAIL)
1375
1376 /* Sanity check */
1377 HDassert(thing);
1378
1379 #if H5AC__TRACE_FILE_ENABLED
1380 /* For the resize pinned entry call, only the addr, and new_size are
1381 * really necessary in the trace file. Write the result to catch
1382 * occult errors.
1383 */
1384 if((H5C_get_trace_file_ptr_from_entry(thing, &trace_file_ptr) >= 0) &&
1385 (NULL != trace_file_ptr))
1386 sprintf(trace, "%s 0x%lx %d", FUNC,
1387 (unsigned long)(((H5C_cache_entry_t *)thing)->addr),
1388 (int)new_size);
1389 #endif /* H5AC__TRACE_FILE_ENABLED */
1390
1391 if(H5C_resize_entry(thing, new_size) < 0)
1392 HGOTO_ERROR(H5E_CACHE, H5E_CANTRESIZE, FAIL, "can't resize entry")
1393
1394 #ifdef H5_HAVE_PARALLEL
1395 {
1396 H5AC_info_t * entry_ptr = (H5AC_info_t *)thing;
1397 H5C_t *cache_ptr = entry_ptr->cache_ptr;
1398
1399 HDassert(cache_ptr);
1400 HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
1401
1402 if((!entry_ptr->is_dirty) && (NULL != cache_ptr->aux_ptr)) {
1403 if(H5AC_log_dirtied_entry(entry_ptr, entry_ptr->addr) < 0)
1404 HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "can't log dirtied entry")
1405 } /* end if */
1406 }
1407 #endif /* H5_HAVE_PARALLEL */
1408
1409 done:
1410 #if H5AC__TRACE_FILE_ENABLED
1411 if(trace_file_ptr)
1412 HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
1413 #endif /* H5AC__TRACE_FILE_ENABLED */
1414
1415 FUNC_LEAVE_NOAPI(ret_value)
1416 } /* H5AC_resize_entry() */
1417
1418
1419 /*-------------------------------------------------------------------------
1420 * Function: H5AC_unpin_entry()
1421 *
1422 * Purpose: Unpin a cache entry. The entry must be unprotected at
1423 * the time of call, and must be pinned.
1424 *
1425 * Return: Non-negative on success/Negative on failure
1426 *
1427 * Programmer: John Mainzer
1428 * 4/11/06
1429 *
1430 *-------------------------------------------------------------------------
1431 */
1432 herr_t
H5AC_unpin_entry(void * thing)1433 H5AC_unpin_entry(void *thing)
1434 {
1435 #if H5AC__TRACE_FILE_ENABLED
1436 char trace[128] = "";
1437 FILE * trace_file_ptr = NULL;
1438 #endif /* H5AC__TRACE_FILE_ENABLED */
1439 herr_t ret_value = SUCCEED; /* Return value */
1440
1441 FUNC_ENTER_NOAPI(FAIL)
1442
1443 /* Sanity check */
1444 HDassert(thing);
1445
1446 #if H5AC__TRACE_FILE_ENABLED
1447 /* For the unpin entry call, only the addr is really necessary
1448 * in the trace file. Also write the result to catch occult errors.
1449 */
1450 if((H5C_get_trace_file_ptr_from_entry(thing, &trace_file_ptr) >= 0) &&
1451 (NULL != trace_file_ptr))
1452 sprintf(trace, "%s 0x%lx", FUNC,
1453 (unsigned long)(((H5C_cache_entry_t *)thing)->addr));
1454 #endif /* H5AC__TRACE_FILE_ENABLED */
1455
1456 if(H5C_unpin_entry(thing) < 0)
1457 HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "can't unpin entry")
1458
1459 done:
1460 #if H5AC__TRACE_FILE_ENABLED
1461 if(trace_file_ptr)
1462 HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value);
1463 #endif /* H5AC__TRACE_FILE_ENABLED */
1464
1465 FUNC_LEAVE_NOAPI(ret_value)
1466 } /* H5AC_unpin_entry() */
1467
1468
1469 /*-------------------------------------------------------------------------
1470 * Function: H5AC_unprotect
1471 *
1472 * Purpose: Undo an H5AC_protect() call -- specifically, mark the
1473 * entry as unprotected, remove it from the protected list,
1474 * and give it back to the replacement policy.
1475 *
1476 * The TYPE and ADDR arguments must be the same as those in
1477 * the corresponding call to H5AC_protect() and the THING
1478 * argument must be the value returned by that call to
1479 * H5AC_protect().
1480 *
1481 * If the deleted flag is TRUE, simply remove the target entry
1482 * from the cache, clear it, and free it without writing it to
1483 * disk.
1484 *
1485 * This verion of the function is a complete re-write to
1486 * use the new metadata cache. While there isn't all that
1487 * much difference between the old and new Purpose sections,
1488 * the original version is given below.
1489 *
1490 * Original purpose section:
1491 *
1492 * This function should be called to undo the effect of
1493 * H5AC_protect(). The TYPE and ADDR arguments should be the
1494 * same as the corresponding call to H5AC_protect() and the
1495 * THING argument should be the value returned by H5AC_protect().
1496 * If the DELETED flag is set, then this object has been deleted
1497 * from the file and should not be returned to the cache.
1498 *
1499 * Return: Non-negative on success/Negative on failure
1500 *
1501 * Programmer: Robb Matzke
1502 * matzke@llnl.gov
1503 * Sep 2 1997
1504 *
1505 *-------------------------------------------------------------------------
1506 */
1507 herr_t
H5AC_unprotect(H5F_t * f,hid_t dxpl_id,const H5AC_class_t * type,haddr_t addr,void * thing,unsigned flags)1508 H5AC_unprotect(H5F_t *f, hid_t dxpl_id, const H5AC_class_t *type, haddr_t addr,
1509 void *thing, unsigned flags)
1510 {
1511 hbool_t dirtied;
1512 hbool_t deleted;
1513 #ifdef H5_HAVE_PARALLEL
1514 hbool_t size_changed = FALSE;
1515 H5AC_aux_t * aux_ptr = NULL;
1516 #endif /* H5_HAVE_PARALLEL */
1517 #if H5AC__TRACE_FILE_ENABLED
1518 char trace[128] = "";
1519 FILE * trace_file_ptr = NULL;
1520 #endif /* H5AC__TRACE_FILE_ENABLED */
1521 herr_t ret_value=SUCCEED; /* Return value */
1522
1523 FUNC_ENTER_NOAPI(FAIL)
1524
1525 HDassert(f);
1526 HDassert(f->shared);
1527 HDassert(f->shared->cache);
1528 HDassert(type);
1529 HDassert(type->clear);
1530 HDassert(type->flush);
1531 HDassert(H5F_addr_defined(addr));
1532 HDassert(thing);
1533 HDassert( ((H5AC_info_t *)thing)->addr == addr );
1534 HDassert( ((H5AC_info_t *)thing)->type == type );
1535
1536 #if H5AC__TRACE_FILE_ENABLED
1537 /* For the unprotect call, only the addr, type id, flags, and possible
1538 * new size are really necessary in the trace file. Write the return
1539 * value to catch occult errors.
1540 */
1541 if ( ( f != NULL ) &&
1542 ( f->shared != NULL ) &&
1543 ( f->shared->cache != NULL ) &&
1544 ( H5C_get_trace_file_ptr(f->shared->cache, &trace_file_ptr) >= 0) &&
1545 ( trace_file_ptr != NULL ) ) {
1546
1547 sprintf(trace, "H5AC_unprotect 0x%lx %d",
1548 (unsigned long)addr,
1549 (int)(type->id));
1550 }
1551 #endif /* H5AC__TRACE_FILE_ENABLED */
1552
1553 dirtied = (hbool_t)( ( (flags & H5AC__DIRTIED_FLAG) == H5AC__DIRTIED_FLAG ) ||
1554 ( ((H5AC_info_t *)thing)->dirtied ) );
1555 deleted = (hbool_t)( (flags & H5C__DELETED_FLAG) == H5C__DELETED_FLAG );
1556
1557 /* Check if the size changed out from underneath us, if we're not deleting
1558 * the entry.
1559 */
1560 if(dirtied && !deleted) {
1561 size_t curr_size = 0;
1562
1563 if((type->size)(f, thing, &curr_size) < 0)
1564 HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGETSIZE, FAIL, "Can't get size of thing")
1565
1566 if(((H5AC_info_t *)thing)->size != curr_size)
1567 HGOTO_ERROR(H5E_CACHE, H5E_BADSIZE, FAIL, "size of entry changed")
1568 } /* end if */
1569
1570 #ifdef H5_HAVE_PARALLEL
1571 if((dirtied) && (((H5AC_info_t *)thing)->is_dirty == FALSE) &&
1572 (NULL != (aux_ptr = (H5AC_aux_t *)f->shared->cache->aux_ptr))) {
1573 if(H5AC_log_dirtied_entry((H5AC_info_t *)thing, addr) < 0)
1574 HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "can't log dirtied entry")
1575 } /* end if */
1576
1577 if((deleted) &&
1578 (NULL != (aux_ptr = (H5AC_aux_t *)(f->shared->cache->aux_ptr))) &&
1579 (aux_ptr->mpi_rank == 0)) {
1580 if(H5AC_log_deleted_entry(f->shared->cache, (H5AC_info_t *)thing, addr, flags) < 0)
1581 HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "H5AC_log_deleted_entry() failed.")
1582 } /* end if */
1583 #endif /* H5_HAVE_PARALLEL */
1584
1585 if(H5C_unprotect(f, dxpl_id, H5AC_noblock_dxpl_id, type, addr, thing, flags) < 0)
1586 HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "H5C_unprotect() failed.")
1587
1588 #ifdef H5_HAVE_PARALLEL
1589 /* Check if we should try to flush */
1590 if((aux_ptr != NULL) && (aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold)) {
1591 if(H5AC_run_sync_point(f, H5AC_noblock_dxpl_id, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0)
1592 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point.")
1593 } /* end if */
1594 #endif /* H5_HAVE_PARALLEL */
1595
1596 done:
1597 #if H5AC__TRACE_FILE_ENABLED
1598 if(trace_file_ptr != NULL)
1599 HDfprintf(trace_file_ptr, "%s %x %d\n",
1600 trace, (unsigned)flags, (int)ret_value);
1601 #endif /* H5AC__TRACE_FILE_ENABLED */
1602
1603 FUNC_LEAVE_NOAPI(ret_value)
1604 } /* H5AC_unprotect() */
1605
1606
1607 /*-------------------------------------------------------------------------
1608 * Function: HA5C_set_sync_point_done_callback
1609 *
1610 * Purpose: Set the value of the sync_point_done callback. This
1611 * callback is used by the parallel test code to verify
1612 * that the expected writes and only the expected writes
1613 * take place during a sync point.
1614 *
1615 * Return: Non-negative on success/Negative on failure
1616 *
1617 * Programmer: John Mainzer
1618 * 5/9/10
1619 *
1620 *-------------------------------------------------------------------------
1621 */
1622 #ifdef H5_HAVE_PARALLEL
1623 herr_t
H5AC_set_sync_point_done_callback(H5C_t * cache_ptr,void (* sync_point_done)(int num_writes,haddr_t * written_entries_tbl))1624 H5AC_set_sync_point_done_callback(H5C_t * cache_ptr,
1625 void (* sync_point_done)(int num_writes, haddr_t * written_entries_tbl))
1626 {
1627 H5AC_aux_t * aux_ptr;
1628
1629 FUNC_ENTER_NOAPI_NOINIT
1630
1631 HDassert(cache_ptr && (cache_ptr->magic == H5C__H5C_T_MAGIC));
1632
1633 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
1634
1635 HDassert( aux_ptr != NULL );
1636 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
1637
1638 aux_ptr->sync_point_done = sync_point_done;
1639
1640 FUNC_LEAVE_NOAPI(SUCCEED)
1641 } /* H5AC_set_sync_point_done_callback() */
1642 #endif /* H5_HAVE_PARALLEL */
1643
1644
1645 /*-------------------------------------------------------------------------
1646 * Function: HA5C_set_write_done_callback
1647 *
1648 * Purpose: Set the value of the write_done callback. This callback
1649 * is used to improve performance of the parallel test bed
1650 * for the cache.
1651 *
1652 * Return: Non-negative on success/Negative on failure
1653 *
1654 * Programmer: John Mainzer
1655 * 5/11/06
1656 *
1657 *-------------------------------------------------------------------------
1658 */
1659 #ifdef H5_HAVE_PARALLEL
1660 herr_t
H5AC_set_write_done_callback(H5C_t * cache_ptr,void (* write_done)(void))1661 H5AC_set_write_done_callback(H5C_t * cache_ptr,
1662 void (* write_done)(void))
1663 {
1664 H5AC_aux_t * aux_ptr;
1665
1666 FUNC_ENTER_NOAPI_NOINIT
1667
1668 HDassert(cache_ptr && (cache_ptr->magic == H5C__H5C_T_MAGIC));
1669
1670 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
1671
1672 HDassert( aux_ptr != NULL );
1673 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
1674
1675 aux_ptr->write_done = write_done;
1676
1677 FUNC_LEAVE_NOAPI(SUCCEED)
1678 } /* H5AC_set_write_done_callback() */
1679 #endif /* H5_HAVE_PARALLEL */
1680
1681
1682 /*-------------------------------------------------------------------------
1683 * Function: H5AC_stats
1684 *
1685 * Purpose: Prints statistics about the cache.
1686 *
1687 * Return: Non-negative on success/Negative on failure
1688 *
1689 * Programmer: Robb Matzke
1690 * Thursday, October 30, 1997
1691 *
1692 *-------------------------------------------------------------------------
1693 */
1694 herr_t
H5AC_stats(const H5F_t * f)1695 H5AC_stats(const H5F_t *f)
1696 {
1697 herr_t ret_value = SUCCEED; /* Return value */
1698
1699 FUNC_ENTER_NOAPI(FAIL)
1700
1701 HDassert(f);
1702 HDassert(f->shared);
1703 HDassert(f->shared->cache);
1704
1705 /* at present, this can't fail */
1706 (void)H5C_stats(f->shared->cache, H5F_OPEN_NAME(f), FALSE);
1707
1708 done:
1709 FUNC_LEAVE_NOAPI(ret_value)
1710 } /* H5AC_stats() */
1711
1712
1713 /*-------------------------------------------------------------------------
1714 * Function: H5AC_dump_cache
1715 *
1716 * Purpose: Dumps a summary of the contents of the metadata cache
1717 * to stdout.
1718 *
1719 * Return: Non-negative on success/Negative on failure
1720 *
1721 * Programmer: John Mainzer
1722 * Sunday, October 10, 2010
1723 *
1724 *-------------------------------------------------------------------------
1725 */
1726 herr_t
H5AC_dump_cache(const H5F_t * f)1727 H5AC_dump_cache(const H5F_t *f)
1728 {
1729 herr_t ret_value = SUCCEED; /* Return value */
1730
1731 FUNC_ENTER_NOAPI(FAIL)
1732
1733 HDassert(f);
1734 HDassert(f->shared);
1735 HDassert(f->shared->cache);
1736
1737 if ( H5C_dump_cache(f->shared->cache, H5F_OPEN_NAME(f)) < 0 ) {
1738
1739 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_dump_cache() failed.")
1740 }
1741
1742 done:
1743 FUNC_LEAVE_NOAPI(ret_value)
1744 } /* H5AC_dump_cache() */
1745
1746
1747 /*-------------------------------------------------------------------------
1748 * Function: H5AC_get_cache_auto_resize_config
1749 *
1750 * Purpose: Wrapper function for H5C_get_cache_auto_resize_config().
1751 *
1752 * Return: SUCCEED on success, and FAIL on failure.
1753 *
1754 * Programmer: John Mainzer
1755 * 3/10/05
1756 *
1757 *-------------------------------------------------------------------------
1758 */
1759 herr_t
H5AC_get_cache_auto_resize_config(const H5AC_t * cache_ptr,H5AC_cache_config_t * config_ptr)1760 H5AC_get_cache_auto_resize_config(const H5AC_t * cache_ptr,
1761 H5AC_cache_config_t *config_ptr)
1762 {
1763 herr_t result;
1764 herr_t ret_value = SUCCEED; /* Return value */
1765 hbool_t evictions_enabled;
1766 H5C_auto_size_ctl_t internal_config;
1767
1768 FUNC_ENTER_NOAPI(FAIL)
1769
1770 if ( ( cache_ptr == NULL )
1771 ||
1772 #ifdef H5_HAVE_PARALLEL
1773 ( ( cache_ptr->aux_ptr != NULL )
1774 &&
1775 ( ((H5AC_aux_t *)(cache_ptr->aux_ptr))->magic
1776 !=
1777 H5AC__H5AC_AUX_T_MAGIC
1778 )
1779 )
1780 ||
1781 #endif /* H5_HAVE_PARALLEL */
1782 ( config_ptr == NULL )
1783 ||
1784 ( config_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION )
1785 )
1786 {
1787 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
1788 "Bad cache_ptr or config_ptr on entry.")
1789
1790 }
1791
1792 result = H5C_get_cache_auto_resize_config((const H5C_t *)cache_ptr,
1793 &internal_config);
1794
1795 if ( result < 0 ) {
1796
1797 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
1798 "H5C_get_cache_auto_resize_config() failed.")
1799 }
1800
1801 if(H5C_get_evictions_enabled((const H5C_t *)cache_ptr, &evictions_enabled) < 0)
1802 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_resize_enabled() failed.")
1803
1804 if ( internal_config.rpt_fcn == NULL ) {
1805
1806 config_ptr->rpt_fcn_enabled = FALSE;
1807
1808 } else {
1809
1810 config_ptr->rpt_fcn_enabled = TRUE;
1811 }
1812
1813 config_ptr->open_trace_file = FALSE;
1814 config_ptr->close_trace_file = FALSE;
1815 config_ptr->trace_file_name[0] = '\0';
1816 config_ptr->evictions_enabled = evictions_enabled;
1817 config_ptr->set_initial_size = internal_config.set_initial_size;
1818 config_ptr->initial_size = internal_config.initial_size;
1819 config_ptr->min_clean_fraction = internal_config.min_clean_fraction;
1820 config_ptr->max_size = internal_config.max_size;
1821 config_ptr->min_size = internal_config.min_size;
1822 config_ptr->epoch_length = (long)(internal_config.epoch_length);
1823 config_ptr->incr_mode = internal_config.incr_mode;
1824 config_ptr->lower_hr_threshold = internal_config.lower_hr_threshold;
1825 config_ptr->increment = internal_config.increment;
1826 config_ptr->apply_max_increment = internal_config.apply_max_increment;
1827 config_ptr->max_increment = internal_config.max_increment;
1828 config_ptr->decr_mode = internal_config.decr_mode;
1829 config_ptr->upper_hr_threshold = internal_config.upper_hr_threshold;
1830 config_ptr->flash_incr_mode = internal_config.flash_incr_mode;
1831 config_ptr->flash_multiple = internal_config.flash_multiple;
1832 config_ptr->flash_threshold = internal_config.flash_threshold;
1833 config_ptr->decrement = internal_config.decrement;
1834 config_ptr->apply_max_decrement = internal_config.apply_max_decrement;
1835 config_ptr->max_decrement = internal_config.max_decrement;
1836 config_ptr->epochs_before_eviction =
1837 (int)(internal_config.epochs_before_eviction);
1838 config_ptr->apply_empty_reserve = internal_config.apply_empty_reserve;
1839 config_ptr->empty_reserve = internal_config.empty_reserve;
1840
1841 #ifdef H5_HAVE_PARALLEL
1842 if ( cache_ptr->aux_ptr != NULL ) {
1843
1844 config_ptr->dirty_bytes_threshold =
1845 ((H5AC_aux_t *)(cache_ptr->aux_ptr))->dirty_bytes_threshold;
1846 config_ptr->metadata_write_strategy =
1847 ((H5AC_aux_t *)(cache_ptr->aux_ptr))->metadata_write_strategy;
1848
1849 } else {
1850 #endif /* H5_HAVE_PARALLEL */
1851
1852 config_ptr->dirty_bytes_threshold =
1853 H5AC__DEFAULT_DIRTY_BYTES_THRESHOLD;
1854 config_ptr->metadata_write_strategy =
1855 H5AC__DEFAULT_METADATA_WRITE_STRATEGY;
1856
1857 #ifdef H5_HAVE_PARALLEL
1858 }
1859 #endif /* H5_HAVE_PARALLEL */
1860
1861 done:
1862
1863 FUNC_LEAVE_NOAPI(ret_value)
1864
1865 } /* H5AC_get_cache_auto_resize_config() */
1866
1867
1868 /*-------------------------------------------------------------------------
1869 * Function: H5AC_get_cache_size
1870 *
1871 * Purpose: Wrapper function for H5C_get_cache_size().
1872 *
1873 * Return: SUCCEED on success, and FAIL on failure.
1874 *
1875 * Programmer: John Mainzer
1876 * 3/11/05
1877 *
1878 *-------------------------------------------------------------------------
1879 */
1880 herr_t
H5AC_get_cache_size(H5AC_t * cache_ptr,size_t * max_size_ptr,size_t * min_clean_size_ptr,size_t * cur_size_ptr,int32_t * cur_num_entries_ptr)1881 H5AC_get_cache_size(H5AC_t * cache_ptr,
1882 size_t * max_size_ptr,
1883 size_t * min_clean_size_ptr,
1884 size_t * cur_size_ptr,
1885 int32_t * cur_num_entries_ptr)
1886 {
1887 herr_t result;
1888 herr_t ret_value = SUCCEED; /* Return value */
1889
1890 FUNC_ENTER_NOAPI(FAIL)
1891
1892 result = H5C_get_cache_size((H5C_t *)cache_ptr,
1893 max_size_ptr,
1894 min_clean_size_ptr,
1895 cur_size_ptr,
1896 cur_num_entries_ptr);
1897
1898 if ( result < 0 ) {
1899
1900 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
1901 "H5C_get_cache_size() failed.")
1902 }
1903
1904 done:
1905
1906 FUNC_LEAVE_NOAPI(ret_value)
1907
1908 } /* H5AC_get_cache_size() */
1909
1910
1911 /*-------------------------------------------------------------------------
1912 * Function: H5AC_get_cache_hit_rate
1913 *
1914 * Purpose: Wrapper function for H5C_get_cache_hit_rate().
1915 *
1916 * Return: SUCCEED on success, and FAIL on failure.
1917 *
1918 * Programmer: John Mainzer
1919 * 3/10/05
1920 *
1921 *-------------------------------------------------------------------------
1922 */
1923 herr_t
H5AC_get_cache_hit_rate(H5AC_t * cache_ptr,double * hit_rate_ptr)1924 H5AC_get_cache_hit_rate(H5AC_t * cache_ptr, double * hit_rate_ptr)
1925 {
1926 herr_t ret_value = SUCCEED; /* Return value */
1927
1928 FUNC_ENTER_NOAPI(FAIL)
1929
1930 if(H5C_get_cache_hit_rate((H5C_t *)cache_ptr, hit_rate_ptr) < 0)
1931 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_get_cache_hit_rate() failed.")
1932
1933 done:
1934 FUNC_LEAVE_NOAPI(ret_value)
1935 } /* H5AC_get_cache_hit_rate() */
1936
1937
1938 /*-------------------------------------------------------------------------
1939 *
1940 * Function: H5AC_reset_cache_hit_rate_stats()
1941 *
1942 * Purpose: Wrapper function for H5C_reset_cache_hit_rate_stats().
1943 *
1944 * Return: SUCCEED on success, and FAIL on failure.
1945 *
1946 * Programmer: John Mainzer, 3/10/05
1947 *
1948 *-------------------------------------------------------------------------
1949 */
1950 herr_t
H5AC_reset_cache_hit_rate_stats(H5AC_t * cache_ptr)1951 H5AC_reset_cache_hit_rate_stats(H5AC_t * cache_ptr)
1952 {
1953 herr_t result;
1954 herr_t ret_value = SUCCEED; /* Return value */
1955
1956 FUNC_ENTER_NOAPI(FAIL)
1957
1958 result = H5C_reset_cache_hit_rate_stats((H5C_t *)cache_ptr);
1959
1960 if ( result < 0 ) {
1961
1962 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
1963 "H5C_reset_cache_hit_rate_stats() failed.")
1964 }
1965
1966 done:
1967
1968 FUNC_LEAVE_NOAPI(ret_value)
1969
1970 } /* H5AC_reset_cache_hit_rate_stats() */
1971
1972
1973 /*-------------------------------------------------------------------------
1974 * Function: H5AC_set_cache_auto_resize_config
1975 *
1976 * Purpose: Wrapper function for H5C_set_cache_auto_resize_config().
1977 *
1978 * Return: SUCCEED on success, and FAIL on failure.
1979 *
1980 * Programmer: John Mainzer
1981 * 3/10/05
1982 *
1983 *-------------------------------------------------------------------------
1984 */
1985 herr_t
H5AC_set_cache_auto_resize_config(H5AC_t * cache_ptr,H5AC_cache_config_t * config_ptr)1986 H5AC_set_cache_auto_resize_config(H5AC_t *cache_ptr,
1987 H5AC_cache_config_t *config_ptr)
1988 {
1989 herr_t result;
1990 herr_t ret_value = SUCCEED; /* Return value */
1991 H5C_auto_size_ctl_t internal_config;
1992 #if H5AC__TRACE_FILE_ENABLED
1993 H5AC_cache_config_t trace_config = H5AC__DEFAULT_CACHE_CONFIG;
1994 FILE * trace_file_ptr = NULL;
1995 #endif /* H5AC__TRACE_FILE_ENABLED */
1996
1997 FUNC_ENTER_NOAPI(FAIL)
1998
1999 HDassert( cache_ptr );
2000
2001 #if H5AC__TRACE_FILE_ENABLED
2002 /* Make note of the new configuration. Don't look up the trace file
2003 * pointer, as that may change before we use it.
2004 */
2005 if ( config_ptr != NULL ) {
2006
2007 trace_config = *config_ptr;
2008
2009 }
2010 #endif /* H5AC__TRACE_FILE_ENABLED */
2011
2012 if ( ( cache_ptr == NULL )
2013 #ifdef H5_HAVE_PARALLEL
2014 ||
2015 ( ( cache_ptr->aux_ptr != NULL )
2016 &&
2017 (
2018 ((H5AC_aux_t *)(cache_ptr->aux_ptr))->magic
2019 !=
2020 H5AC__H5AC_AUX_T_MAGIC
2021 )
2022 )
2023 #endif /* H5_HAVE_PARALLEL */
2024 ) {
2025
2026 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "bad cache_ptr on entry.")
2027 }
2028
2029 result = H5AC_validate_config(config_ptr);
2030
2031 if ( result != SUCCEED ) {
2032
2033 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Bad cache configuration");
2034 }
2035
2036 if ( config_ptr->open_trace_file ) {
2037
2038 FILE * file_ptr = NULL;
2039
2040 if ( H5C_get_trace_file_ptr(cache_ptr, &file_ptr) < 0 ) {
2041
2042 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
2043 "H5C_get_trace_file_ptr() failed.")
2044 }
2045
2046 if ( ( ! ( config_ptr->close_trace_file ) ) &&
2047 ( file_ptr != NULL ) ) {
2048
2049 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \
2050 "Trace file already open.")
2051 }
2052 }
2053
2054 if ( config_ptr->close_trace_file ) {
2055
2056 if ( H5AC_close_trace_file(cache_ptr) < 0 ) {
2057
2058 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
2059 "H5AC_close_trace_file() failed.")
2060 }
2061 }
2062
2063 if ( config_ptr->open_trace_file ) {
2064
2065 if ( H5AC_open_trace_file(cache_ptr, config_ptr->trace_file_name) < 0 )
2066 {
2067
2068 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \
2069 "H5AC_open_trace_file() failed.")
2070 }
2071 }
2072
2073 if(H5AC_ext_config_2_int_config(config_ptr, &internal_config) < 0)
2074 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_ext_config_2_int_config() failed.")
2075
2076 if(H5C_set_cache_auto_resize_config(cache_ptr, &internal_config) < 0)
2077 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_set_cache_auto_resize_config() failed.")
2078
2079 if(H5C_set_evictions_enabled(cache_ptr, config_ptr->evictions_enabled) < 0)
2080 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_set_evictions_enabled() failed.")
2081
2082 #ifdef H5_HAVE_PARALLEL
2083 if ( cache_ptr->aux_ptr != NULL ) {
2084
2085 ((H5AC_aux_t *)(cache_ptr->aux_ptr))->dirty_bytes_threshold =
2086 config_ptr->dirty_bytes_threshold;
2087
2088 ((H5AC_aux_t *)(cache_ptr->aux_ptr))->metadata_write_strategy =
2089 config_ptr->metadata_write_strategy;
2090 }
2091 #endif /* H5_HAVE_PARALLEL */
2092
2093 done:
2094
2095 #if H5AC__TRACE_FILE_ENABLED
2096 /* For the set cache auto resize config call, only the contents
2097 * of the config is necessary in the trace file. Write the return
2098 * value to catch occult errors.
2099 */
2100 if ( ( cache_ptr != NULL ) &&
2101 ( H5C_get_trace_file_ptr(cache_ptr, &trace_file_ptr) >= 0 ) &&
2102 ( trace_file_ptr != NULL ) ) {
2103
2104 HDfprintf(trace_file_ptr,
2105 "%s %d %d %d %d \"%s\" %d %d %d %f %d %d %ld %d %f %f %d %f %f %d %d %d %f %f %d %d %d %d %f %d %d %d\n",
2106 "H5AC_set_cache_auto_resize_config",
2107 trace_config.version,
2108 (int)(trace_config.rpt_fcn_enabled),
2109 (int)(trace_config.open_trace_file),
2110 (int)(trace_config.close_trace_file),
2111 trace_config.trace_file_name,
2112 (int)(trace_config.evictions_enabled),
2113 (int)(trace_config.set_initial_size),
2114 (int)(trace_config.initial_size),
2115 trace_config.min_clean_fraction,
2116 (int)(trace_config.max_size),
2117 (int)(trace_config.min_size),
2118 trace_config.epoch_length,
2119 (int)(trace_config.incr_mode),
2120 trace_config.lower_hr_threshold,
2121 trace_config.increment,
2122 (int)(trace_config.flash_incr_mode),
2123 trace_config.flash_multiple,
2124 trace_config.flash_threshold,
2125 (int)(trace_config.apply_max_increment),
2126 (int)(trace_config.max_increment),
2127 (int)(trace_config.decr_mode),
2128 trace_config.upper_hr_threshold,
2129 trace_config.decrement,
2130 (int)(trace_config.apply_max_decrement),
2131 (int)(trace_config.max_decrement),
2132 trace_config.epochs_before_eviction,
2133 (int)(trace_config.apply_empty_reserve),
2134 trace_config.empty_reserve,
2135 trace_config.dirty_bytes_threshold,
2136 trace_config.metadata_write_strategy,
2137 (int)ret_value);
2138 }
2139 #endif /* H5AC__TRACE_FILE_ENABLED */
2140
2141 FUNC_LEAVE_NOAPI(ret_value)
2142
2143 } /* H5AC_set_cache_auto_resize_config() */
2144
2145
2146 /*-------------------------------------------------------------------------
2147 * Function: H5AC_validate_config()
2148 *
2149 * Purpose: Run a sanity check on the contents of the supplied
2150 * instance of H5AC_cache_config_t.
2151 *
2152 * Do nothing and return SUCCEED if no errors are detected,
2153 * and flag an error and return FAIL otherwise.
2154 *
2155 * At present, this function operates by packing the data
2156 * from the instance of H5AC_cache_config_t into an instance
2157 * of H5C_auto_size_ctl_t, and then calling
2158 * H5C_validate_resize_config(). As H5AC_cache_config_t and
2159 * H5C_auto_size_ctl_t diverge, we may have to change this.
2160 *
2161 * Return: Non-negative on success/Negative on failure
2162 *
2163 * Programmer: John Mainzer
2164 * 4/6/05
2165 *
2166 *-------------------------------------------------------------------------
2167 */
2168 herr_t
H5AC_validate_config(H5AC_cache_config_t * config_ptr)2169 H5AC_validate_config(H5AC_cache_config_t * config_ptr)
2170 {
2171 H5C_auto_size_ctl_t internal_config;
2172 herr_t ret_value = SUCCEED; /* Return value */
2173
2174 FUNC_ENTER_NOAPI(FAIL)
2175
2176 if(config_ptr == NULL)
2177 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL config_ptr on entry.")
2178
2179 if(config_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION)
2180 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Unknown config version.")
2181
2182 if((config_ptr->rpt_fcn_enabled != TRUE) && (config_ptr->rpt_fcn_enabled != FALSE))
2183 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "config_ptr->rpt_fcn_enabled must be either TRUE or FALSE.")
2184
2185 if((config_ptr->open_trace_file != TRUE) && (config_ptr->open_trace_file != FALSE))
2186 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "config_ptr->open_trace_file must be either TRUE or FALSE.")
2187
2188 if((config_ptr->close_trace_file != TRUE) && (config_ptr->close_trace_file != FALSE))
2189 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "config_ptr->close_trace_file must be either TRUE or FALSE.")
2190
2191 /* don't bother to test trace_file_name unless open_trace_file is TRUE */
2192 if(config_ptr->open_trace_file) {
2193 size_t name_len;
2194
2195 /* Can't really test the trace_file_name field without trying to
2196 * open the file, so we will content ourselves with a couple of
2197 * sanity checks on the length of the file name.
2198 */
2199 name_len = HDstrlen(config_ptr->trace_file_name);
2200
2201 if(name_len == 0) {
2202 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "config_ptr->trace_file_name is empty.")
2203 } else if(name_len > H5AC__MAX_TRACE_FILE_NAME_LEN) {
2204 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "config_ptr->trace_file_name too long.")
2205 }
2206 }
2207
2208 if ( ( config_ptr->evictions_enabled != TRUE ) &&
2209 ( config_ptr->evictions_enabled != FALSE ) ) {
2210
2211 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \
2212 "config_ptr->evictions_enabled must be either TRUE or FALSE.")
2213 }
2214
2215 if ( ( config_ptr->evictions_enabled == FALSE ) &&
2216 ( ( config_ptr->incr_mode != H5C_incr__off ) ||
2217 ( config_ptr->flash_incr_mode != H5C_flash_incr__off ) ||
2218 ( config_ptr->decr_mode != H5C_decr__off ) ) ) {
2219
2220 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \
2221 "Can't disable evictions while auto-resize is enabled.")
2222 }
2223
2224 if(config_ptr->dirty_bytes_threshold < H5AC__MIN_DIRTY_BYTES_THRESHOLD) {
2225 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dirty_bytes_threshold too small.")
2226 } else if(config_ptr->dirty_bytes_threshold > H5AC__MAX_DIRTY_BYTES_THRESHOLD) {
2227 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dirty_bytes_threshold too big.")
2228 }
2229
2230 if((config_ptr->metadata_write_strategy != H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY) &&
2231 (config_ptr->metadata_write_strategy != H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED))
2232 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "config_ptr->metadata_write_strategy out of range.")
2233
2234 if(H5AC_ext_config_2_int_config(config_ptr, &internal_config) < 0)
2235 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5AC_ext_config_2_int_config() failed.")
2236
2237 if(H5C_validate_resize_config(&internal_config, H5C_RESIZE_CFG__VALIDATE_ALL) < 0)
2238 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error(s) in new config.")
2239
2240 done:
2241 FUNC_LEAVE_NOAPI(ret_value)
2242 } /* H5AC_validate_config() */
2243
2244
2245 /*-------------------------------------------------------------------------
2246 * Function: H5AC_close_trace_file()
2247 *
2248 * Purpose: If a trace file is open, stop logging calls to the cache,
2249 * and close the file.
2250 *
2251 * Note that the function does nothing if there is no trace
2252 * file.
2253 *
2254 * Return: Non-negative on success/Negative on failure
2255 *
2256 * Programmer: John Mainzer
2257 * 6/2/06
2258 *
2259 *-------------------------------------------------------------------------
2260 */
2261 herr_t
H5AC_close_trace_file(H5AC_t * cache_ptr)2262 H5AC_close_trace_file(H5AC_t * cache_ptr)
2263
2264 {
2265 herr_t ret_value = SUCCEED; /* Return value */
2266 FILE * trace_file_ptr = NULL;
2267
2268 FUNC_ENTER_NOAPI(FAIL)
2269
2270 if ( cache_ptr == NULL ) {
2271
2272 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL cache_ptr on entry.")
2273 }
2274
2275 if ( H5C_get_trace_file_ptr(cache_ptr, &trace_file_ptr) < 0 ) {
2276
2277 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
2278 "H5C_get_trace_file_ptr() failed.")
2279 }
2280
2281 if ( trace_file_ptr != NULL ) {
2282
2283 if ( H5C_set_trace_file_ptr(cache_ptr, NULL) < 0 ) {
2284
2285 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
2286 "H5C_set_trace_file_ptr() failed.")
2287 }
2288
2289 if ( HDfclose(trace_file_ptr) != 0 ) {
2290
2291 HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, \
2292 "can't close metadata cache trace file")
2293 }
2294 }
2295
2296 done:
2297
2298 FUNC_LEAVE_NOAPI(ret_value)
2299
2300 } /* H5AC_close_trace_file() */
2301
2302
2303 /*-------------------------------------------------------------------------
2304 * Function: H5AC_open_trace_file()
2305 *
2306 * Purpose: Open a trace file, and start logging calls to the cache.
2307 *
2308 * This logging is done at the H5C level, and will only take
2309 * place if H5C_TRACE_FILE_ENABLED (defined in H5Cprivate.h)
2310 * is TRUE.
2311 *
2312 * Return: Non-negative on success/Negative on failure
2313 *
2314 * Programmer: John Mainzer
2315 * 6/1/06
2316 *
2317 *-------------------------------------------------------------------------
2318 */
2319 herr_t
H5AC_open_trace_file(H5AC_t * cache_ptr,const char * trace_file_name)2320 H5AC_open_trace_file(H5AC_t * cache_ptr,
2321 const char * trace_file_name)
2322 {
2323 herr_t ret_value = SUCCEED; /* Return value */
2324 char file_name[H5AC__MAX_TRACE_FILE_NAME_LEN + H5C__PREFIX_LEN + 2];
2325 FILE * file_ptr = NULL;
2326 #ifdef H5_HAVE_PARALLEL
2327 H5AC_aux_t * aux_ptr = NULL;
2328 #endif /* H5_HAVE_PARALLEL */
2329
2330 FUNC_ENTER_NOAPI(FAIL)
2331
2332 HDassert(cache_ptr);
2333
2334 if ( cache_ptr == NULL ) {
2335
2336 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache_ptr NULL on entry.")
2337 }
2338
2339 if ( trace_file_name == NULL ) {
2340
2341 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \
2342 "NULL trace_file_name on entry.")
2343 }
2344
2345 if ( HDstrlen(trace_file_name) > H5AC__MAX_TRACE_FILE_NAME_LEN ) {
2346
2347 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "trace file name too long.")
2348 }
2349
2350 if ( H5C_get_trace_file_ptr(cache_ptr, &file_ptr) < 0 ) {
2351
2352 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
2353 "H5C_get_trace_file_ptr() failed.")
2354 }
2355
2356 if ( file_ptr != NULL ) {
2357
2358 HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "trace file already open.")
2359 }
2360
2361 #ifdef H5_HAVE_PARALLEL
2362
2363 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
2364
2365 if ( cache_ptr->aux_ptr == NULL ) {
2366
2367 sprintf(file_name, "%s", trace_file_name);
2368
2369 } else {
2370
2371 if ( aux_ptr->magic != H5AC__H5AC_AUX_T_MAGIC ) {
2372
2373 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad aux_ptr->magic.")
2374 }
2375
2376 sprintf(file_name, "%s.%d", trace_file_name, aux_ptr->mpi_rank);
2377
2378 }
2379
2380 if ( HDstrlen(file_name) >
2381 H5AC__MAX_TRACE_FILE_NAME_LEN + H5C__PREFIX_LEN + 1 ) {
2382
2383 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
2384 "cooked trace file name too long.")
2385 }
2386
2387 #else /* H5_HAVE_PARALLEL */
2388
2389 HDsnprintf(file_name,
2390 (size_t)(H5AC__MAX_TRACE_FILE_NAME_LEN + H5C__PREFIX_LEN + 1),
2391 "%s", trace_file_name);
2392
2393 #endif /* H5_HAVE_PARALLEL */
2394
2395 if ( (file_ptr = HDfopen(file_name, "w")) == NULL ) {
2396
2397 /* trace file open failed */
2398 HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "trace file open failed.")
2399 }
2400
2401 HDfprintf(file_ptr, "### HDF5 metadata cache trace file ###\n");
2402
2403 if ( H5C_set_trace_file_ptr(cache_ptr, file_ptr) < 0 ) {
2404
2405 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
2406 "H5C_set_trace_file_ptr() failed.")
2407 }
2408
2409 done:
2410
2411 FUNC_LEAVE_NOAPI(ret_value)
2412
2413 } /* H5AC_open_trace_file() */
2414
2415
2416 /*-------------------------------------------------------------------------
2417 * Function: H5AC_add_candidate()
2418 *
2419 * Purpose: Add the supplied metadata entry address to the candidate
2420 * list. Verify that each entry added does not appear in
2421 * the list prior to its insertion.
2422 *
2423 * This function is intended for used in constructing list
2424 * of entried to be flushed during sync points. It shouldn't
2425 * be called anywhere else.
2426 *
2427 * Return: Non-negative on success/Negative on failure
2428 *
2429 * Programmer: John Mainzer
2430 * 3/17/10
2431 *
2432 *-------------------------------------------------------------------------
2433 */
2434 #ifdef H5_HAVE_PARALLEL
2435 herr_t
H5AC_add_candidate(H5AC_t * cache_ptr,haddr_t addr)2436 H5AC_add_candidate(H5AC_t * cache_ptr,
2437 haddr_t addr)
2438 {
2439 H5AC_aux_t * aux_ptr;
2440 H5AC_slist_entry_t * slist_entry_ptr = NULL;
2441 herr_t ret_value = SUCCEED; /* Return value */
2442
2443 FUNC_ENTER_NOAPI(FAIL)
2444
2445 HDassert( cache_ptr != NULL );
2446 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
2447
2448 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
2449
2450 HDassert( aux_ptr != NULL );
2451 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
2452 HDassert( aux_ptr->metadata_write_strategy ==
2453 H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED );
2454 HDassert( aux_ptr->candidate_slist_ptr != NULL );
2455
2456 /* If the supplied address appears in the candidate list, scream and die. */
2457 if(NULL != H5SL_search(aux_ptr->candidate_slist_ptr, (void *)(&addr)))
2458 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "entry already in candidate slist.")
2459
2460 /* otherwise, construct an entry for the supplied address, and insert
2461 * it into the candidate slist.
2462 */
2463 if(NULL == (slist_entry_ptr = H5FL_CALLOC(H5AC_slist_entry_t)))
2464 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "Can't allocate candidate slist entry .")
2465
2466 slist_entry_ptr->magic = H5AC__H5AC_SLIST_ENTRY_T_MAGIC;
2467 slist_entry_ptr->addr = addr;
2468
2469 if(H5SL_insert(aux_ptr->candidate_slist_ptr, slist_entry_ptr, &(slist_entry_ptr->addr)) < 0)
2470 HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "can't insert entry into dirty entry slist.")
2471
2472 aux_ptr->candidate_slist_len += 1;
2473
2474 done:
2475 FUNC_LEAVE_NOAPI(ret_value)
2476 } /* H5AC_add_candidate() */
2477 #endif /* H5_HAVE_PARALLEL */
2478
2479
2480 /*************************************************************************/
2481 /**************************** Private Functions: *************************/
2482 /*************************************************************************/
2483
2484 /*-------------------------------------------------------------------------
2485 *
2486 * Function: H5AC_broadcast_candidate_list()
2487 *
2488 * Purpose: Broadcast the contents of the process 0 candidate entry
2489 * slist. In passing, also remove all entries from said
2490 * list. As the application of this will be handled by
2491 * the same functions on all processes, construct and
2492 * return a copy of the list in the same format as that
2493 * received by the other processes. Note that if this
2494 * copy is returned in *haddr_buf_ptr_ptr, the caller
2495 * must free it.
2496 *
2497 * This function must only be called by the process with
2498 * MPI_rank 0.
2499 *
2500 * Return SUCCEED on success, and FAIL on failure.
2501 *
2502 * Return: Non-negative on success/Negative on failure.
2503 *
2504 * Programmer: John Mainzer, 7/1/05
2505 *
2506 *-------------------------------------------------------------------------
2507 */
2508 #ifdef H5_HAVE_PARALLEL
2509 static herr_t
H5AC_broadcast_candidate_list(H5AC_t * cache_ptr,int * num_entries_ptr,haddr_t ** haddr_buf_ptr_ptr)2510 H5AC_broadcast_candidate_list(H5AC_t * cache_ptr,
2511 int * num_entries_ptr,
2512 haddr_t ** haddr_buf_ptr_ptr)
2513 {
2514 herr_t result;
2515 hbool_t success = FALSE;
2516 H5AC_aux_t * aux_ptr = NULL;
2517 haddr_t * haddr_buf_ptr = NULL;
2518 MPI_Offset * MPI_Offset_buf_ptr = NULL;
2519 size_t buf_size = 0;
2520 int mpi_result;
2521 int chk_num_entries = 0;
2522 int num_entries = 0;
2523 herr_t ret_value = SUCCEED; /* Return value */
2524
2525 FUNC_ENTER_NOAPI(FAIL)
2526
2527 HDassert( cache_ptr != NULL );
2528 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
2529
2530 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
2531
2532 HDassert( aux_ptr != NULL );
2533 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
2534 HDassert( aux_ptr->mpi_rank == 0 );
2535 HDassert( aux_ptr->metadata_write_strategy ==
2536 H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED );
2537 HDassert( aux_ptr->candidate_slist_ptr != NULL );
2538 HDassert( H5SL_count(aux_ptr->candidate_slist_ptr) ==
2539 (size_t)(aux_ptr->candidate_slist_len) );
2540 HDassert( num_entries_ptr != NULL );
2541 HDassert( *num_entries_ptr == 0 );
2542 HDassert( haddr_buf_ptr_ptr != NULL );
2543 HDassert( *haddr_buf_ptr_ptr == NULL );
2544
2545 /* First broadcast the number of entries in the list so that the
2546 * receivers can set up buffers to receive them. If there aren't
2547 * any, we are done.
2548 */
2549 num_entries = aux_ptr->candidate_slist_len;
2550 if(MPI_SUCCESS != (mpi_result = MPI_Bcast(&num_entries, 1, MPI_INT, 0, aux_ptr->mpi_comm)))
2551 HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 1", mpi_result)
2552
2553 if(num_entries > 0) {
2554 /* convert the candidate list into the format we
2555 * are used to receiving from process 0, and also load it
2556 * into a buffer for transmission.
2557 */
2558 if(H5AC_copy_candidate_list_to_buffer(cache_ptr, &chk_num_entries,
2559 &haddr_buf_ptr, &buf_size, &MPI_Offset_buf_ptr) < 0)
2560 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't construct candidate buffer.")
2561
2562 HDassert( chk_num_entries == num_entries );
2563 HDassert( haddr_buf_ptr != NULL );
2564 HDassert( MPI_Offset_buf_ptr != NULL );
2565 HDassert( aux_ptr->candidate_slist_len == 0 );
2566
2567 /* Now broadcast the list of candidate entries -- if there is one.
2568 *
2569 * The peculiar structure of the following call to MPI_Bcast is
2570 * due to MPI's (?) failure to believe in the MPI_Offset type.
2571 * Thus the element type is MPI_BYTE, with size equal to the
2572 * buf_size computed above.
2573 */
2574 if(MPI_SUCCESS != (mpi_result = MPI_Bcast((void *)MPI_Offset_buf_ptr, (int)buf_size, MPI_BYTE, 0, aux_ptr->mpi_comm)))
2575 HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 2", mpi_result)
2576 } /* end if */
2577
2578 success = TRUE;
2579
2580 done:
2581 if(MPI_Offset_buf_ptr != NULL)
2582 MPI_Offset_buf_ptr = (MPI_Offset *)H5MM_xfree((void *)MPI_Offset_buf_ptr);
2583
2584 if(success) {
2585 /* Pass the number of entries and the buffer pointer
2586 * back to the caller. Do this so that we can use the same code
2587 * to apply the candidate list to all the processes.
2588 */
2589 *num_entries_ptr = num_entries;
2590 *haddr_buf_ptr_ptr = haddr_buf_ptr;
2591 } else if(haddr_buf_ptr != NULL) {
2592 haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr);
2593 }
2594
2595 FUNC_LEAVE_NOAPI(ret_value)
2596 } /* H5AC_broadcast_candidate_list() */
2597 #endif /* H5_HAVE_PARALLEL */
2598
2599
2600 /*-------------------------------------------------------------------------
2601 *
2602 * Function: H5AC_broadcast_clean_list()
2603 *
2604 * Purpose: Broadcast the contents of the process 0 cleaned entry
2605 * slist. In passing, also remove all entries from said
2606 * list, and also remove any matching entries from the dirtied
2607 * slist.
2608 *
2609 * This function must only be called by the process with
2610 * MPI_rank 0.
2611 *
2612 * Return SUCCEED on success, and FAIL on failure.
2613 *
2614 * Return: Non-negative on success/Negative on failure.
2615 *
2616 * Programmer: John Mainzer, 7/1/05
2617 *
2618 *-------------------------------------------------------------------------
2619 */
2620 #ifdef H5_HAVE_PARALLEL
2621 static herr_t
H5AC_broadcast_clean_list(H5AC_t * cache_ptr)2622 H5AC_broadcast_clean_list(H5AC_t * cache_ptr)
2623 {
2624 herr_t ret_value = SUCCEED; /* Return value */
2625 haddr_t addr;
2626 haddr_t * addr_buf_ptr = NULL;
2627 H5AC_aux_t * aux_ptr = NULL;
2628 H5SL_node_t * slist_node_ptr = NULL;
2629 H5AC_slist_entry_t * slist_entry_ptr = NULL;
2630 MPI_Offset * buf_ptr = NULL;
2631 size_t buf_size;
2632 int i = 0;
2633 int mpi_result;
2634 int num_entries = 0;
2635
2636 FUNC_ENTER_NOAPI(FAIL)
2637
2638 HDassert( cache_ptr != NULL );
2639 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
2640
2641 aux_ptr = (H5AC_aux_t *)cache_ptr->aux_ptr;
2642
2643 HDassert( aux_ptr != NULL );
2644 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
2645 HDassert( aux_ptr->mpi_rank == 0 );
2646 HDassert( aux_ptr->c_slist_ptr != NULL );
2647 HDassert( H5SL_count(aux_ptr->c_slist_ptr) ==
2648 (size_t)(aux_ptr->c_slist_len) );
2649
2650
2651 /* First broadcast the number of entries in the list so that the
2652 * receives can set up a buffer to receive them. If there aren't
2653 * any, we are done.
2654 */
2655 num_entries = aux_ptr->c_slist_len;
2656
2657 mpi_result = MPI_Bcast(&num_entries, 1, MPI_INT, 0, aux_ptr->mpi_comm);
2658
2659 if ( mpi_result != MPI_SUCCESS ) {
2660
2661 HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 1", mpi_result)
2662
2663 }
2664
2665 if ( num_entries > 0 )
2666 {
2667 /* allocate a buffer to store the list of entry base addresses in */
2668
2669 buf_size = sizeof(MPI_Offset) * (size_t)num_entries;
2670
2671 buf_ptr = (MPI_Offset *)H5MM_malloc(buf_size);
2672
2673 if ( buf_ptr == NULL ) {
2674
2675 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \
2676 "memory allocation failed for clean entry buffer")
2677 }
2678
2679 /* if the sync_point_done callback is defined, allocate the
2680 * addr buffer as well.
2681 */
2682 if ( aux_ptr->sync_point_done != NULL ) {
2683
2684 addr_buf_ptr = H5MM_malloc((size_t)(num_entries * sizeof(haddr_t)));
2685
2686 if ( addr_buf_ptr == NULL ) {
2687
2688 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \
2689 "memory allocation failed for addr buffer")
2690 }
2691 }
2692
2693
2694 /* now load the entry base addresses into the buffer, emptying the
2695 * cleaned entry list in passing
2696 */
2697
2698 while ( NULL != (slist_node_ptr = H5SL_first(aux_ptr->c_slist_ptr) ) )
2699 {
2700 slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_item(slist_node_ptr);
2701
2702 HDassert(slist_entry_ptr->magic == H5AC__H5AC_SLIST_ENTRY_T_MAGIC);
2703
2704 HDassert( i < num_entries );
2705
2706 addr = slist_entry_ptr->addr;
2707
2708 if ( addr_buf_ptr != NULL ) {
2709
2710 addr_buf_ptr[i] = addr;
2711 }
2712
2713 if ( H5FD_mpi_haddr_to_MPIOff(addr, &(buf_ptr[i])) < 0 ) {
2714
2715 HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, \
2716 "can't convert from haddr to MPI off")
2717 }
2718
2719 i++;
2720
2721 /* now remove the entry from the cleaned entry list */
2722 if ( H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr))
2723 != slist_entry_ptr ) {
2724
2725 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \
2726 "Can't delete entry from cleaned entry slist.")
2727 }
2728
2729 slist_entry_ptr->magic = 0;
2730 H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
2731 slist_entry_ptr = NULL;
2732
2733 aux_ptr->c_slist_len -= 1;
2734
2735 HDassert( aux_ptr->c_slist_len >= 0 );
2736
2737 /* and also remove the matching entry from the dirtied list
2738 * if it exists.
2739 */
2740 if((slist_entry_ptr = H5SL_search(aux_ptr->d_slist_ptr, (void *)(&addr))) != NULL) {
2741 HDassert( slist_entry_ptr->magic == H5AC__H5AC_SLIST_ENTRY_T_MAGIC );
2742 HDassert( slist_entry_ptr->addr == addr );
2743
2744 if(H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&addr)) != slist_entry_ptr)
2745 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, "Can't delete entry from dirty entry slist.")
2746
2747 slist_entry_ptr->magic = 0;
2748 H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
2749 slist_entry_ptr = NULL;
2750
2751 aux_ptr->d_slist_len -= 1;
2752
2753 HDassert( aux_ptr->d_slist_len >= 0 );
2754 } /* end if */
2755 } /* while */
2756
2757
2758 /* Now broadcast the list of cleaned entries -- if there is one.
2759 *
2760 * The peculiar structure of the following call to MPI_Bcast is
2761 * due to MPI's (?) failure to believe in the MPI_Offset type.
2762 * Thus the element type is MPI_BYTE, with size equal to the
2763 * buf_size computed above.
2764 */
2765
2766 mpi_result = MPI_Bcast((void *)buf_ptr, (int)buf_size, MPI_BYTE, 0,
2767 aux_ptr->mpi_comm);
2768
2769 if ( mpi_result != MPI_SUCCESS ) {
2770
2771 HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 2", mpi_result)
2772 }
2773 }
2774
2775 if(aux_ptr->sync_point_done != NULL)
2776 (aux_ptr->sync_point_done)(num_entries, addr_buf_ptr);
2777
2778 done:
2779 if(buf_ptr != NULL)
2780 buf_ptr = (MPI_Offset *)H5MM_xfree((void *)buf_ptr);
2781 if(addr_buf_ptr != NULL)
2782 addr_buf_ptr = (MPI_Offset *)H5MM_xfree((void *)addr_buf_ptr);
2783
2784 FUNC_LEAVE_NOAPI(ret_value)
2785 } /* H5AC_broadcast_clean_list() */
2786 #endif /* H5_HAVE_PARALLEL */
2787
2788
2789 /*-------------------------------------------------------------------------
2790 *
2791 * Function: H5AC_check_if_write_permitted
2792 *
2793 * Purpose: Determine if a write is permitted under the current
2794 * circumstances, and set *write_permitted_ptr accordingly.
2795 * As a general rule it is, but when we are running in parallel
2796 * mode with collective I/O, we must ensure that a read cannot
2797 * cause a write.
2798 *
2799 * In the event of failure, the value of *write_permitted_ptr
2800 * is undefined.
2801 *
2802 * Return: Non-negative on success/Negative on failure.
2803 *
2804 * Programmer: John Mainzer, 5/15/04
2805 *
2806 *-------------------------------------------------------------------------
2807 */
2808 #ifdef H5_HAVE_PARALLEL
2809 static herr_t
H5AC_check_if_write_permitted(const H5F_t * f,hid_t UNUSED dxpl_id,hbool_t * write_permitted_ptr)2810 H5AC_check_if_write_permitted(const H5F_t *f,
2811 hid_t UNUSED dxpl_id,
2812 hbool_t * write_permitted_ptr)
2813 #else /* H5_HAVE_PARALLEL */
2814 static herr_t
2815 H5AC_check_if_write_permitted(const H5F_t UNUSED * f,
2816 hid_t UNUSED dxpl_id,
2817 hbool_t * write_permitted_ptr)
2818 #endif /* H5_HAVE_PARALLEL */
2819 {
2820 hbool_t write_permitted = TRUE;
2821 herr_t ret_value = SUCCEED; /* Return value */
2822 #ifdef H5_HAVE_PARALLEL
2823 H5AC_aux_t * aux_ptr = NULL;
2824 #endif /* H5_HAVE_PARALLEL */
2825
2826
2827 FUNC_ENTER_NOAPI(FAIL)
2828
2829 #ifdef H5_HAVE_PARALLEL
2830 HDassert( f != NULL );
2831 HDassert( f->shared != NULL );
2832 HDassert( f->shared->cache != NULL );
2833
2834 aux_ptr = (H5AC_aux_t *)(f->shared->cache->aux_ptr);
2835
2836 if ( aux_ptr != NULL ) {
2837
2838 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
2839
2840 if ( ( aux_ptr->mpi_rank == 0 ) ||
2841 ( aux_ptr->metadata_write_strategy ==
2842 H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED ) ) {
2843
2844 write_permitted = aux_ptr->write_permitted;
2845
2846 } else {
2847
2848 write_permitted = FALSE;
2849 }
2850 }
2851 #endif /* H5_HAVE_PARALLEL */
2852
2853 *write_permitted_ptr = write_permitted;
2854
2855 done:
2856
2857 FUNC_LEAVE_NOAPI(ret_value)
2858
2859 } /* H5AC_check_if_write_permitted() */
2860
2861
2862 /*-------------------------------------------------------------------------
2863 * Function: H5AC_construct_candidate_list()
2864 *
2865 * Purpose: In the parallel case when the metadata_write_strategy is
2866 * H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED, process 0 uses
2867 * this function to construct the list of cache entries to
2868 * be flushed. This list is then propagated to the other
2869 * caches, and then flushed in a distributed fashion.
2870 *
2871 * The sync_point_op parameter is used to determine the extent
2872 * of the flush.
2873 *
2874 * Return: Non-negative on success/Negative on failure
2875 *
2876 * Programmer: John Mainzer
2877 * 3/17/10
2878 *
2879 *-------------------------------------------------------------------------
2880 */
2881 #ifdef H5_HAVE_PARALLEL
2882 herr_t
H5AC_construct_candidate_list(H5AC_t * cache_ptr,H5AC_aux_t * aux_ptr,int sync_point_op)2883 H5AC_construct_candidate_list(H5AC_t * cache_ptr,
2884 H5AC_aux_t * aux_ptr,
2885 int sync_point_op)
2886 {
2887 herr_t ret_value = SUCCEED; /* Return value */
2888
2889 FUNC_ENTER_NOAPI(FAIL)
2890
2891 HDassert( cache_ptr != NULL );
2892 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
2893 HDassert( aux_ptr != NULL );
2894 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
2895 HDassert( aux_ptr->metadata_write_strategy ==
2896 H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED );
2897 HDassert( ( sync_point_op == H5AC_SYNC_POINT_OP__FLUSH_CACHE ) ||
2898 ( aux_ptr->mpi_rank == 0 ) );
2899 HDassert( aux_ptr->d_slist_ptr != NULL );
2900 HDassert( aux_ptr->c_slist_ptr != NULL );
2901 HDassert( aux_ptr->c_slist_len == 0 );
2902 HDassert( aux_ptr->candidate_slist_ptr != NULL );
2903 HDassert( aux_ptr->candidate_slist_len == 0 );
2904 HDassert( ( sync_point_op == H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN ) ||
2905 ( sync_point_op == H5AC_SYNC_POINT_OP__FLUSH_CACHE ) );
2906
2907 switch(sync_point_op) {
2908 case H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN:
2909 if(H5C_construct_candidate_list__min_clean((H5C_t *)cache_ptr) < 0)
2910 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_construct_candidate_list__min_clean() failed.")
2911 break;
2912
2913 case H5AC_SYNC_POINT_OP__FLUSH_CACHE:
2914 if(H5C_construct_candidate_list__clean_cache((H5C_t *)cache_ptr) < 0)
2915 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_construct_candidate_list__clean_cache() failed.")
2916 break;
2917
2918 default:
2919 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unknown sync point operation.")
2920 break;
2921 } /* end switch */
2922
2923 done:
2924 FUNC_LEAVE_NOAPI(ret_value)
2925 } /* H5AC_construct_candidate_list() */
2926 #endif /* H5_HAVE_PARALLEL */
2927
2928
2929 /*-------------------------------------------------------------------------
2930 *
2931 * Function: H5AC_copy_candidate_list_to_buffer
2932 *
2933 * Purpose: Allocate buffer(s) and copy the contents of the candidate
2934 * entry slist into it (them). In passing, remove all
2935 * entries from the candidate slist. Note that the
2936 * candidate slist must not be empty.
2937 *
2938 * If MPI_Offset_buf_ptr_ptr is not NULL, allocate a buffer
2939 * of MPI_Offset, copy the contents of the candidate
2940 * entry list into it with the appropriate conversions,
2941 * and return the base address of the buffer in
2942 * *MPI_Offset_buf_ptr. Note that this is the buffer
2943 * used by process 0 to transmit the list of entries to
2944 * be flushed to all other processes (in this file group).
2945 *
2946 * Similarly, allocate a buffer of haddr_t, load the contents
2947 * of the candidate list into this buffer, and return its
2948 * base address in *haddr_buf_ptr_ptr. Note that this
2949 * latter buffer is constructed unconditionally.
2950 *
2951 * In passing, also remove all entries from the candidate
2952 * entry slist.
2953 *
2954 * Return: Return SUCCEED on success, and FAIL on failure.
2955 *
2956 * Programmer: John Mainzer, 4/19/10
2957 *
2958 *-------------------------------------------------------------------------
2959 */
2960 #ifdef H5_HAVE_PARALLEL
2961 static herr_t
H5AC_copy_candidate_list_to_buffer(H5AC_t * cache_ptr,int * num_entries_ptr,haddr_t ** haddr_buf_ptr_ptr,size_t * MPI_Offset_buf_size_ptr,MPI_Offset ** MPI_Offset_buf_ptr_ptr)2962 H5AC_copy_candidate_list_to_buffer(H5AC_t * cache_ptr,
2963 int * num_entries_ptr,
2964 haddr_t ** haddr_buf_ptr_ptr,
2965 size_t * MPI_Offset_buf_size_ptr,
2966 MPI_Offset ** MPI_Offset_buf_ptr_ptr)
2967 {
2968 herr_t ret_value = SUCCEED; /* Return value */
2969 hbool_t success = FALSE;
2970 haddr_t addr;
2971 H5AC_aux_t * aux_ptr = NULL;
2972 H5SL_node_t * slist_node_ptr = NULL;
2973 H5AC_slist_entry_t * slist_entry_ptr = NULL;
2974 MPI_Offset * MPI_Offset_buf_ptr = NULL;
2975 haddr_t * haddr_buf_ptr = NULL;
2976 size_t buf_size;
2977 int i = 0;
2978 int num_entries = 0;
2979
2980 FUNC_ENTER_NOAPI(FAIL)
2981
2982 HDassert( cache_ptr != NULL );
2983 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
2984
2985 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
2986
2987 HDassert( aux_ptr != NULL );
2988 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
2989 HDassert( aux_ptr->metadata_write_strategy ==
2990 H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED );
2991 HDassert( aux_ptr->candidate_slist_ptr != NULL );
2992 HDassert( H5SL_count(aux_ptr->candidate_slist_ptr) ==
2993 (size_t)(aux_ptr->candidate_slist_len) );
2994 HDassert( aux_ptr->candidate_slist_len > 0 );
2995 HDassert( num_entries_ptr != NULL );
2996 HDassert( *num_entries_ptr == 0 );
2997 HDassert( haddr_buf_ptr_ptr != NULL );
2998 HDassert( *haddr_buf_ptr_ptr == NULL );
2999
3000 num_entries = aux_ptr->candidate_slist_len;
3001
3002 /* allocate a buffer(s) to store the list of candidate entry
3003 * base addresses in
3004 */
3005 if(MPI_Offset_buf_ptr_ptr != NULL) {
3006 HDassert( MPI_Offset_buf_size_ptr != NULL );
3007
3008 /* allocate a buffer of MPI_Offset */
3009 buf_size = sizeof(MPI_Offset) * (size_t)num_entries;
3010 if(NULL == (MPI_Offset_buf_ptr = (MPI_Offset *)H5MM_malloc(buf_size)))
3011 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for MPI_Offset buffer")
3012 } /* end if */
3013
3014 /* allocate a buffer of haddr_t */
3015 if(NULL == (haddr_buf_ptr = (haddr_t *)H5MM_malloc(sizeof(haddr_t) * (size_t)num_entries)))
3016 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for haddr buffer")
3017
3018 /* now load the entry base addresses into the buffer, emptying the
3019 * candidate entry list in passing
3020 */
3021 while(NULL != (slist_node_ptr = H5SL_first(aux_ptr->candidate_slist_ptr))) {
3022 slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_item(slist_node_ptr);
3023
3024 HDassert(slist_entry_ptr->magic == H5AC__H5AC_SLIST_ENTRY_T_MAGIC);
3025 HDassert( i < num_entries );
3026
3027 addr = slist_entry_ptr->addr;
3028 haddr_buf_ptr[i] = addr;
3029 if(MPI_Offset_buf_ptr != NULL) {
3030 if(H5FD_mpi_haddr_to_MPIOff(addr, &(MPI_Offset_buf_ptr[i])) < 0)
3031 HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert from haddr to MPI off")
3032 } /* end if */
3033
3034 i++;
3035
3036 /* now remove the entry from the cleaned entry list */
3037 if(H5SL_remove(aux_ptr->candidate_slist_ptr, (void *)(&addr)) != slist_entry_ptr)
3038 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, "Can't delete entry from candidate entry slist.")
3039
3040 slist_entry_ptr->magic = 0;
3041 H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
3042 slist_entry_ptr = NULL;
3043
3044 aux_ptr->candidate_slist_len -= 1;
3045
3046 HDassert( aux_ptr->candidate_slist_len >= 0 );
3047 } /* while */
3048 HDassert( aux_ptr->candidate_slist_len == 0 );
3049
3050 success = TRUE;
3051
3052 done:
3053 if(success) {
3054 /* Pass the number of entries and the buffer pointer
3055 * back to the caller.
3056 */
3057 *num_entries_ptr = num_entries;
3058 *haddr_buf_ptr_ptr = haddr_buf_ptr;
3059
3060 if(MPI_Offset_buf_ptr_ptr != NULL) {
3061 HDassert( MPI_Offset_buf_ptr != NULL);
3062 *MPI_Offset_buf_size_ptr = buf_size;
3063 *MPI_Offset_buf_ptr_ptr = MPI_Offset_buf_ptr;
3064 } /* end if */
3065 } /* end if */
3066 else {
3067 if(MPI_Offset_buf_ptr != NULL)
3068 MPI_Offset_buf_ptr = (MPI_Offset *)H5MM_xfree((void *)MPI_Offset_buf_ptr);
3069 if(haddr_buf_ptr != NULL)
3070 haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr);
3071 } /* end else */
3072
3073 FUNC_LEAVE_NOAPI(ret_value)
3074 } /* H5AC_copy_candidate_list_to_buffer() */
3075 #endif /* H5_HAVE_PARALLEL */
3076
3077
3078 /*-------------------------------------------------------------------------
3079 * Function: H5AC_ext_config_2_int_config()
3080 *
3081 * Purpose: Utility function to translate an instance of
3082 * H5AC_cache_config_t to an instance of H5C_auto_size_ctl_t.
3083 *
3084 * Places translation in *int_conf_ptr and returns SUCCEED
3085 * if successful. Returns FAIL on failure.
3086 *
3087 * Does only minimal sanity checking.
3088 *
3089 * Return: Non-negative on success/Negative on failure
3090 *
3091 * Programmer: John Mainzer
3092 * 1/26/06
3093 *
3094 *-------------------------------------------------------------------------
3095 */
3096 herr_t
H5AC_ext_config_2_int_config(H5AC_cache_config_t * ext_conf_ptr,H5C_auto_size_ctl_t * int_conf_ptr)3097 H5AC_ext_config_2_int_config(H5AC_cache_config_t * ext_conf_ptr,
3098 H5C_auto_size_ctl_t * int_conf_ptr)
3099 {
3100 herr_t ret_value = SUCCEED; /* Return value */
3101
3102 FUNC_ENTER_NOAPI(FAIL)
3103
3104 if ( ( ext_conf_ptr == NULL ) ||
3105 ( ext_conf_ptr->version != H5AC__CURR_CACHE_CONFIG_VERSION ) ||
3106 ( int_conf_ptr == NULL ) ) {
3107 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
3108 "Bad ext_conf_ptr or inf_conf_ptr on entry.")
3109 }
3110
3111 int_conf_ptr->version = H5C__CURR_AUTO_SIZE_CTL_VER;
3112
3113 if ( ext_conf_ptr->rpt_fcn_enabled ) {
3114
3115 int_conf_ptr->rpt_fcn = H5C_def_auto_resize_rpt_fcn;
3116
3117 } else {
3118
3119 int_conf_ptr->rpt_fcn = NULL;
3120 }
3121
3122 int_conf_ptr->set_initial_size = ext_conf_ptr->set_initial_size;
3123 int_conf_ptr->initial_size = ext_conf_ptr->initial_size;
3124 int_conf_ptr->min_clean_fraction = ext_conf_ptr->min_clean_fraction;
3125 int_conf_ptr->max_size = ext_conf_ptr->max_size;
3126 int_conf_ptr->min_size = ext_conf_ptr->min_size;
3127 int_conf_ptr->epoch_length = (int64_t)(ext_conf_ptr->epoch_length);
3128
3129 int_conf_ptr->incr_mode = ext_conf_ptr->incr_mode;
3130 int_conf_ptr->lower_hr_threshold = ext_conf_ptr->lower_hr_threshold;
3131 int_conf_ptr->increment = ext_conf_ptr->increment;
3132 int_conf_ptr->apply_max_increment = ext_conf_ptr->apply_max_increment;
3133 int_conf_ptr->max_increment = ext_conf_ptr->max_increment;
3134 int_conf_ptr->flash_incr_mode = ext_conf_ptr->flash_incr_mode;
3135 int_conf_ptr->flash_multiple = ext_conf_ptr->flash_multiple;
3136 int_conf_ptr->flash_threshold = ext_conf_ptr->flash_threshold;
3137
3138 int_conf_ptr->decr_mode = ext_conf_ptr->decr_mode;
3139 int_conf_ptr->upper_hr_threshold = ext_conf_ptr->upper_hr_threshold;
3140 int_conf_ptr->decrement = ext_conf_ptr->decrement;
3141 int_conf_ptr->apply_max_decrement = ext_conf_ptr->apply_max_decrement;
3142 int_conf_ptr->max_decrement = ext_conf_ptr->max_decrement;
3143 int_conf_ptr->epochs_before_eviction = (int32_t)(ext_conf_ptr->epochs_before_eviction);
3144 int_conf_ptr->apply_empty_reserve = ext_conf_ptr->apply_empty_reserve;
3145 int_conf_ptr->empty_reserve = ext_conf_ptr->empty_reserve;
3146
3147 done:
3148 FUNC_LEAVE_NOAPI(ret_value)
3149 } /* H5AC_ext_config_2_int_config() */
3150
3151
3152 /*-------------------------------------------------------------------------
3153 *
3154 * Function: H5AC_log_deleted_entry()
3155 *
3156 * Purpose: Log an entry for which H5C__DELETED_FLAG has been set.
3157 *
3158 * If mpi_rank is 0, we must make sure that the entry doesn't
3159 * appear in the cleaned or dirty entry lists. Otherwise,
3160 * we have nothing to do.
3161 *
3162 * Return SUCCEED on success, and FAIL on failure.
3163 *
3164 * Return: Non-negative on success/Negative on failure.
3165 *
3166 * Programmer: John Mainzer, 6/29/05
3167 *
3168 *-------------------------------------------------------------------------
3169 */
3170 #ifdef H5_HAVE_PARALLEL
3171 static herr_t
H5AC_log_deleted_entry(H5AC_t * cache_ptr,H5AC_info_t * entry_ptr,haddr_t addr,unsigned int flags)3172 H5AC_log_deleted_entry(H5AC_t * cache_ptr,
3173 H5AC_info_t * entry_ptr,
3174 haddr_t addr,
3175 unsigned int flags)
3176 {
3177 H5AC_aux_t * aux_ptr;
3178 H5AC_slist_entry_t * slist_entry_ptr = NULL;
3179 herr_t ret_value = SUCCEED; /* Return value */
3180
3181 FUNC_ENTER_NOAPI(FAIL)
3182
3183 HDassert( cache_ptr != NULL );
3184 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
3185
3186 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
3187
3188 HDassert( aux_ptr != NULL );
3189 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
3190
3191 HDassert( entry_ptr != NULL );
3192 HDassert( entry_ptr->addr == addr );
3193
3194 HDassert( (flags & H5C__DELETED_FLAG) != 0 );
3195
3196 if(aux_ptr->mpi_rank == 0) {
3197 HDassert( aux_ptr->d_slist_ptr != NULL );
3198 HDassert( aux_ptr->c_slist_ptr != NULL );
3199
3200 /* if the entry appears in the dirtied entry slist, remove it. */
3201 if((slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_search(aux_ptr->d_slist_ptr, (void *)(&addr))) != NULL) {
3202 HDassert(slist_entry_ptr->magic == H5AC__H5AC_SLIST_ENTRY_T_MAGIC);
3203 HDassert(slist_entry_ptr->addr == addr);
3204
3205 if(H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&addr)) != slist_entry_ptr)
3206 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, "Can't delete entry from dirty entry slist.")
3207
3208 slist_entry_ptr->magic = 0;
3209 H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
3210 slist_entry_ptr = NULL;
3211
3212 aux_ptr->d_slist_len -= 1;
3213
3214 HDassert( aux_ptr->d_slist_len >= 0 );
3215 } /* end if */
3216
3217 /* if the entry appears in the cleaned entry slist, remove it. */
3218 if((slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_search(aux_ptr->c_slist_ptr, (void *)(&addr))) != NULL) {
3219 HDassert(slist_entry_ptr->magic == H5AC__H5AC_SLIST_ENTRY_T_MAGIC);
3220 HDassert(slist_entry_ptr->addr == addr);
3221
3222 if(H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr)) != slist_entry_ptr)
3223 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, "Can't delete entry from cleaned entry slist.")
3224
3225 slist_entry_ptr->magic = 0;
3226 H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
3227 slist_entry_ptr = NULL;
3228
3229 aux_ptr->c_slist_len -= 1;
3230
3231 HDassert( aux_ptr->c_slist_len >= 0 );
3232 } /* end if */
3233 } /* if */
3234
3235 done:
3236 FUNC_LEAVE_NOAPI(ret_value)
3237 } /* H5AC_log_deleted_entry() */
3238 #endif /* H5_HAVE_PARALLEL */
3239
3240
3241 /*-------------------------------------------------------------------------
3242 *
3243 * Function: H5AC_log_dirtied_entry()
3244 *
3245 * Purpose: Update the dirty_bytes count for a newly dirtied entry.
3246 *
3247 * If mpi_rank isnt 0, this simply means adding the size
3248 * of the entries to the dirty_bytes count.
3249 *
3250 * If mpi_rank is 0, we must first check to see if the entry
3251 * appears in the dirty entries slist. If it is, do nothing.
3252 * If it isn't, add the size to th dirty_bytes count, add the
3253 * entry to the dirty entries slist, and remove it from the
3254 * cleaned list (if it is present there).
3255 *
3256 * Return SUCCEED on success, and FAIL on failure.
3257 *
3258 * Return: Non-negative on success/Negative on failure.
3259 *
3260 * Programmer: John Mainzer, 6/29/05
3261 *
3262 *-------------------------------------------------------------------------
3263 */
3264 #ifdef H5_HAVE_PARALLEL
3265 static herr_t
H5AC_log_dirtied_entry(const H5AC_info_t * entry_ptr,haddr_t addr)3266 H5AC_log_dirtied_entry(const H5AC_info_t * entry_ptr,
3267 haddr_t addr)
3268 {
3269 H5AC_t * cache_ptr;
3270 H5AC_aux_t * aux_ptr;
3271 herr_t ret_value = SUCCEED; /* Return value */
3272
3273 FUNC_ENTER_NOAPI(FAIL)
3274
3275 HDassert( entry_ptr );
3276 HDassert( entry_ptr->addr == addr );
3277 HDassert( entry_ptr->is_dirty == FALSE );
3278
3279 cache_ptr = entry_ptr->cache_ptr;
3280
3281 HDassert( cache_ptr != NULL );
3282 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
3283
3284 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
3285
3286 HDassert( aux_ptr != NULL );
3287 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
3288
3289 if ( aux_ptr->mpi_rank == 0 ) {
3290 H5AC_slist_entry_t * slist_entry_ptr;
3291
3292 HDassert( aux_ptr->d_slist_ptr != NULL );
3293 HDassert( aux_ptr->c_slist_ptr != NULL );
3294
3295 if ( H5SL_search(aux_ptr->d_slist_ptr, (void *)(&addr)) == NULL ) {
3296
3297 /* insert the address of the entry in the dirty entry list, and
3298 * add its size to the dirty_bytes count.
3299 */
3300 if ( NULL == (slist_entry_ptr = H5FL_CALLOC(H5AC_slist_entry_t)) ) {
3301
3302 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \
3303 "Can't allocate dirty slist entry .")
3304 }
3305
3306 slist_entry_ptr->magic = H5AC__H5AC_SLIST_ENTRY_T_MAGIC;
3307 slist_entry_ptr->addr = addr;
3308
3309 if ( H5SL_insert(aux_ptr->d_slist_ptr, slist_entry_ptr,
3310 &(slist_entry_ptr->addr)) < 0 ) {
3311
3312 HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, \
3313 "can't insert entry into dirty entry slist.")
3314 }
3315
3316 aux_ptr->d_slist_len += 1;
3317 aux_ptr->dirty_bytes += entry_ptr->size;
3318 #if H5AC_DEBUG_DIRTY_BYTES_CREATION
3319 aux_ptr->unprotect_dirty_bytes += entry_ptr->size;
3320 aux_ptr->unprotect_dirty_bytes_updates += 1;
3321 #endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
3322 }
3323
3324 if(H5SL_search(aux_ptr->c_slist_ptr, (void *)(&addr)) != NULL) {
3325 /* the entry is dirty. If it exists on the cleaned entries list,
3326 * remove it.
3327 */
3328 if((slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_search(aux_ptr->c_slist_ptr, (void *)(&addr))) != NULL) {
3329 HDassert(slist_entry_ptr->magic == H5AC__H5AC_SLIST_ENTRY_T_MAGIC);
3330 HDassert(slist_entry_ptr->addr == addr);
3331
3332 if(H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr)) != slist_entry_ptr)
3333 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, "Can't delete entry from clean entry slist.")
3334
3335 slist_entry_ptr->magic = 0;
3336 H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
3337 slist_entry_ptr = NULL;
3338
3339 aux_ptr->c_slist_len -= 1;
3340
3341 HDassert( aux_ptr->c_slist_len >= 0 );
3342 } /* end if */
3343 } /* end if */
3344 } else {
3345
3346 aux_ptr->dirty_bytes += entry_ptr->size;
3347 #if H5AC_DEBUG_DIRTY_BYTES_CREATION
3348 aux_ptr->unprotect_dirty_bytes += entry_size;
3349 aux_ptr->unprotect_dirty_bytes_updates += 1;
3350 #endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
3351 }
3352
3353 done:
3354
3355 FUNC_LEAVE_NOAPI(ret_value)
3356
3357 } /* H5AC_log_dirtied_entry() */
3358 #endif /* H5_HAVE_PARALLEL */
3359
3360
3361 /*-------------------------------------------------------------------------
3362 *
3363 * Function: H5AC_log_flushed_entry()
3364 *
3365 * Purpose: Update the clean entry slist for the flush of an entry --
3366 * specifically, if the entry has been cleared, remove it
3367 * from both the cleaned and dirtied lists if it is present.
3368 * Otherwise, if the entry was dirty, insert the indicated
3369 * entry address in the clean slist if it isn't there already.
3370 *
3371 * This function is only used in PHDF5, and should only
3372 * be called for the process with mpi rank 0.
3373 *
3374 * Return SUCCEED on success, and FAIL on failure.
3375 *
3376 * Return: Non-negative on success/Negative on failure.
3377 *
3378 * Programmer: John Mainzer, 6/29/05
3379 *
3380 *-------------------------------------------------------------------------
3381 */
3382 #ifdef H5_HAVE_PARALLEL
3383 static herr_t
H5AC_log_flushed_entry(H5C_t * cache_ptr,haddr_t addr,hbool_t was_dirty,unsigned flags,int UNUSED type_id)3384 H5AC_log_flushed_entry(H5C_t * cache_ptr,
3385 haddr_t addr,
3386 hbool_t was_dirty,
3387 unsigned flags,
3388 int UNUSED type_id)
3389 {
3390 herr_t ret_value = SUCCEED; /* Return value */
3391 hbool_t cleared;
3392 H5AC_aux_t * aux_ptr;
3393 H5AC_slist_entry_t * slist_entry_ptr = NULL;
3394
3395
3396 FUNC_ENTER_NOAPI(FAIL)
3397
3398 HDassert( cache_ptr != NULL );
3399 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
3400
3401 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
3402
3403 HDassert( aux_ptr != NULL );
3404 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
3405 HDassert( aux_ptr->mpi_rank == 0 );
3406 HDassert( aux_ptr->c_slist_ptr != NULL );
3407
3408 cleared = ( (flags & H5C__FLUSH_CLEAR_ONLY_FLAG) != 0 );
3409
3410 if ( cleared ) {
3411
3412 /* If the entry has been cleared, must remove it from both the
3413 * cleaned list and the dirtied list.
3414 */
3415
3416 if ( (slist_entry_ptr = (H5AC_slist_entry_t *)
3417 H5SL_search(aux_ptr->c_slist_ptr,
3418 (void *)(&addr))) != NULL ) {
3419
3420 HDassert( slist_entry_ptr->magic == H5AC__H5AC_SLIST_ENTRY_T_MAGIC);
3421 HDassert( slist_entry_ptr->addr == addr );
3422
3423 if ( H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr))
3424 != slist_entry_ptr ) {
3425
3426 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \
3427 "Can't delete entry from clean entry slist.")
3428 }
3429
3430 slist_entry_ptr->magic = 0;
3431 H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
3432 slist_entry_ptr = NULL;
3433
3434 aux_ptr->c_slist_len -= 1;
3435
3436 HDassert( aux_ptr->c_slist_len >= 0 );
3437 }
3438
3439 if ( (slist_entry_ptr = (H5AC_slist_entry_t *)
3440 H5SL_search(aux_ptr->d_slist_ptr, (void *)(&addr))) != NULL ) {
3441
3442 HDassert( slist_entry_ptr->magic == H5AC__H5AC_SLIST_ENTRY_T_MAGIC);
3443 HDassert( slist_entry_ptr->addr == addr );
3444
3445 if ( H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&addr))
3446 != slist_entry_ptr ) {
3447
3448 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \
3449 "Can't delete entry from dirty entry slist.")
3450 }
3451
3452 slist_entry_ptr->magic = 0;
3453 H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
3454 slist_entry_ptr = NULL;
3455
3456 aux_ptr->d_slist_len -= 1;
3457
3458 HDassert( aux_ptr->d_slist_len >= 0 );
3459 }
3460 } else if ( was_dirty ) {
3461
3462 if ( H5SL_search(aux_ptr->c_slist_ptr, (void *)(&addr)) == NULL ) {
3463
3464 /* insert the address of the entry in the clean entry list. */
3465
3466 if ( NULL == (slist_entry_ptr = H5FL_CALLOC(H5AC_slist_entry_t)) ) {
3467
3468 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \
3469 "Can't allocate clean slist entry .")
3470 }
3471
3472 slist_entry_ptr->magic = H5AC__H5AC_SLIST_ENTRY_T_MAGIC;
3473 slist_entry_ptr->addr = addr;
3474
3475 if ( H5SL_insert(aux_ptr->c_slist_ptr, slist_entry_ptr,
3476 &(slist_entry_ptr->addr)) < 0 ) {
3477
3478 HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, \
3479 "can't insert entry into clean entry slist.")
3480 }
3481
3482 aux_ptr->c_slist_len += 1;
3483 }
3484 }
3485
3486 done:
3487
3488 FUNC_LEAVE_NOAPI(ret_value)
3489
3490 } /* H5AC_log_flushed_entry() */
3491 #endif /* H5_HAVE_PARALLEL */
3492
3493
3494 /*-------------------------------------------------------------------------
3495 *
3496 * Function: H5AC_log_inserted_entry()
3497 *
3498 * Purpose: Update the dirty_bytes count for a newly inserted entry.
3499 *
3500 * If mpi_rank isnt 0, this simply means adding the size
3501 * of the entry to the dirty_bytes count.
3502 *
3503 * If mpi_rank is 0, we must also add the entry to the
3504 * dirty entries slist.
3505 *
3506 * Return SUCCEED on success, and FAIL on failure.
3507 *
3508 * Return: Non-negative on success/Negative on failure.
3509 *
3510 * Programmer: John Mainzer, 6/30/05
3511 *
3512 *-------------------------------------------------------------------------
3513 */
3514 #ifdef H5_HAVE_PARALLEL
3515 static herr_t
H5AC_log_inserted_entry(H5F_t * f,H5AC_t * cache_ptr,H5AC_info_t * entry_ptr)3516 H5AC_log_inserted_entry(H5F_t * f,
3517 H5AC_t * cache_ptr,
3518 H5AC_info_t * entry_ptr)
3519 {
3520 H5AC_aux_t * aux_ptr;
3521 herr_t ret_value = SUCCEED; /* Return value */
3522
3523 FUNC_ENTER_NOAPI(FAIL)
3524
3525 HDassert(cache_ptr != NULL);
3526 HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
3527
3528 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
3529
3530 HDassert(aux_ptr != NULL);
3531 HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
3532
3533 HDassert( entry_ptr != NULL );
3534
3535 if(aux_ptr->mpi_rank == 0) {
3536 H5AC_slist_entry_t * slist_entry_ptr;
3537
3538 HDassert(aux_ptr->d_slist_ptr != NULL);
3539 HDassert(aux_ptr->c_slist_ptr != NULL);
3540
3541 if(NULL != H5SL_search(aux_ptr->d_slist_ptr, (void *)(&entry_ptr->addr)))
3542 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Inserted entry already in dirty slist.")
3543
3544 /* insert the address of the entry in the dirty entry list, and
3545 * add its size to the dirty_bytes count.
3546 */
3547 if(NULL == (slist_entry_ptr = H5FL_CALLOC(H5AC_slist_entry_t)))
3548 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "Can't allocate dirty slist entry .")
3549
3550 slist_entry_ptr->magic = H5AC__H5AC_SLIST_ENTRY_T_MAGIC;
3551 slist_entry_ptr->addr = entry_ptr->addr;
3552
3553 if(H5SL_insert(aux_ptr->d_slist_ptr, slist_entry_ptr, &(slist_entry_ptr->addr)) < 0 )
3554 HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, "can't insert entry into dirty entry slist.")
3555
3556 aux_ptr->d_slist_len += 1;
3557
3558 if(NULL != H5SL_search(aux_ptr->c_slist_ptr, (void *)(&entry_ptr->addr)))
3559 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Inserted entry in clean slist.")
3560 } /* end if */
3561
3562 aux_ptr->dirty_bytes += entry_ptr->size;
3563
3564 #if H5AC_DEBUG_DIRTY_BYTES_CREATION
3565 aux_ptr->insert_dirty_bytes += size;
3566 aux_ptr->insert_dirty_bytes_updates += 1;
3567 #endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
3568
3569 done:
3570 FUNC_LEAVE_NOAPI(ret_value)
3571 } /* H5AC_log_inserted_entry() */
3572 #endif /* H5_HAVE_PARALLEL */
3573
3574
3575 /*-------------------------------------------------------------------------
3576 *
3577 * Function: H5AC_log_moved_entry()
3578 *
3579 * Purpose: Update the dirty_bytes count for a moved entry.
3580 *
3581 * WARNING
3582 *
3583 * At present, the way that the move call is used ensures
3584 * that the moved entry is present in all caches by
3585 * moving in a collective operation and immediately after
3586 * unprotecting the target entry.
3587 *
3588 * This function uses this invarient, and will cause arcane
3589 * failures if it is not met. If maintaining this invarient
3590 * becomes impossible, we will have to rework this function
3591 * extensively, and likely include a bit of IPC for
3592 * synchronization. A better option might be to subsume
3593 * move in the unprotect operation.
3594 *
3595 * Given that the target entry is in all caches, the function
3596 * proceeds as follows:
3597 *
3598 * For processes with mpi rank other 0, it simply checks to
3599 * see if the entry was dirty prior to the move, and adds
3600 * the entries size to the dirty bytes count.
3601 *
3602 * In the process with mpi rank 0, the function first checks
3603 * to see if the entry was dirty prior to the move. If it
3604 * was, and if the entry doesn't appear in the dirtied list
3605 * under its old address, it adds the entry's size to the
3606 * dirty bytes count.
3607 *
3608 * The rank 0 process then removes any references to the
3609 * entry under its old address from the cleands and dirtied
3610 * lists, and inserts an entry in the dirtied list under the
3611 * new address.
3612 *
3613 * Return SUCCEED on success, and FAIL on failure.
3614 *
3615 * Return: Non-negative on success/Negative on failure.
3616 *
3617 * Programmer: John Mainzer, 6/30/05
3618 *
3619 *-------------------------------------------------------------------------
3620 */
3621 #ifdef H5_HAVE_PARALLEL
3622 static herr_t
H5AC_log_moved_entry(const H5F_t * f,haddr_t old_addr,haddr_t new_addr)3623 H5AC_log_moved_entry(const H5F_t *f,
3624 haddr_t old_addr,
3625 haddr_t new_addr)
3626 {
3627 H5AC_t * cache_ptr;
3628 hbool_t entry_in_cache;
3629 hbool_t entry_dirty;
3630 size_t entry_size;
3631 H5AC_aux_t * aux_ptr = NULL;
3632 H5AC_slist_entry_t * slist_entry_ptr = NULL;
3633 herr_t ret_value = SUCCEED; /* Return value */
3634
3635 FUNC_ENTER_NOAPI(FAIL)
3636
3637 HDassert( f );
3638 HDassert( f->shared );
3639
3640 cache_ptr = (H5AC_t *)f->shared->cache;
3641
3642 HDassert( cache_ptr );
3643 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
3644
3645 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
3646
3647 HDassert( aux_ptr != NULL );
3648 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
3649
3650 /* get entry status, size, etc here */
3651 if ( H5C_get_entry_status(f, old_addr, &entry_size, &entry_in_cache,
3652 &entry_dirty, NULL, NULL) < 0 ) {
3653
3654 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't get entry status.")
3655
3656 } else if ( ! entry_in_cache ) {
3657
3658 HDassert( entry_in_cache );
3659 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "entry not in cache.")
3660 }
3661
3662 if ( aux_ptr->mpi_rank == 0 ) {
3663
3664 HDassert( aux_ptr->d_slist_ptr != NULL );
3665 HDassert( aux_ptr->c_slist_ptr != NULL );
3666
3667 /* if the entry appears in the cleaned entry slist, under its old
3668 * address, remove it.
3669 */
3670 if ( (slist_entry_ptr = (H5AC_slist_entry_t *)
3671 H5SL_search(aux_ptr->c_slist_ptr, (void *)(&old_addr))) != NULL ) {
3672
3673 HDassert( slist_entry_ptr->magic ==
3674 H5AC__H5AC_SLIST_ENTRY_T_MAGIC );
3675 HDassert( slist_entry_ptr->addr == old_addr );
3676
3677 if ( H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&old_addr))
3678 != slist_entry_ptr ) {
3679
3680 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \
3681 "Can't delete entry from cleaned entry slist.")
3682 }
3683
3684 slist_entry_ptr->magic = 0;
3685 H5FL_FREE(H5AC_slist_entry_t, slist_entry_ptr);
3686 slist_entry_ptr = NULL;
3687
3688 aux_ptr->c_slist_len -= 1;
3689
3690 HDassert( aux_ptr->c_slist_len >= 0 );
3691 }
3692
3693 /* if the entry appears in the dirtied entry slist under its old
3694 * address, remove it, but don't free it. Set addr to new_addr.
3695 */
3696 if ( (slist_entry_ptr = (H5AC_slist_entry_t *)
3697 H5SL_search(aux_ptr->d_slist_ptr, (void *)(&old_addr))) != NULL ) {
3698
3699 HDassert( slist_entry_ptr->magic ==
3700 H5AC__H5AC_SLIST_ENTRY_T_MAGIC );
3701 HDassert( slist_entry_ptr->addr == old_addr );
3702
3703 if ( H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&old_addr))
3704 != slist_entry_ptr ) {
3705
3706 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \
3707 "Can't delete entry from dirty entry slist.")
3708 }
3709
3710 slist_entry_ptr->addr = new_addr;
3711
3712 aux_ptr->d_slist_len -= 1;
3713
3714 HDassert( aux_ptr->d_slist_len >= 0 );
3715
3716 } else {
3717
3718 /* otherwise, allocate a new entry that is ready
3719 * for insertion, and increment dirty_bytes.
3720 *
3721 * Note that the fact that the entry wasn't in the dirtied
3722 * list under its old address implies that it must have
3723 * been clean to start with.
3724 */
3725
3726 HDassert( !entry_dirty );
3727
3728 if ( NULL == (slist_entry_ptr = H5FL_CALLOC(H5AC_slist_entry_t)) ) {
3729
3730 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \
3731 "Can't allocate dirty slist entry .")
3732 }
3733
3734 slist_entry_ptr->magic = H5AC__H5AC_SLIST_ENTRY_T_MAGIC;
3735 slist_entry_ptr->addr = new_addr;
3736
3737 aux_ptr->dirty_bytes += entry_size;
3738
3739 #if H5AC_DEBUG_DIRTY_BYTES_CREATION
3740 aux_ptr->move_dirty_bytes += entry_size;
3741 aux_ptr->move_dirty_bytes_updates += 1;
3742 #endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
3743 }
3744
3745 /* verify that there is no entry at new_addr in the dirty slist */
3746 if ( H5SL_search(aux_ptr->d_slist_ptr, (void *)(&new_addr)) != NULL ) {
3747
3748 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \
3749 "dirty slist already contains entry at new_addr.")
3750 }
3751
3752 /* insert / reinsert the entry in the dirty slist */
3753 if ( H5SL_insert(aux_ptr->d_slist_ptr, slist_entry_ptr,
3754 &(slist_entry_ptr->addr)) < 0 ) {
3755
3756 HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, \
3757 "can't insert entry into dirty entry slist.")
3758 }
3759
3760 aux_ptr->d_slist_len += 1;
3761
3762 } else if ( ! entry_dirty ) {
3763
3764 aux_ptr->dirty_bytes += entry_size;
3765
3766 #if H5AC_DEBUG_DIRTY_BYTES_CREATION
3767 aux_ptr->move_dirty_bytes += entry_size;
3768 aux_ptr->move_dirty_bytes_updates += 1;
3769 #endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
3770 }
3771
3772 done:
3773 FUNC_LEAVE_NOAPI(ret_value)
3774 } /* H5AC_log_moved_entry() */
3775 #endif /* H5_HAVE_PARALLEL */
3776
3777
3778 /*-------------------------------------------------------------------------
3779 * Function: H5AC_propagate_and_apply_candidate_list
3780 *
3781 * Purpose: Prior to the addition of support for multiple metadata
3782 * write strategies, in PHDF5, only the metadata cache with
3783 * mpi rank 0 was allowed to write to file. All other
3784 * metadata caches on processes with rank greater than 0
3785 * were required to retain dirty entries until they were
3786 * notified that the entry was clean.
3787 *
3788 * This constraint is relaxed with the distributed
3789 * metadata write strategy, in which a list of candidate
3790 * metadata cache entries is constructed by the process 0
3791 * cache and then distributed to the caches of all the other
3792 * processes. Once the listed is distributed, many (if not
3793 * all) processes writing writing a unique subset of the
3794 * entries, and marking the remainder clean. The subsets
3795 * are chosen so that each entry in the list of candidates
3796 * is written by exactly one cache, and all entries are
3797 * marked as being clean in all caches.
3798 *
3799 * While the list of candidate cache entries is prepared
3800 * elsewhere, this function is the main routine for distributing
3801 * and applying the list. It must be run simultaniously on
3802 * all processes that have the relevant file open. To ensure
3803 * proper synchronization, there is a barrier at the beginning
3804 * of this function.
3805 *
3806 * At present, this function is called under one of two
3807 * circumstances:
3808 *
3809 * 1) Dirty byte creation exceeds some user specified value.
3810 *
3811 * While metadata reads may occur independently, all
3812 * operations writing metadata must be collective. Thus
3813 * all metadata caches see the same sequence of operations,
3814 * and therefore the same dirty data creation.
3815 *
3816 * This fact is used to synchronize the caches for purposes
3817 * of propagating the list of candidate entries, by simply
3818 * calling this function from all caches whenever some user
3819 * specified threshold on dirty data is exceeded. (the
3820 * process 0 cache creates the candidate list just before
3821 * calling this function).
3822 *
3823 * 2) Under direct user control -- this operation must be
3824 * collective.
3825 *
3826 * The operations to be managed by this function are as
3827 * follows:
3828 *
3829 * All processes:
3830 *
3831 * 1) Participate in an opening barrier.
3832 *
3833 * For the process with mpi rank 0:
3834 *
3835 * 1) Load the contents of the candidate list
3836 * (candidate_slist_ptr) into a buffer, and broadcast that
3837 * buffer to all the other caches. Clear the candidate
3838 * list in passing.
3839 *
3840 * If there is a positive number of candidates, proceed with
3841 * the following:
3842 *
3843 * 2) Apply the candidate entry list.
3844 *
3845 * 3) Particpate in a closing barrier.
3846 *
3847 * 4) Remove from the dirty list (d_slist_ptr) and from the
3848 * flushed and still clean entries list (c_slist_ptr),
3849 * all addresses that appeared in the candidate list, as
3850 * these entries are now clean.
3851 *
3852 *
3853 * For all processes with mpi rank greater than 0:
3854 *
3855 * 1) Receive the candidate entry list broadcast
3856 *
3857 * If there is a positive number of candidates, proceed with
3858 * the following:
3859 *
3860 * 2) Apply the candidate entry list.
3861 *
3862 * 3) Particpate in a closing barrier.
3863 *
3864 * Return: Success: non-negative
3865 *
3866 * Failure: negative
3867 *
3868 * Programmer: John Mainzer
3869 * 3/17/10
3870 *
3871 *-------------------------------------------------------------------------
3872 */
3873 #ifdef H5_HAVE_PARALLEL
3874 static herr_t
H5AC_propagate_and_apply_candidate_list(H5F_t * f,hid_t dxpl_id,H5AC_t * cache_ptr)3875 H5AC_propagate_and_apply_candidate_list(H5F_t * f,
3876 hid_t dxpl_id,
3877 H5AC_t * cache_ptr)
3878 {
3879 int mpi_code;
3880 int num_candidates = 0;
3881 haddr_t * candidates_list_ptr = NULL;
3882 H5AC_aux_t * aux_ptr;
3883 herr_t ret_value = SUCCEED; /* Return value */
3884
3885 FUNC_ENTER_NOAPI(FAIL)
3886
3887 HDassert( cache_ptr != NULL );
3888 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
3889
3890 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
3891
3892 HDassert( aux_ptr != NULL );
3893 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
3894 HDassert( aux_ptr->metadata_write_strategy ==
3895 H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED );
3896
3897 /* to prevent "messages from the future" we must synchronize all
3898 * processes before we write any entries.
3899 */
3900 if(MPI_SUCCESS != (mpi_code = MPI_Barrier(aux_ptr->mpi_comm)))
3901 HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed 1", mpi_code)
3902
3903 if(aux_ptr->mpi_rank == 0) {
3904 if(H5AC_broadcast_candidate_list(cache_ptr, &num_candidates, &candidates_list_ptr) < 0)
3905 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't broadcast candidate slist.")
3906
3907 HDassert( aux_ptr->candidate_slist_len == 0 );
3908 } /* end if */
3909 else {
3910 if(H5AC_receive_candidate_list(cache_ptr, &num_candidates, &candidates_list_ptr) < 0)
3911 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't receive candidate broadcast.")
3912 } /* end else */
3913
3914 if(num_candidates > 0) {
3915 herr_t result;
3916
3917 /* all processes apply the candidate list.
3918 * H5C_apply_candidate_list() handles the details of
3919 * distributing the writes across the processes.
3920 */
3921
3922 aux_ptr->write_permitted = TRUE;
3923
3924 result = H5C_apply_candidate_list(f,
3925 dxpl_id,
3926 dxpl_id,
3927 cache_ptr,
3928 num_candidates,
3929 candidates_list_ptr,
3930 aux_ptr->mpi_rank,
3931 aux_ptr->mpi_size);
3932
3933 aux_ptr->write_permitted = FALSE;
3934
3935 if(result < 0)
3936 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't apply candidate list.")
3937
3938 if(aux_ptr->write_done != NULL)
3939 (aux_ptr->write_done)();
3940
3941 /* to prevent "messages from the past" we must synchronize all
3942 * processes again before we go on.
3943 */
3944 if(MPI_SUCCESS != (mpi_code = MPI_Barrier(aux_ptr->mpi_comm)))
3945 HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed 2", mpi_code)
3946
3947 if(aux_ptr->mpi_rank == 0) {
3948 if(H5AC_tidy_cache_0_lists(cache_ptr, num_candidates, candidates_list_ptr) < 0)
3949 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't tidy up process 0 lists.")
3950 } /* end if */
3951 } /* end if */
3952
3953 /* if it is defined, call the sync point done callback. Note
3954 * that this callback is defined purely for testing purposes,
3955 * and should be undefined under normal operating circumstances.
3956 */
3957 if(aux_ptr->sync_point_done != NULL)
3958 (aux_ptr->sync_point_done)(num_candidates, candidates_list_ptr);
3959
3960 done:
3961 if(candidates_list_ptr != NULL)
3962 candidates_list_ptr = (haddr_t *)H5MM_xfree((void *)candidates_list_ptr);
3963
3964 FUNC_LEAVE_NOAPI(ret_value)
3965 } /* H5AC_propagate_and_apply_candidate_list() */
3966 #endif /* H5_HAVE_PARALLEL */
3967
3968
3969 /*-------------------------------------------------------------------------
3970 * Function: H5AC_propagate_flushed_and_still_clean_entries_list
3971 *
3972 * Purpose: In PHDF5, if the process 0 only metadata write strategy
3973 * is selected, only the metadata cache with mpi rank 0 is
3974 * allowed to write to file. All other metadata caches on
3975 * processes with rank greater than 0 must retain dirty
3976 * entries until they are notified that the entry is now
3977 * clean.
3978 *
3979 * This function is the main routine for handling this
3980 * notification proceedure. It must be called
3981 * simultaniously on all processes that have the relevant
3982 * file open. To this end, it is called only during a
3983 * sync point, with a barrier prior to the call.
3984 *
3985 * Note that any metadata entry writes by process 0 will
3986 * occur after the barrier and just before this call.
3987 *
3988 * Typicaly, calls to this function will be triggered in
3989 * one of two ways:
3990 *
3991 * 1) Dirty byte creation exceeds some user specified value.
3992 *
3993 * While metadata reads may occur independently, all
3994 * operations writing metadata must be collective. Thus
3995 * all metadata caches see the same sequence of operations,
3996 * and therefore the same dirty data creation.
3997 *
3998 * This fact is used to synchronize the caches for purposes
3999 * of propagating the list of flushed and still clean
4000 * entries, by simply calling this function from all
4001 * caches whenever some user specified threshold on dirty
4002 * data is exceeded.
4003 *
4004 * 2) Under direct user control -- this operation must be
4005 * collective.
4006 *
4007 * The operations to be managed by this function are as
4008 * follows:
4009 *
4010 * For the process with mpi rank 0:
4011 *
4012 * 1) Load the contents of the flushed and still clean entries
4013 * list (c_slist_ptr) into a buffer, and broadcast that
4014 * buffer to all the other caches.
4015 *
4016 * 2) Clear the flushed and still clean entries list
4017 * (c_slist_ptr).
4018 *
4019 *
4020 * For all processes with mpi rank greater than 0:
4021 *
4022 * 1) Receive the flushed and still clean entries list broadcast
4023 *
4024 * 2) Mark the specified entries as clean.
4025 *
4026 *
4027 * For all processes:
4028 *
4029 * 1) Reset the dirtied bytes count to 0.
4030 *
4031 * Return: Success: non-negative
4032 *
4033 * Failure: negative
4034 *
4035 * Programmer: John Mainzer
4036 * July 5, 2005
4037 *
4038 *-------------------------------------------------------------------------
4039 */
4040 #ifdef H5_HAVE_PARALLEL
4041 herr_t
H5AC_propagate_flushed_and_still_clean_entries_list(H5F_t * f,hid_t dxpl_id,H5AC_t * cache_ptr)4042 H5AC_propagate_flushed_and_still_clean_entries_list(H5F_t * f,
4043 hid_t dxpl_id,
4044 H5AC_t * cache_ptr)
4045 {
4046 H5AC_aux_t * aux_ptr;
4047 herr_t ret_value = SUCCEED; /* Return value */
4048
4049 FUNC_ENTER_NOAPI(FAIL)
4050
4051 HDassert(cache_ptr != NULL);
4052 HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC);
4053
4054 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
4055
4056 HDassert(aux_ptr != NULL);
4057 HDassert(aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC);
4058 HDassert(aux_ptr->metadata_write_strategy ==
4059 H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY);
4060
4061 if(aux_ptr->mpi_rank == 0) {
4062 if(H5AC_broadcast_clean_list(cache_ptr) < 0)
4063 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't broadcast clean slist.")
4064 HDassert( aux_ptr->c_slist_len == 0 );
4065 } /* end if */
4066 else {
4067 if(H5AC_receive_and_apply_clean_list(f, dxpl_id, H5AC_noblock_dxpl_id, cache_ptr) < 0)
4068 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't receive and/or process clean slist broadcast.")
4069 } /* end else */
4070
4071 done:
4072 FUNC_LEAVE_NOAPI(ret_value)
4073 } /* H5AC_propagate_flushed_and_still_clean_entries_list() */
4074 #endif /* H5_HAVE_PARALLEL */
4075
4076
4077 /*-------------------------------------------------------------------------
4078 *
4079 * Function: H5AC_receive_and_apply_clean_list()
4080 *
4081 * Purpose: Receive the list of cleaned entries from process 0,
4082 * and mark the specified entries as clean.
4083 *
4084 * This function must only be called by the process with
4085 * MPI_rank greater than 0.
4086 *
4087 * Return SUCCEED on success, and FAIL on failure.
4088 *
4089 * Return: Non-negative on success/Negative on failure.
4090 *
4091 * Programmer: John Mainzer, 7/4/05
4092 *
4093 *-------------------------------------------------------------------------
4094 */
4095 #ifdef H5_HAVE_PARALLEL
4096 static herr_t
H5AC_receive_and_apply_clean_list(H5F_t * f,hid_t primary_dxpl_id,hid_t secondary_dxpl_id,H5AC_t * cache_ptr)4097 H5AC_receive_and_apply_clean_list(H5F_t * f,
4098 hid_t primary_dxpl_id,
4099 hid_t secondary_dxpl_id,
4100 H5AC_t * cache_ptr)
4101 {
4102 H5AC_aux_t * aux_ptr;
4103 haddr_t * haddr_buf_ptr = NULL;
4104 MPI_Offset * MPI_Offset_buf_ptr = NULL;
4105 int mpi_result;
4106 int num_entries = 0;
4107 herr_t ret_value = SUCCEED; /* Return value */
4108
4109 FUNC_ENTER_NOAPI(FAIL)
4110
4111 HDassert( f != NULL );
4112 HDassert( f->shared->cache == cache_ptr );
4113
4114 HDassert( cache_ptr != NULL );
4115 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
4116
4117 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
4118
4119 HDassert( aux_ptr != NULL );
4120 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
4121 HDassert( aux_ptr->mpi_rank != 0 );
4122
4123 /* First receive the number of entries in the list so that we
4124 * can set up a buffer to receive them. If there aren't
4125 * any, we are done.
4126 */
4127 if(MPI_SUCCESS != (mpi_result = MPI_Bcast(&num_entries, 1, MPI_INT, 0, aux_ptr->mpi_comm)))
4128 HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 1", mpi_result)
4129
4130 if(num_entries > 0) {
4131 size_t buf_size;
4132 int i;
4133
4134 /* allocate buffers to store the list of entry base addresses in */
4135 buf_size = sizeof(MPI_Offset) * (size_t)num_entries;
4136 if(NULL == (MPI_Offset_buf_ptr = (MPI_Offset *)H5MM_malloc(buf_size)))
4137 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for receive buffer")
4138 if(NULL == (haddr_buf_ptr = (haddr_t *)H5MM_malloc(sizeof(haddr_t) * (size_t)num_entries)))
4139 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for haddr buffer")
4140
4141 /* Now receive the list of cleaned entries
4142 *
4143 * The peculiar structure of the following call to MPI_Bcast is
4144 * due to MPI's (?) failure to believe in the MPI_Offset type.
4145 * Thus the element type is MPI_BYTE, with size equal to the
4146 * buf_size computed above.
4147 */
4148 if(MPI_SUCCESS != (mpi_result = MPI_Bcast((void *)MPI_Offset_buf_ptr, (int)buf_size, MPI_BYTE, 0, aux_ptr->mpi_comm)))
4149 HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 2", mpi_result)
4150
4151 /* translate the MPI_Offsets to haddr_t */
4152 i = 0;
4153 while(i < num_entries) {
4154 haddr_buf_ptr[i] = H5FD_mpi_MPIOff_to_haddr(MPI_Offset_buf_ptr[i]);
4155
4156 if(haddr_buf_ptr[i] == HADDR_UNDEF)
4157 HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert MPI off to haddr")
4158
4159 i++;
4160 } /* end while */
4161
4162 /* mark the indicated entries as clean */
4163 if(H5C_mark_entries_as_clean(f, primary_dxpl_id, secondary_dxpl_id,
4164 (int32_t)num_entries, &(haddr_buf_ptr[0])) < 0)
4165 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't mark entries clean.")
4166 } /* end if */
4167
4168 /* if it is defined, call the sync point done callback. Note
4169 * that this callback is defined purely for testing purposes,
4170 * and should be undefined under normal operating circumstances.
4171 */
4172 if(aux_ptr->sync_point_done != NULL)
4173 (aux_ptr->sync_point_done)(num_entries, haddr_buf_ptr);
4174
4175 done:
4176 if(MPI_Offset_buf_ptr != NULL)
4177 MPI_Offset_buf_ptr = (MPI_Offset *)H5MM_xfree((void *)MPI_Offset_buf_ptr);
4178 if(haddr_buf_ptr != NULL)
4179 haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr);
4180
4181 FUNC_LEAVE_NOAPI(ret_value)
4182 } /* H5AC_receive_and_apply_clean_list() */
4183 #endif /* H5_HAVE_PARALLEL */
4184
4185
4186 /*-------------------------------------------------------------------------
4187 *
4188 * Function: H5AC_receive_candidate_list()
4189 *
4190 * Purpose: Receive the list of candidate entries from process 0,
4191 * and return it in a buffer pointed to by *haddr_buf_ptr_ptr.
4192 * Note that the caller must free this buffer if it is
4193 * returned.
4194 *
4195 * This function must only be called by the process with
4196 * MPI_rank greater than 0.
4197 *
4198 * Return SUCCEED on success, and FAIL on failure.
4199 *
4200 * Return: Non-negative on success/Negative on failure.
4201 *
4202 * Programmer: John Mainzer, 3/17/10
4203 *
4204 *-------------------------------------------------------------------------
4205 */
4206 #ifdef H5_HAVE_PARALLEL
4207 static herr_t
H5AC_receive_candidate_list(H5AC_t * cache_ptr,int * num_entries_ptr,haddr_t ** haddr_buf_ptr_ptr)4208 H5AC_receive_candidate_list(H5AC_t * cache_ptr,
4209 int * num_entries_ptr,
4210 haddr_t ** haddr_buf_ptr_ptr)
4211 {
4212 hbool_t success = FALSE;
4213 H5AC_aux_t * aux_ptr;
4214 haddr_t * haddr_buf_ptr = NULL;
4215 MPI_Offset * MPI_Offset_buf_ptr = NULL;
4216 int mpi_result;
4217 int num_entries;
4218 herr_t ret_value = SUCCEED; /* Return value */
4219
4220 FUNC_ENTER_NOAPI(FAIL)
4221
4222 HDassert( cache_ptr != NULL );
4223 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
4224
4225 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
4226
4227 HDassert( aux_ptr != NULL );
4228 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
4229 HDassert( aux_ptr->mpi_rank != 0 );
4230 HDassert( aux_ptr-> metadata_write_strategy ==
4231 H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED );
4232
4233 HDassert( num_entries_ptr != NULL );
4234 HDassert( *num_entries_ptr == 0 );
4235
4236 HDassert( haddr_buf_ptr_ptr != NULL );
4237 HDassert( *haddr_buf_ptr_ptr == NULL );
4238
4239
4240 /* First receive the number of entries in the list so that we
4241 * can set up a buffer to receive them. If there aren't
4242 * any, we are done.
4243 */
4244 if(MPI_SUCCESS != (mpi_result = MPI_Bcast(&num_entries, 1, MPI_INT, 0, aux_ptr->mpi_comm)))
4245 HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 1", mpi_result)
4246
4247 if(num_entries > 0) {
4248 size_t buf_size;
4249 int i;
4250
4251 /* allocate buffers to store the list of entry base addresses in */
4252 buf_size = sizeof(MPI_Offset) * (size_t)num_entries;
4253
4254 if(NULL == (MPI_Offset_buf_ptr = (MPI_Offset *)H5MM_malloc(buf_size)))
4255 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for receive buffer")
4256 if(NULL == (haddr_buf_ptr = (haddr_t *)H5MM_malloc(sizeof(haddr_t) * (size_t)num_entries)))
4257 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for haddr buffer")
4258
4259 /* Now receive the list of candidate entries
4260 *
4261 * The peculiar structure of the following call to MPI_Bcast is
4262 * due to MPI's (?) failure to believe in the MPI_Offset type.
4263 * Thus the element type is MPI_BYTE, with size equal to the
4264 * buf_size computed above.
4265 */
4266 if(MPI_SUCCESS != (mpi_result = MPI_Bcast((void *)MPI_Offset_buf_ptr, (int)buf_size, MPI_BYTE, 0, aux_ptr->mpi_comm)))
4267 HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 2", mpi_result)
4268
4269 /* translate the MPI_Offsets to haddr_t */
4270 i = 0;
4271 while(i < num_entries) {
4272 haddr_buf_ptr[i] = H5FD_mpi_MPIOff_to_haddr(MPI_Offset_buf_ptr[i]);
4273
4274 if(haddr_buf_ptr[i] == HADDR_UNDEF)
4275 HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, "can't convert MPI off to haddr")
4276
4277 i++;
4278 } /* end while */
4279 } /* end if */
4280
4281 success = TRUE;
4282
4283 done:
4284 if(MPI_Offset_buf_ptr != NULL)
4285 MPI_Offset_buf_ptr = (MPI_Offset *)H5MM_xfree((void *)MPI_Offset_buf_ptr);
4286
4287 if(success) {
4288 /* finally, pass the number of entries and the buffer pointer
4289 * back to the caller. Do this so that we can use the same code
4290 * to apply the candidate list to all the processes.
4291 */
4292 *num_entries_ptr = num_entries;
4293 *haddr_buf_ptr_ptr = haddr_buf_ptr;
4294 } /* end if */
4295 else {
4296 if(haddr_buf_ptr != NULL)
4297 haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr);
4298 } /* end else */
4299
4300 FUNC_LEAVE_NOAPI(ret_value)
4301 } /* H5AC_receive_candidate_list() */
4302 #endif /* H5_HAVE_PARALLEL */
4303
4304
4305 /*-------------------------------------------------------------------------
4306 * Function: H5AC_rsp__dist_md_write__flush
4307 *
4308 * Purpose: Routine for handling the details of running a sync point
4309 * that is triggered by a flush -- which in turn must have been
4310 * triggered by either a flush API call or a file close --
4311 * when the distributed metadata write strategy is selected.
4312 *
4313 * Upon entry, each process generates it own candidate list,
4314 * being a sorted list of all dirty metadata entries currently
4315 * in the metadata cache. Note that this list must be idendical
4316 * across all processes, as all processes see the same stream
4317 * of dirty metadata coming in, and use the same lists of
4318 * candidate entries at each sync point. (At first glance, this
4319 * argument sounds circular, but think of it in the sense of
4320 * a recursive proof).
4321 *
4322 * If this this list is empty, we are done, and the function
4323 * returns
4324 *
4325 * Otherwise, after the sorted list dirty metadata entries is
4326 * constructed, each process uses the same algorithm to assign
4327 * each entry on the candidate list to exactly one process for
4328 * flushing.
4329 *
4330 * At this point, all processes participate in a barrier to
4331 * avoid messages from the past/future bugs.
4332 *
4333 * Each process then flushes the entries assigned to it, and
4334 * marks all other entries on the candidate list as clean.
4335 *
4336 * Finally, all processes participate in a second barrier to
4337 * avoid messages from the past/future bugs.
4338 *
4339 * At the end of this process, process 0 and only process 0
4340 * must tidy up its lists of dirtied and cleaned entries.
4341 * These lists are not used in the distributed metadata write
4342 * strategy, but they must be maintained should we shift
4343 * to a strategy that uses them.
4344 *
4345 * Return: Success: non-negative
4346 *
4347 * Failure: negative
4348 *
4349 * Programmer: John Mainzer
4350 * April 28, 2010
4351 *
4352 *-------------------------------------------------------------------------
4353 */
4354 #ifdef H5_HAVE_PARALLEL
4355 herr_t
H5AC_rsp__dist_md_write__flush(H5F_t * f,hid_t dxpl_id,H5AC_t * cache_ptr)4356 H5AC_rsp__dist_md_write__flush(H5F_t *f,
4357 hid_t dxpl_id,
4358 H5AC_t * cache_ptr)
4359 {
4360 int mpi_code;
4361 int num_entries = 0;
4362 haddr_t * haddr_buf_ptr = NULL;
4363 H5AC_aux_t * aux_ptr;
4364 herr_t ret_value = SUCCEED; /* Return value */
4365
4366 FUNC_ENTER_NOAPI(FAIL)
4367
4368 HDassert( f != NULL );
4369 HDassert( f->shared->cache == cache_ptr );
4370
4371 HDassert( cache_ptr != NULL );
4372 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
4373
4374 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
4375
4376 HDassert( aux_ptr != NULL );
4377 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
4378 HDassert( aux_ptr->metadata_write_strategy ==
4379 H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED );
4380
4381 /* first construct the candidate list -- initially, this will be in the
4382 * form of a skip list. We will convert it later.
4383 */
4384 if(H5C_construct_candidate_list__clean_cache(cache_ptr) < 0)
4385 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't construct candidate list.")
4386
4387 if(aux_ptr->candidate_slist_len > 0) {
4388 herr_t result;
4389
4390 /* convert the candidate list into the format we
4391 * are used to receiving from process 0.
4392 */
4393 if(H5AC_copy_candidate_list_to_buffer(cache_ptr, &num_entries, &haddr_buf_ptr, NULL, NULL) < 0)
4394 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't construct candidate buffer.")
4395
4396 /* initial sync point barrier */
4397 if(MPI_SUCCESS != (mpi_code = MPI_Barrier(aux_ptr->mpi_comm)))
4398 HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed 1", mpi_code)
4399
4400 /* apply the candidate list */
4401 aux_ptr->write_permitted = TRUE;
4402
4403 result = H5C_apply_candidate_list(f,
4404 dxpl_id,
4405 dxpl_id,
4406 cache_ptr,
4407 num_entries,
4408 haddr_buf_ptr,
4409 aux_ptr->mpi_rank,
4410 aux_ptr->mpi_size);
4411
4412 aux_ptr->write_permitted = FALSE;
4413
4414 if(result < 0)
4415 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't apply candidate list.")
4416
4417 /* this code exists primarily for the test bed -- it allows us to
4418 * enforce posix semantics on the server that pretends to be a
4419 * file system in our parallel tests.
4420 */
4421 if(aux_ptr->write_done != NULL)
4422 (aux_ptr->write_done)();
4423
4424 /* final sync point barrier */
4425 if(MPI_SUCCESS != (mpi_code = MPI_Barrier(aux_ptr->mpi_comm)))
4426 HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed 1", mpi_code)
4427
4428 /* if this is process zero, tidy up the dirtied,
4429 * and flushed and still clean lists.
4430 */
4431 if(aux_ptr->mpi_rank == 0) {
4432 if(H5AC_tidy_cache_0_lists(cache_ptr, num_entries, haddr_buf_ptr) < 0)
4433 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't tidy up process 0 lists.")
4434 } /* end if */
4435 } /* end if */
4436
4437 /* if it is defined, call the sync point done callback. Note
4438 * that this callback is defined purely for testing purposes,
4439 * and should be undefined under normal operating circumstances.
4440 */
4441 if(aux_ptr->sync_point_done != NULL)
4442 (aux_ptr->sync_point_done)(num_entries, haddr_buf_ptr);
4443
4444 done:
4445 if(haddr_buf_ptr != NULL)
4446 haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr);
4447
4448 FUNC_LEAVE_NOAPI(ret_value)
4449 } /* H5AC_rsp__dist_md_write__flush() */
4450 #endif /* H5_HAVE_PARALLEL */
4451
4452
4453 /*-------------------------------------------------------------------------
4454 * Function: H5AC_rsp__dist_md_write__flush_to_min_clean
4455 *
4456 * Purpose: Routine for handling the details of running a sync point
4457 * triggered by the accumulation of dirty metadata (as
4458 * opposed to a flush call to the API) when the distributed
4459 * metadata write strategy is selected.
4460 *
4461 * After invocation and initial sanity checking this function
4462 * first checks to see if evictions are enabled -- if they
4463 * are not, the function does nothing and returns.
4464 *
4465 * Otherwise, process zero constructs a list of entries to
4466 * be flushed in order to bring the process zero cache back
4467 * within its min clean requirement. Note that this list
4468 * (the candidate list) may be empty.
4469 *
4470 * Then, all processes participate in a barrier.
4471 *
4472 * After the barrier, process 0 broadcasts the number of
4473 * entries in the candidate list prepared above, and all
4474 * other processes receive this number.
4475 *
4476 * If this number is zero, we are done, and the function
4477 * returns without further action.
4478 *
4479 * Otherwise, process 0 broadcasts the sorted list of
4480 * candidate entries, and all other processes receive it.
4481 *
4482 * Then, each process uses the same algorithm to assign
4483 * each entry on the candidate list to exactly one process
4484 * for flushing.
4485 *
4486 * Each process then flushes the entries assigned to it, and
4487 * marks all other entries on the candidate list as clean.
4488 *
4489 * Finally, all processes participate in a second barrier to
4490 * avoid messages from the past/future bugs.
4491 *
4492 * At the end of this process, process 0 and only process 0
4493 * must tidy up its lists of dirtied and cleaned entries.
4494 * These lists are not used in the distributed metadata write
4495 * strategy, but they must be maintained should we shift
4496 * to a strategy that uses them.
4497 *
4498 * Return: Success: non-negative
4499 *
4500 * Failure: negative
4501 *
4502 * Programmer: John Mainzer
4503 * April 28, 2010
4504 *
4505 *-------------------------------------------------------------------------
4506 */
4507 #ifdef H5_HAVE_PARALLEL
4508 herr_t
H5AC_rsp__dist_md_write__flush_to_min_clean(H5F_t * f,hid_t dxpl_id,H5AC_t * cache_ptr)4509 H5AC_rsp__dist_md_write__flush_to_min_clean(H5F_t *f,
4510 hid_t dxpl_id,
4511 H5AC_t * cache_ptr)
4512 {
4513 hbool_t evictions_enabled;
4514 H5AC_aux_t * aux_ptr;
4515 herr_t ret_value = SUCCEED; /* Return value */
4516
4517 FUNC_ENTER_NOAPI(FAIL)
4518
4519 HDassert( f != NULL );
4520 HDassert( f->shared->cache == cache_ptr );
4521
4522 HDassert( cache_ptr != NULL );
4523 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
4524
4525 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
4526
4527 HDassert( aux_ptr != NULL );
4528 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
4529 HDassert( aux_ptr->metadata_write_strategy ==
4530 H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED );
4531
4532 /* Query if evictions are allowed */
4533 if(H5C_get_evictions_enabled((const H5C_t *)cache_ptr, &evictions_enabled) < 0)
4534 HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5C_get_evictions_enabled() failed.")
4535
4536 if(evictions_enabled) {
4537 /* construct candidate list -- process 0 only */
4538 if(aux_ptr->mpi_rank == 0) {
4539 if(H5AC_construct_candidate_list(cache_ptr, aux_ptr, H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN) < 0)
4540 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't construct candidate list.")
4541 } /* mpi rank == 0 */
4542
4543 /* propagate and apply candidate list -- all processes */
4544 if(H5AC_propagate_and_apply_candidate_list(f, dxpl_id, cache_ptr) < 0)
4545 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't propagate and apply candidate list.")
4546 } /* evictions enabled */
4547
4548 done:
4549 FUNC_LEAVE_NOAPI(ret_value)
4550 } /* H5AC_rsp__dist_md_write__flush_to_min_clean() */
4551 #endif /* H5_HAVE_PARALLEL */
4552
4553
4554 /*-------------------------------------------------------------------------
4555 * Function: H5AC_rsp__p0_only__flush
4556 *
4557 * Purpose: Routine for handling the details of running a sync point
4558 * that is triggered a flush -- which in turn must have been
4559 * triggered by either a flush API call or a file close --
4560 * when the process 0 only metadata write strategy is selected.
4561 *
4562 * First, all processes participate in a barrier.
4563 *
4564 * Then process zero flushes all dirty entries, and broadcasts
4565 * they number of clean entries (if any) to all the other
4566 * caches.
4567 *
4568 * If this number is zero, we are done.
4569 *
4570 * Otherwise, process 0 broadcasts the list of cleaned
4571 * entries, and all other processes which are part of this
4572 * file group receive it, and mark the listed entries as
4573 * clean in their caches.
4574 *
4575 * Since all processes have the same set of dirty
4576 * entries at the beginning of the sync point, and all
4577 * entries that will be written are written before
4578 * process zero broadcasts the number of cleaned entries,
4579 * there is no need for a closing barrier.
4580 *
4581 * Return: Success: non-negative
4582 *
4583 * Failure: negative
4584 *
4585 * Programmer: John Mainzer
4586 * April 28, 2010
4587 *
4588 *-------------------------------------------------------------------------
4589 */
4590 #ifdef H5_HAVE_PARALLEL
4591 herr_t
H5AC_rsp__p0_only__flush(H5F_t * f,hid_t dxpl_id,H5AC_t * cache_ptr)4592 H5AC_rsp__p0_only__flush(H5F_t *f,
4593 hid_t dxpl_id,
4594 H5AC_t * cache_ptr)
4595 {
4596 int mpi_code;
4597 H5AC_aux_t * aux_ptr;
4598 herr_t ret_value = SUCCEED; /* Return value */
4599
4600 FUNC_ENTER_NOAPI(FAIL)
4601
4602 HDassert( f != NULL );
4603 HDassert( f->shared->cache == cache_ptr );
4604
4605 HDassert( cache_ptr != NULL );
4606 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
4607
4608 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
4609
4610 HDassert( aux_ptr != NULL );
4611 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
4612 HDassert( aux_ptr->metadata_write_strategy ==
4613 H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY );
4614
4615
4616 /* to prevent "messages from the future" we must
4617 * synchronize all processes before we start the flush.
4618 * Hence the following barrier.
4619 */
4620 if(MPI_SUCCESS != (mpi_code = MPI_Barrier(aux_ptr->mpi_comm)))
4621 HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed 1", mpi_code)
4622
4623 /* Flush data to disk, from rank 0 process */
4624 if(aux_ptr->mpi_rank == 0) {
4625 herr_t result;
4626
4627 aux_ptr->write_permitted = TRUE;
4628
4629 result = H5C_flush_cache(f, dxpl_id, dxpl_id, H5AC__NO_FLAGS_SET);
4630
4631 aux_ptr->write_permitted = FALSE;
4632
4633 if(result < 0)
4634 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush.")
4635
4636 if(aux_ptr->write_done != NULL)
4637 (aux_ptr->write_done)();
4638 } /* end if */
4639
4640 /* Propagate cleaned entries to other ranks. */
4641 if(H5AC_propagate_flushed_and_still_clean_entries_list(f, H5AC_noblock_dxpl_id, cache_ptr) < 0)
4642 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't propagate clean entries list.")
4643
4644 done:
4645 FUNC_LEAVE_NOAPI(ret_value)
4646 } /* H5AC_rsp__p0_only__flush() */
4647 #endif /* H5_HAVE_PARALLEL */
4648
4649
4650 /*-------------------------------------------------------------------------
4651 * Function: H5AC_rsp__p0_only__flush_to_min_clean
4652 *
4653 * Purpose: Routine for handling the details of running a sync point
4654 * triggered by the accumulation of dirty metadata (as
4655 * opposed to a flush call to the API) when the process 0
4656 * only metadata write strategy is selected.
4657 *
4658 * After invocation and initial sanity checking this function
4659 * first checks to see if evictions are enabled -- if they
4660 * are not, the function does nothing and returns.
4661 *
4662 * Otherwise, all processes participate in a barrier.
4663 *
4664 * After the barrier, if this is process 0, the function
4665 * causes the cache to flush sufficient entries to get the
4666 * cache back within its minimum clean fraction, and broadcast
4667 * the number of entries which have been flushed since
4668 * the last sync point, and are still clean.
4669 *
4670 * If this number is zero, we are done.
4671 *
4672 * Otherwise, process 0 broadcasts the list of cleaned
4673 * entries, and all other processes which are part of this
4674 * file group receive it, and mark the listed entries as
4675 * clean in their caches.
4676 *
4677 * Since all processes have the same set of dirty
4678 * entries at the beginning of the sync point, and all
4679 * entries that will be written are written before
4680 * process zero broadcasts the number of cleaned entries,
4681 * there is no need for a closing barrier.
4682 *
4683 * Return: Success: non-negative
4684 *
4685 * Failure: negative
4686 *
4687 * Programmer: John Mainzer
4688 * April 28, 2010
4689 *
4690 *-------------------------------------------------------------------------
4691 */
4692 #ifdef H5_HAVE_PARALLEL
4693 herr_t
H5AC_rsp__p0_only__flush_to_min_clean(H5F_t * f,hid_t dxpl_id,H5AC_t * cache_ptr)4694 H5AC_rsp__p0_only__flush_to_min_clean(H5F_t *f,
4695 hid_t dxpl_id,
4696 H5AC_t * cache_ptr)
4697 {
4698 hbool_t evictions_enabled;
4699 H5AC_aux_t * aux_ptr;
4700 herr_t ret_value = SUCCEED; /* Return value */
4701
4702 FUNC_ENTER_NOAPI(FAIL)
4703
4704 HDassert( f != NULL );
4705 HDassert( f->shared->cache == cache_ptr );
4706
4707 HDassert( cache_ptr != NULL );
4708 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
4709
4710 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
4711
4712 HDassert( aux_ptr != NULL );
4713 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
4714 HDassert( aux_ptr->metadata_write_strategy ==
4715 H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY );
4716
4717 /* Query if evictions are allowed */
4718 if(H5C_get_evictions_enabled((const H5C_t *)cache_ptr, &evictions_enabled) < 0)
4719 HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5C_get_evictions_enabled() failed.")
4720
4721 /* Flush if evictions are allowed -- following call
4722 * will cause process 0 to flush to min clean size,
4723 * and then propagate the newly clean entries to the
4724 * other processes.
4725 *
4726 * Otherwise, do nothing.
4727 */
4728 if(evictions_enabled) {
4729 int mpi_code;
4730
4731 /* to prevent "messages from the future" we must synchronize all
4732 * processes before we start the flush. This synchronization may
4733 * already be done -- hence the do_barrier parameter.
4734 */
4735 if(MPI_SUCCESS != (mpi_code = MPI_Barrier(aux_ptr->mpi_comm)))
4736 HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code)
4737
4738 if(0 == aux_ptr->mpi_rank) {
4739 herr_t result;
4740
4741 /* here, process 0 flushes as many entries as necessary to
4742 * comply with the currently specified min clean size.
4743 * Note that it is quite possible that no entries will be
4744 * flushed.
4745 */
4746 aux_ptr->write_permitted = TRUE;
4747
4748 result = H5C_flush_to_min_clean(f, dxpl_id, H5AC_noblock_dxpl_id);
4749
4750 aux_ptr->write_permitted = FALSE;
4751
4752 if(result < 0)
4753 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_flush_to_min_clean() failed.")
4754
4755 /* this call exists primarily for the test code -- it is used
4756 * to enforce POSIX semantics on the process used to simulate
4757 * reads and writes in t_cache.c.
4758 */
4759 if(aux_ptr->write_done != NULL)
4760 (aux_ptr->write_done)();
4761 } /* end if */
4762
4763 if(H5AC_propagate_flushed_and_still_clean_entries_list(f, dxpl_id, cache_ptr) < 0)
4764 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't propagate clean entries list.")
4765 } /* end if */
4766
4767 done:
4768 FUNC_LEAVE_NOAPI(ret_value)
4769 } /* H5AC_rsp__p0_only__flush_to_min_clean() */
4770 #endif /* H5_HAVE_PARALLEL */
4771
4772
4773 /*-------------------------------------------------------------------------
4774 * Function: H5AC_run_sync_point
4775 *
4776 * Purpose: Top level routine for managing a sync point between all
4777 * meta data caches in the parallel case. Since all caches
4778 * see the same sequence of dirty metadata, we simply count
4779 * bytes of dirty metadata, and run a sync point whenever the
4780 * number of dirty bytes of metadata seen since the last
4781 * sync point exceeds a threshold that is common across all
4782 * processes. We also run sync points in response to
4783 * HDF5 API calls triggering either a flush or a file close.
4784 *
4785 * In earlier versions of PHDF5, only the metadata cache with
4786 * mpi rank 0 was allowed to write to file. All other
4787 * metadata caches on processes with rank greater than 0 were
4788 * required to retain dirty entries until they were notified
4789 * that the entry is was clean.
4790 *
4791 * This function was created to make it easier for us to
4792 * experiment with other options, as it is a single point
4793 * for the execution of sync points.
4794 *
4795 * Return: Success: non-negative
4796 *
4797 * Failure: negative
4798 *
4799 * Programmer: John Mainzer
4800 * March 11, 2010
4801 *
4802 *-------------------------------------------------------------------------
4803 */
4804 #ifdef H5_HAVE_PARALLEL
4805 herr_t
H5AC_run_sync_point(H5F_t * f,hid_t dxpl_id,int sync_point_op)4806 H5AC_run_sync_point(H5F_t *f,
4807 hid_t dxpl_id,
4808 int sync_point_op)
4809 {
4810 H5AC_t * cache_ptr;
4811 H5AC_aux_t * aux_ptr;
4812 herr_t ret_value = SUCCEED; /* Return value */
4813
4814 FUNC_ENTER_NOAPI(FAIL)
4815
4816 HDassert( f != NULL );
4817
4818 cache_ptr = f->shared->cache;
4819
4820 HDassert( cache_ptr != NULL );
4821 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
4822
4823 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
4824
4825 HDassert( aux_ptr != NULL );
4826 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
4827
4828 HDassert( ( sync_point_op == H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN ) ||
4829 ( sync_point_op == H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED ) );
4830
4831 #if H5AC_DEBUG_DIRTY_BYTES_CREATION
4832 HDfprintf(stdout,
4833 "%d:H5AC_propagate...:%d: (u/uu/i/iu/r/ru) = %d/%d/%d/%d/%d/%d\n",
4834 (int)(aux_ptr->mpi_rank),
4835 (int)(aux_ptr->dirty_bytes_propagations),
4836 (int)(aux_ptr->unprotect_dirty_bytes),
4837 (int)(aux_ptr->unprotect_dirty_bytes_updates),
4838 (int)(aux_ptr->insert_dirty_bytes),
4839 (int)(aux_ptr->insert_dirty_bytes_updates),
4840 (int)(aux_ptr->rename_dirty_bytes),
4841 (int)(aux_ptr->rename_dirty_bytes_updates));
4842 #endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
4843
4844 switch(aux_ptr->metadata_write_strategy) {
4845 case H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY:
4846 switch(sync_point_op) {
4847 case H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN:
4848 if(H5AC_rsp__p0_only__flush_to_min_clean(f, dxpl_id, cache_ptr) < 0)
4849 HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5AC_rsp__p0_only__flush_to_min_clean() failed.")
4850 break;
4851
4852 case H5AC_SYNC_POINT_OP__FLUSH_CACHE:
4853 if(H5AC_rsp__p0_only__flush(f, dxpl_id, cache_ptr) < 0)
4854 HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5AC_rsp__p0_only__flush() failed.")
4855 break;
4856
4857 default:
4858 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unknown flush op");
4859 break;
4860 } /* end switch */
4861 break;
4862
4863 case H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED:
4864 switch(sync_point_op) {
4865 case H5AC_SYNC_POINT_OP__FLUSH_TO_MIN_CLEAN:
4866 if(H5AC_rsp__dist_md_write__flush_to_min_clean(f, dxpl_id, cache_ptr) < 0)
4867 HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5AC_rsp__dist_md_write__flush() failed.")
4868 break;
4869
4870 case H5AC_SYNC_POINT_OP__FLUSH_CACHE:
4871 if(H5AC_rsp__dist_md_write__flush(f, dxpl_id, cache_ptr) < 0)
4872 HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, FAIL, "H5AC_rsp__dist_md_write__flush() failed.")
4873 break;
4874
4875 default:
4876 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unknown flush op");
4877 break;
4878 } /* end switch */
4879 break;
4880
4881 default:
4882 HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown metadata write strategy.")
4883 break;
4884 } /* end switch */
4885
4886 /* reset the dirty bytes count */
4887 aux_ptr->dirty_bytes = 0;
4888
4889 #if H5AC_DEBUG_DIRTY_BYTES_CREATION
4890 aux_ptr->dirty_bytes_propagations += 1;
4891 aux_ptr->unprotect_dirty_bytes = 0;
4892 aux_ptr->unprotect_dirty_bytes_updates = 0;
4893 aux_ptr->insert_dirty_bytes = 0;
4894 aux_ptr->insert_dirty_bytes_updates = 0;
4895 aux_ptr->rename_dirty_bytes = 0;
4896 aux_ptr->rename_dirty_bytes_updates = 0;
4897 #endif /* H5AC_DEBUG_DIRTY_BYTES_CREATION */
4898
4899 done:
4900 FUNC_LEAVE_NOAPI(ret_value)
4901 } /* H5AC_run_sync_point() */
4902 #endif /* H5_HAVE_PARALLEL */
4903
4904
4905 /*-------------------------------------------------------------------------
4906 * Function: H5AC_tidy_cache_0_lists()
4907 *
4908 * Purpose: In the distributed metadata write strategy, not all dirty
4909 * entries are written by process 0 -- thus we must tidy
4910 * up the dirtied, and flushed and still clean lists
4911 * maintained by process zero after each sync point.
4912 *
4913 * This procedure exists to tend to this issue.
4914 *
4915 * At this point, all entries that process 0 cleared should
4916 * have been removed from both the dirty and flushed and
4917 * still clean lists, and entries that process 0 has flushed
4918 * should have been removed from the dirtied list and added
4919 * to the flushed and still clean list.
4920 *
4921 * However, since the distributed metadata write strategy
4922 * doesn't make use of these lists, the objective is simply
4923 * to maintain these lists in consistent state that allows
4924 * them to be used should the metadata write strategy change
4925 * to one that uses these lists.
4926 *
4927 * Thus for our purposes, all we need to do is remove from
4928 * the dirtied and flushed and still clean lists all
4929 * references to entries that appear in the candidate list.
4930 *
4931 * Return: Success: non-negative
4932 *
4933 * Failure: negative
4934 *
4935 * Programmer: John Mainzer
4936 * 4/20/10
4937 *
4938 *-------------------------------------------------------------------------
4939 */
4940 #ifdef H5_HAVE_PARALLEL
4941 static herr_t
H5AC_tidy_cache_0_lists(H5AC_t * cache_ptr,int num_candidates,haddr_t * candidates_list_ptr)4942 H5AC_tidy_cache_0_lists(H5AC_t * cache_ptr,
4943 int num_candidates,
4944 haddr_t * candidates_list_ptr)
4945
4946 {
4947 int i;
4948 H5AC_aux_t * aux_ptr;
4949 herr_t ret_value = SUCCEED; /* Return value */
4950
4951 FUNC_ENTER_NOAPI(FAIL)
4952
4953 HDassert( cache_ptr != NULL );
4954 HDassert( cache_ptr->magic == H5C__H5C_T_MAGIC );
4955
4956 aux_ptr = (H5AC_aux_t *)(cache_ptr->aux_ptr);
4957
4958 HDassert( aux_ptr != NULL );
4959 HDassert( aux_ptr->magic == H5AC__H5AC_AUX_T_MAGIC );
4960 HDassert( aux_ptr->metadata_write_strategy ==
4961 H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED );
4962 HDassert( aux_ptr->mpi_rank == 0 );
4963 HDassert( num_candidates > 0 );
4964 HDassert( candidates_list_ptr != NULL );
4965
4966 /* clean up dirtied and flushed and still clean lists by removing
4967 * all entries on the candidate list. Cleared entries should
4968 * have been removed from both the dirty and cleaned lists at
4969 * this point, flushed entries should have been added to the
4970 * cleaned list. However, for this metadata write strategy,
4971 * we just want to remove all references to the candidate entries.
4972 */
4973 for(i = 0; i < num_candidates; i++) {
4974 H5AC_slist_entry_t * d_slist_entry_ptr;
4975 H5AC_slist_entry_t * c_slist_entry_ptr;
4976 haddr_t addr;
4977
4978 addr = candidates_list_ptr[i];
4979
4980 /* addr must be either on the dirtied list, or on the flushed
4981 * and still clean list. Remove it.
4982 */
4983 d_slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_search(aux_ptr->d_slist_ptr, (void *)&addr);
4984 if(d_slist_entry_ptr != NULL) {
4985 HDassert(d_slist_entry_ptr->magic == H5AC__H5AC_SLIST_ENTRY_T_MAGIC);
4986 HDassert(d_slist_entry_ptr->addr == addr);
4987
4988 if(H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&addr)) != d_slist_entry_ptr)
4989 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, "Can't delete entry from dirty entry slist.")
4990
4991 d_slist_entry_ptr->magic = 0;
4992 H5FL_FREE(H5AC_slist_entry_t, d_slist_entry_ptr);
4993
4994 aux_ptr->d_slist_len -= 1;
4995
4996 HDassert(aux_ptr->d_slist_len >= 0);
4997 } /* end if */
4998
4999 c_slist_entry_ptr = (H5AC_slist_entry_t *)H5SL_search(aux_ptr->c_slist_ptr, (void *)&addr);
5000 if(c_slist_entry_ptr != NULL) {
5001 HDassert(c_slist_entry_ptr->magic == H5AC__H5AC_SLIST_ENTRY_T_MAGIC);
5002 HDassert(c_slist_entry_ptr->addr == addr);
5003
5004 if(H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr)) != c_slist_entry_ptr)
5005 HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, "Can't delete entry from clean entry slist.")
5006
5007 c_slist_entry_ptr->magic = 0;
5008 H5FL_FREE(H5AC_slist_entry_t, c_slist_entry_ptr);
5009
5010 aux_ptr->c_slist_len -= 1;
5011
5012 HDassert( aux_ptr->c_slist_len >= 0 );
5013 } /* end if */
5014 } /* end for */
5015
5016 done:
5017 FUNC_LEAVE_NOAPI(ret_value)
5018 } /* H5AC_tidy_cache_0_lists() */
5019 #endif /* H5_HAVE_PARALLEL */
5020
5021
5022 /*-------------------------------------------------------------------------
5023 * Function: H5AC_flush_entries
5024 *
5025 * Purpose: Flush the metadata cache associated with the specified file,
5026 * only writing from rank 0, but propagating the cleaned entries
5027 * to all ranks.
5028 *
5029 * Return: Non-negative on success/Negative on failure if there was a
5030 * request to flush all items and something was protected.
5031 *
5032 * Programmer: Quincey Koziol
5033 * koziol@hdfgroup.org
5034 * Aug 22 2009
5035 *
5036 *-------------------------------------------------------------------------
5037 */
5038 #ifdef H5_HAVE_PARALLEL
5039 herr_t
H5AC_flush_entries(H5F_t * f)5040 H5AC_flush_entries(H5F_t *f)
5041 {
5042 herr_t ret_value = SUCCEED; /* Return value */
5043
5044 FUNC_ENTER_NOAPI_NOINIT
5045
5046 HDassert(f);
5047 HDassert(f->shared->cache);
5048
5049 /* Check if we have >1 ranks */
5050 if(f->shared->cache->aux_ptr) {
5051 if(H5AC_run_sync_point(f, H5AC_noblock_dxpl_id, H5AC_SYNC_POINT_OP__FLUSH_CACHE) < 0)
5052 HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't run sync point.")
5053 } /* end if */
5054
5055 done:
5056 FUNC_LEAVE_NOAPI(ret_value)
5057 } /* H5AC_flush_entries() */
5058 #endif /* H5_HAVE_PARALLEL */
5059
5060