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